gerrit_windows_wsl was configure to build with 'make build'
so this failure wasn't caught in time.
Now gerrit_windows_wsl builds with 'make build unitcheck slowcheck'
and it fails with
Test name: testExtTextOutScaleGM_COMPATIBLE::TestBody
double equality assertion failed
- Expected: 199
- Actual : 201
- Delta : 1
- In <>, attribute 'width' of '/primitive2D/metafile/transform/textsimpleportion[3]' incorrect value.
Change-Id: Ibce7398946ef52eea05438feacc7a1dcaa22d579
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/208165
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
It is a misnomer now, so return to the original name.
Also drop the redundant private Font::GetAverageFontSize().
Change-Id: I67495fa675091b459a4e90ac09665489cc61fdd9
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207991
Tested-by: Jenkins
Reviewed-by: Khaled Hosny <khaled@libreoffice.org>
The font width used to mean the average character width on Windows,
like GDI’s LOGFONT lfWidth. This complicates things cross-platform, and
also DirectWrite does not expose such info.
Drop the whole average character width nonsense and align Windows to
other platforms, keeping the already existing cross-platforms
workarounds for EMF/WMF that are now applied also to Windows.
Change-Id: I750d42ad090bb9d0f776e80609b7a67b8ac38aac
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207990
Reviewed-by: Khaled Hosny <khaled@libreoffice.org>
Tested-by: Jenkins
ReadMultiformatsComment dereferenced aGraphic.getVectorGraphicData()
unconditionally to call setSizeHint, then a few lines later acquired
the same pointer into a local and checked it for null. Reorder so
the null check happens before the first use, and reuse the local
for getType() too.
vcl::ImportPDF always installs a non-null VectorGraphicData on
success today, so this is defensive against future changes (or
edge-case ImportPDF backends that succeed without producing one)
rather than a fix for a confirmed crash. The macOS dbgutil
tinderbox report for tdf#167641 was not reproducible on two
separate macOS boxes, so the underlying issue could not be
diagnosed; this guard is the conservative belt-and-braces change.
Signed-off-by: Andras Timar <andras.timar@collabora.com>
Change-Id: I2569f26b099f305dd98b94ef4e9ab5c9a20fef11
(cherry picked from commit 36b0369ad6205aa7383ff4e93214853ea1081d61)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206642
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
MS Office writes the EmrFormat.Version field as 0 in the
EMR_COMMENT_MULTIFORMATS record carrying an embedded PDF. Per
[MS-EMF] 2.3.3.4.2 EmrFormat, Version MUST be 0x00000001 only when
Signature == EPS_SIGNATURE; for any other signature it MUST be
ignored. The reader rejected anything but 1, so the embedded PDF
was dropped on the floor.
Real-world files also use an empty OutputRect (0,0,0,0); per
[MS-EMF] 2.3.3.4.3 it is in logical coordinates, so fall back to
the EMF's logical bounds (mrclBounds) when it is degenerate, so
ResolveBitmapActions has somewhere to draw the PDF bitmap.
The new fixture is the existing pdf-in-emf.pptx EMF with the two
fields patched to reproduce the regression in 776 bytes.
Signed-off-by: Andras Timar <andras.timar@collabora.com>
Change-Id: I432f75a1cac11d84448db07c1a1815cd0be60744
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1904
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit a5d7b2935718bf7f1f6cc0352c8d8681e6713f4b)
Cherry-pick note: the test fails on macOS in CI
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205084
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
The handler accumulated every rect from one EmfPlusFillRects
record into a single B2DPolyPolygon and emitted a single
PolyPolygonColorPrimitive2D, which drawinglayer fills under the
even-odd rule. With overlapping rects, even-odd cancels pairwise
overlaps - three south-east-shifted gray squares rendered as
filled-then-hollow-then-filled stripes (the triple-overlap centre
came back as filled because three crossings is again odd).
Per MS-EMFPLUS each rect in EmfPlusFillRects fills its interior
independently; there is no fill-rule choice. Emit one fill
primitive per rect inside the loop and keep the polypolygon path
only for EmfPlusDrawRects, where stroking is independent of fill
rule so the existing single-call shape stays correct.
Tests: testEmfPlusFillRectsOverlap with three 300x300 squares
shifted south-east by 100px each (extracted from the tdf#107034
sample EMF) asserts three separate polypolygoncolor primitives
rather than one combined.
Signed-off-by: Andras Timar <andras.timar@collabora.com>
Change-Id: I567e6a06d103684a723f513297684c66f700587a
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2314
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit 679c654a5b9a5f4a1cd787e5fa2d2380eb5574fb)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205087
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
Replace the previous SvgRadialGradientPrimitive2D approximation of
PathGradientBrush with a bitmap-textured polypolygongraphic fill,
where the bitmap content is computed by a per-triangle Gouraud
shading of the brush boundary.
The old approximation positioned the gradient centre via
Map(brush->firstPoint), which typically landed far outside the
polygon's unit-coordinate range because the brush's path lives in
its own coordinate space; with SpreadMethod::Pad the gradient then
degenerated into a flat boundary-colour fill - the "orange square
instead of tiled gradient circles" of tdf#143031.
The bitmap is allocated with the brush bbox's aspect ratio
(longest side 256 px) and anchored to aBrushBounds.getMinX/MinY in
raw EMF coords, so when maMapTransform sends it to world space it
lines up with the fill polygon. wrapMode != WrapModeClamp routes
it through the existing texture-tiling path so larger fill polygons
repeat the bitmap.
Per-pixel content (Gouraud sweep):
- Partition the brush boundary into N triangles formed by (centre,
V_i, V_{i+1}) and Gouraud-shade each one with vertex colours
(centerColor, surround[i], surround[(i+1) % nSurround]). Inside a
triangle the pixel colour is the barycentric blend of the three
vertex colours; this reproduces multi-surround-colour brushes
(e.g. the libUEMF 5-pointed star with red/blue/red/blue/magenta
outer points and green inner indents on a black centre) and
collapses to a smooth radial gradient when all surround colours
are equal.
- The brush's BlendFactors curve (sampleFactor) remaps the
centre/edge parameter t before mixing centre and per-segment
edge colour. PresetColors / ColorBlend (sampleColor), when
present, override the centre/edge mix entirely with a sampled
stop colour. Both fall back to a linear centre-to-edge mix when
the brush carries no curve.
Rasterization is done per-triangle: Pass 1 walks each fan
triangle's pixel-space AABB (clipped to the bitmap) and writes
only the pixels that fall inside, so total work is O(sum of
triangle AABB areas) rather than O(bitmap area * triangle count).
Structurally this is what cairo's mesh-pattern rasterizer
(cairo-mesh-pattern-rasterizer.c) does for PDF type-7 shadings -
each patch paints into its own pixel range rather than every
pixel testing every patch. With N up to ~512 boundary segments
after Bezier flattening, that turns a 256x256-pixel bitmap from
a ~30M pixel-tests-triangle loop into ~50k AABB iterations
(per-pixel arithmetic is unchanged so the rendered colours match
bit-for-bit).
Boundary handling:
- BrushDataPath set: take the brush's path polygon and flatten
Bezier segments via adaptiveSubdivideByDistance with bound =
bbox/512 so the boundary closely follows the curve.
- BrushDataPath unset: use a new EMFPPath::GetRawPointsPolygon()
helper that builds a polygon directly from the boundary points.
GetPolygon() can't be used here because the trailing bytes of
boundary-only brush data don't encode valid path-point types and
produce a degenerate polygon.
Pixels outside every fan triangle (in the bitmap bbox but not in
the boundary) are handled per wrapMode in a second pass:
- Tile / TileFlipX / TileFlipY / TileFlipXY: left transparent so
adjacent tiles in the fill polygon stay visually separate. Pass
2 is skipped entirely for these wrap modes.
- Clamp: extended using the closest triangle's edge colour
(smallest-negative-margin barycentric weights), eliminating
sub-pixel transparent jaggies along smooth Bezier fill polygons
that extend slightly past the flattened boundary.
Tests: testEmfPlusBrushPathGradientWithBlendColors expectations
updated to assert the new polypolygongraphic-with-bitmap structure
(single bitmap copy fills the polygon when bitmap and polygon bbox
coincide). New testEmfPlusBrushPathGradientMultiSurroundColor
with a hand-extracted libUEMF 5-pointed-star EMF exercises the
boundary-only / multi-surround-colour path. testEmfPlusBrushPath-
GradientTiled covers the texture-tiling case where the brush
gradient is repeated across a larger fill polygon.
Signed-off-by: Andras Timar <andras.timar@collabora.com>
Change-Id: I92aa6d90ef6d2106f1d8d1cad97a3bb83594bd23
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2209
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit fa76144b9cf130e232465c2480a5a7127bb282ed)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205086
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
The fill-mode bit (0x2000) of EMF+ FillClosedCurve records was
logged but ignored, so a self-intersecting closed curve drawn with
WINDING semantics rendered the same as ALTERNATE - the centre of a
pentagram fill came out as a hole instead of being filled. Convert
the polypolygon at parse time the same way the pre-existing
EMR_SETPOLYFILLMODE path does (solveCrossovers +
stripNeutralPolygons + mergeToSinglePolyPolygon for single self-
intersecting polygons, createNonzeroConform for nested poly-
polygons) so the resulting even-odd fill of primitive2d primitives
matches the intended winding-fill visual.
Add a unit test with a minimal EMF+ FillClosedCurve drawing a
self-intersecting pentagram in winding mode.
Signed-off-by: Andras Timar <andras.timar@collabora.com>
Change-Id: Ic02048aae223527dca0f556f0171f117baf147c0
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2313
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit fd018f6203f61aaf0c8c781c11a93578bf1eaf6b)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205085
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
[MS-EMF] 2.3.2.2 says the RegionData field "MUST be ignored" when
iMode is RGN_COPY, but real EMFs include data with RGN_COPY and
expect the clip to be replaced with the given region (verified
against MS Word reference rendering of test files such as
TestCreatePen.emf and a chart EMF where the colored plot lines
were leaking outside the plot frame). Treat the record like the
Win32 ExtSelectClipRgn API: a non-NULL region with RGN_COPY
replaces the clip, a NULL region (cbRgnData == 0) with RGN_COPY
resets the clip to the default null region.
Add a minimal hand-crafted EMF (TestExtSelectClipRgnCopy.emf) that
draws a (0,0)-(200,200) rectangle through a (50,50)-(150,150)
RGN_COPY clip and asserts the imported metafile wraps the rectangle
in a clip-region mask matching the requested rectangle.
Update existing test expectations to reflect the new clip-region
group/mask wrappers that now appear in the metafile primitive tree
where RGN_COPY data is present (testCreatePen, testPolyPolygon,
testTextMapMode, testEmfPlusSetPageTransform,
testDrawImagePointsWithMetafile, testSine).
Signed-off-by: Andras Timar <andras.timar@collabora.com>
Change-Id: Id123157b64b75d817b4736443eac14804b04bb89
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2206
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit 1c2ff94b6079451a7047a2afb45467d6fe31cb4f)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205072
Tested-by: Jenkins
Reviewed-by: Julien Nabet <serval2412@yahoo.fr>
DrawPolygon and DrawRect already route Pattern fill style through
ImplEmitPatternFill, but DrawEllipse, DrawRoundRect, DrawPie,
DrawChord, and DrawPolyPolygon still emit their plain Meta*Action
which leaves the shape unfilled. Route Pattern fill through the
helper for those too, converting the shape to its polygon
equivalent and emitting the clipped MetaWallpaperAction.
Add a unit test that draws an ellipse with a DIB pattern brush and
asserts the wallpaper is emitted in the metafile dump. Without the
fix the ellipse renders as a hairline outline only.
Signed-off-by: Andras Timar <andras.timar@collabora.com>
Change-Id: I2d4e273029770ddc727bc24d9b3205fe079fafd6
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2205
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit e87013a0457d270d442841610f4a3430e82f1274)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205041
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
UpdateFillStyle short-circuits when maLatestFillStyle == maFillStyle,
but for a hatched brush the emitted MetaFillColorAction depends on
mnBkMode (bk color when OPAQUE, transparent when TRANSPARENT). With
no brush change between two rectangles separated only by SETBKMODE,
the second rectangle inherits the previous OPAQUE bk color fill, so
the gaps between hatch lines stay opaque.
Make SetBkMode invalidate maLatestFillStyle.aFillColor (using the
same sentinel that ResetInternalState uses) when the mode actually
changes, forcing the next UpdateFillStyle to re-emit a fresh
MetaFillColorAction with the correct bk-mode-dependent fill.
Add a unit test with a minimal hand-crafted WMF that draws two
rectangles using the same hatched brush across a SETBKMODE flip
and asserts that both a #ff0000 (OPAQUE bk color) and a #000000
(TRANSPARENT) fillcolor are emitted in the metafile.
Signed-off-by: Andras Timar <andras.timar@collabora.com>
Change-Id: I34b8984989f3ce9108464ad5a8c379174a988b59
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2204
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit 41ddf034e276a5493f4fd56be61702a8b28e9649)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205040
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
META_DIBCREATEPATTERNBRUSH with Style=BS_PATTERN was dropped on the
floor with a SAL_WARN, and BS_DIBPATTERN averaged the bitmap to a
solid color, so neither produced a real pattern fill. Read both
variants into a real Bitmap (DIB or, for BS_PATTERN, a 1bpp Bitmap16)
and store it as a Pattern WinMtfFillStyle. Real-world generators
emit a DIB even with Style=BS_PATTERN, so peek the leading DWORD to
decide between DIB and Bitmap16. The same Bitmap16 helper handles
the obsolete META_CREATEPATTERNBRUSH record (32-byte legacy BITMAP +
reserved padding per MS-WMF 2.3.4.4).
The Pattern fill type was only handled in DrawPolygon, and that path
emitted XPATHFILL_SEQ_BEGIN/END comments with no actual paint
primitives. wmfemfhelper does not consume those comments, so the
PNG/drawinglayer rendering path saw nothing. Replace the comment
emission with a clip-region wrapped MetaWallpaperAction (Tile style)
which is fully consumed downstream. Factor the emission into
ImplEmitPatternFill and call it from DrawRect too, where Pattern
was previously not handled at all.
WinMtfFillStyle::operator== did not compare aBmp, so successive
pattern brushes with different bitmaps but identical solid-fill
fields compared equal and UpdateFillStyle short-circuited, leaving
maLatestFillStyle pointing at the previous bitmap. Include aBmp in
the equality check.
Add a unit test with a minimal hand-crafted WMF that asserts the
expected wallpaper sequence in the metafile dump.
Signed-off-by: Andras Timar <andras.timar@collabora.com>
Change-Id: Ia2662de9cac5fcf1a7153237f9974467b8f849de
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2203
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit 66dcbef6b5ceec8d9ccd4542509d5f9d7fdce2c1)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205039
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
The tracking field was parsed but ignored, so DrawString always
used the font's natural character advances. Now build a DX-array
by multiplying each cumulative width by tracking, and pass it to
the text primitive. Also use the stretched width for alignment
math so center/far positioning stays correct.
testDrawStringTracking loads an EMF+ with tracking == 1.5 and checks
that the resulting textsimpleportion carries a stretched DX-array.
testDrawStringAlign turned out to use a file with tracking == 1.03 and
its expected x positions were based on the old buggy behavior (tracking
silently ignored). Update the centered/right-aligned expectations to
match the corrected text width.
Signed-off-by: Andras Timar <andras.timar@collabora.com>
Change-Id: Ica93f6ba11d2d951688ee18230e5993d97a34db6
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1986
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
(cherry picked from commit 1a9cce32f7408aab06289295c63b3e24146472a0)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/204839
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
Handle BS_HATCHED brush style in EMR_CREATEBRUSHINDIRECT,
W_META_CREATEBRUSHINDIRECT, and EMR_EXTCREATEPEN.
For brushes (hatch indices 0-5), map Windows hatch styles
(HS_HORIZONTAL..HS_DIAGCROSS) to VCL Hatch objects and emit
MetaHatchAction in all polygon/polypolygon fill paths.
For EMF-specific hatch indices 6-11, use the appropriate color
source per [MS-EMF] 2.1.17: brush color (6-7), text color (8-9),
or background color (10-11) as solid fills.
For wide geometric pens with BS_HATCHED (EMR_EXTCREATEPEN),
create stroke area geometry via createAreaGeometry and render
the hatch pattern inside the pen stroke area, replacing the
normal MetaPolyLineAction/MetaLineAction. This covers all
drawing paths including LineTo, DrawPolyLine, DrawPolygon,
DrawPolyPolygon, DrawRect, DrawRoundRect, DrawEllipse, DrawArc,
DrawPie, DrawChord, DrawPolyBezier, and StrokeAndFillPath.
Change-Id: Ie8482ac53b6d4d263793488ce10a97fa1716c68d
Reviewed-on: https://gerrit.collaboraoffice.com/c/core/+/325
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit 8808d550d12afb3e7abc4fe6a3145d80fc5bdde4)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/204389
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
The polygon fill mode (ALTERNATE vs WINDING) was ignored in both EMF
and WMF readers. ALTERNATE (even-odd) is the default; WINDING
(non-zero winding) appears in 2541/6939 EMF files and 135/467 WMF
files that set the mode. Self-intersecting polygons like pentagram
stars render differently under the two rules.
Store the fill mode state in MtfTools with save/restore in Push/Pop,
wire up the record handlers, and fix the hardcoded fillNonZero in
DrawPolygon pattern fills to respect the current mode.
Add a unit test with a pentagram star EMF using WINDING mode.
Change-Id: I1d9127b79cc6c3b67f39bebe2c82e806c9db4ce8
Reviewed-on: https://gerrit.collaboraoffice.com/c/core/+/324
Tested-by: Andras Timar <andras.timar@collabora.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Signed-off-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/204388
Tested-by: Jenkins
Read the TriVertex array and GradientRectangle indices, then emit
MetaGradientAction with a linear gradient for each rectangle pair.
- GRADIENT_FILL_RECT_H (0): horizontal, left-to-right
- GRADIENT_FILL_RECT_V (1): vertical, top-to-bottom
- GRADIENT_FILL_TRIANGLE (2): logged as TODO (Gouraud shading has
no direct VCL primitive)
COLOR16 values are converted to 8-bit via >> 8; Alpha is ignored
per the [MS-EMF] spec.
Change-Id: I9bb525eb16fe63908b0160ff029c270765edda15
Reviewed-on: https://gerrit.collaboraoffice.com/c/core/+/323
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Andras Timar <andras.timar@collabora.com>
(cherry picked from commit b13431518550e387318190b6827eaf10427aa745)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/204387
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Wire up EMR_EXCLUDECLIPRECT (record type 29) in the EMF reader.
ExcludeClipRect() was already implemented in MtfTools and used by the
WMF reader, but missing from the EMF record dispatch. This record
subtracts a rectangle from the current clipping region, creating a
"hole" that prevents drawing in that area.
Present in 291 of 6,939 real-world EMF files (4.2%).
Change-Id: I7bff53473c19453605e5fd88fdeff101f213fd85
Reviewed-on: https://gerrit.collaboraoffice.com/c/core/+/320
Tested-by: Andras Timar <andras.timar@collabora.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit 38e963b2b4b12471b2530e11208a543f403bf4f2)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/204247
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Record 115 (0x73) was incorrectly named EMR_ALPHADIBBLEND, from a
pre-Windows 2000 draft of the EMF spec. The final [MS-EMF] spec defines
it as EMR_SETLAYOUT, which controls the DC layout direction (LTR/RTL).
For now just rename and log when a non-zero LayoutMode is encountered
(SAL_WARN), so we can observe real-world usage before deciding how to
implement the actual coordinate mirroring and text direction changes.
6939 EMF files from public bug trackers were analyzed, 2143 files
contained EMR_SETLAYOUT but none of them contain LayoutMode other
than 0.
Change-Id: Ic4116fcd4a079d09684deb792e2f0ddc646248eb
Reviewed-on: https://gerrit.collaboraoffice.com/c/core/+/319
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Andras Timar <andras.timar@collabora.com>
(cherry picked from commit ab2b4437b178d5d397844cfeeeff43fd88b5cc9f)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/204246
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
also tdf#137440 and tdf#102780
EMF files with pre-shaped text (e.g. Arabic) use ETO_GLYPH_INDEX in
EMR_EXTTEXTOUTW records. The string data in these records contains
font-specific glyph indices (16-bit IDs), not Unicode codepoints.
Previously, emfio read these glyph indices as Unicode text via
read_uInt16s_ToOUString, then passed them to DrawText which creates
a MetaTextArrayAction. On playback, VCL/HarfBuzz would shape these
fake "characters" again, producing double-shaped garbage output.
Fix this by detecting ETO_GLYPH_INDEX and rendering the pre-shaped
glyphs as filled polypolygon outlines, bypassing text shaping entirely.
Implementation:
- Add OutputDevice::GetGlyphOutlines() as a new VCL public API that
takes raw glyph IDs and returns per-glyph B2DPolyPolygon outlines
by calling LogicalFontInstance::GetGlyphOutline() directly. This is
needed because LogicalFontInstance is in VCL's private headers and
not accessible from emfio.
- Add MtfTools::DrawGlyphs() in emfio that mirrors the DrawText()
setup (position/DX/DY mapping, font/color/alignment MetaActions)
but instead of emitting MetaTextArrayAction, it obtains glyph
outlines via GetGlyphOutlines() on a VirtualDevice, positions each
glyph using the DX/DY array, and emits the combined result as a
filled MetaPolyPolygonAction with the text color.
- Branch in emfreader.cxx: when ETO_GLYPH_INDEX is set on the Unicode
variant (EMR_EXTTEXTOUTW), read glyph indices as sal_uInt16 values
and call DrawGlyphs() instead of DrawText().
- Since glyph indices are font-specific, DrawGlyphs() checks font
availability via IsFontAvailable() before rendering. If the required
font is not installed, it returns false and the code falls back to
the standard DrawText() path (same as before this change).
- Remove the stale SAL_WARN_IF for ETO_PDY|ETO_GLYPH_INDEX, since
both flags are now handled.
Change-Id: Ib6e0a0b1accfe61ff871c391d02f4c529764438c
Reviewed-on: https://gerrit.collaboraoffice.com/c/core/+/318
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit b260c2a6d8313c80720e34a366f01bcd0e429f47)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/204245
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
This patch corrects several variable types across the EMF reader
to strictly align with the official Enhanced Metafile specification,
improving memory safety and fixing minor logging bugs.
Change-Id: I1cc1351248bcdb40220c33441e363aaa226f1ea1
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/202625
Tested-by: Jenkins
Reviewed-by: Bartosz Kosiorek <gang65@poczta.onet.pl>
When an EMF+ Dual Mode file switches back to GDI records via
EmfPlusRecordType::GetDC (0x4004), the GDI parser (MtfTools)
might have outdated information about the current state of the
VCL MetaFile, as EMF+ records could have modified it in the meantime.
By introducing ResetInternalState(), we invalidate the "latest"
trackers for fill style, line style, and text attributes. This
forces the parser to re-emit the necessary GDI actions (like
SetFillColor) for the subsequent GDI records, preventing issues
like incorrect colors (e.g., black shapes instead of white).
Change-Id: I1665daba2d9a2105f135e2b638af48d2b14150eb
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/201720
Tested-by: Jenkins
Reviewed-by: Bartosz Kosiorek <gang65@poczta.onet.pl>
Previously, nested EMF images were sized based on rclBounds, which
only encompasses the drawn objects. This caused incorrect scaling
and offsets when the drawing did not fill the entire logical canvas.
Changes:
- Switched from rclBounds to rclFrame for logical canvas dimensions.
- Implemented DPI calculation using szlDevice and szlMillimeters
from the EMF header.
- Correctly mapped rclFrame (0.01mm units) to image pixel
coordinates (x, y, width, height).
Change-Id: I32f6679bedb26e86b069abd6b4d270a385ca7e89
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/201586
Reviewed-by: Bartosz Kosiorek <gang65@poczta.onet.pl>
Tested-by: Jenkins
And not truncate it to an integer value.
Add additional overload for attribute that takes an enumerated type, otherwise
the compiler will complain about ambiguous conversion because it cannot
choose between the attribute that takes a integral value and the one that
takes a double value.
Change-Id: I9eae22817ec3b26da7b9468d1c8b5e6f3e900538
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/201193
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Tested-by: Jenkins
This commit fixes the incorrect positioning and scaling of Metafiles
rendered via EMF+ DrawImagePoints.
Key changes:
- Implemented a normalization matrix for Metafiles to properly map
source coordinates (SrcRect) to the destination.
- Updated EMFPImage to parse and store bounds from nested EMF headers,
ensuring correct dimensions (x, y, width, height) are available.
Change-Id: I07b4d99c334611a10e7faff42b76699f04fa1520
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/201084
Tested-by: Jenkins
Reviewed-by: Bartosz Kosiorek <gang65@poczta.onet.pl>
This patch implements the missing TextureFill brush support for EMF+
records. Previously, texture fills were ignored, resulting in missing
backgrounds or shapes.
Change-Id: I61f80a9851f3929651f54b68d6d4d21e65720aa6
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200547
Tested-by: Jenkins
Reviewed-by: Bartosz Kosiorek <gang65@poczta.onet.pl>
When importing EMF files, certain records (like EXTTEXTOUTW) in
GM_COMPATIBLE mode were not respecting non-proportional scaling
or single-axis mirroring. This resulted in text that was too wide/narrow
or rotated in the wrong direction.
Key changes:
- Added font width scaling based on the ratio between fXScale and fYScale.
- Handled 180-degree rotation when both axes are negative.
- Corrected font orientation for single-axis mirroring by inverting the
angle (3600 - orientation) to compensate for the reversed chirality
of the coordinate system.
Change-Id: Ib1126c192a80b973f343f25bf20ec119d94d71a8
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199770
Tested-by: Jenkins
Reviewed-by: Bartosz Kosiorek <gang65@poczta.onet.pl>
The implementation of SetPageTransform was incorrectly overwriting mnMmX and mnMmY
with calculated pixel values.
These variables represent the Reference Device size from the EMF+ header and should
remain constant. Overwriting them causes mappingChanged() to calculate an incorrect
transformation matrix, as it relies on the original ratio between reference
millimeters and pixels. This led to incorrect scaling and cumulative errors
if multiple SetPageTransform records were present in the document.
This patch ensures that header constants are preserved and the Page Scale
is applied as a separate step in the transformation pipeline.
Change-Id: I7a957f57894cc079292e8f93c119dd0fdb456fb4
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199380
Tested-by: Jenkins
Reviewed-by: Bartosz Kosiorek <gang65@poczta.onet.pl>