Regression from 5707b5dce7
tdf#101083 speed up SVG rendering with pattern fill (2)
This is the same thing I did in
commit 3cbe3a0259
Author: Noel Grandin <noel.grandin@collabora.co.uk>
Date: Mon Jun 14 15:05:59 2021 +0200
tdf#101083 speed up SVG rendering with pattern fill
but cut and paste from the VclPixelProcessor2D to the CairoPixelProcessor2D code.
Which makes this SVG render in reasonable time when using the cairo backend.
We can probably do even better by cutting out the usage of VCL here, but this
is good enough for now.
+ apply the same as af2175bb87
crashtesting: divide by zero
since:
commit 7b807a6b79
Date: Fri Jun 21 12:28:30 2024 +0200
tdf#161086 bitmap location wrong with SVG with an embedded PNG
bodge it by using the requested width/height and not the possibly
zero on fail actual sizes
Change-Id: Ie0e0462e564a568f99d1c5b9c62f71049f71f9b3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/208275
Reviewed-by: Julien Nabet <serval2412@yahoo.fr>
Tested-by: Jenkins
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
Completes the deprecation of legacy coordinate subsystem naming by
renaming GetOutOffYPixel() and SetOutOffYPixel() to
GetDeviceOriginY() and SetDeviceOriginY() across OutputDevice,
Window, and CoordinateMapper.
This unifies axis naming conventions following previous X-axis
refactoring passes, clarifying that these fields represent the
physical origin offsets of the device rendering canvas.
This patch also moves view transformation logic inline from outdev/map
to CoordinateMapper, and wraps sprawling multi-line logic formulas
across mapping routines to clean up formatting boundaries.
Key changes:
* include/vcl/outdev.hxx / window.hxx: Updated public declarations
to replace GetOutOffYPixel with GetDeviceOriginY.
* vcl/inc/CoordinateMapper.hxx: Migrated view transformation cache State
members and mapping calculation methods into the mapper object.
* Global adjustments: Patched all related coordinate offset reads
and tracking writes throughout desktop, editeng, sc, svx, and vcl.
Change-Id: I28fec54a7f3312cc41ada2de38b26351c0a65527
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/203646
Tested-by: Jenkins
Reviewed-by: Dan Williams <dcbw@libreoffice.org>
Rename GetOutOffXPixel() and SetOutOffXPixel() to GetDeviceOriginX()
and SetDeviceOriginX() across OutputDevice, Window, and CoordinateMapper.
The legacy "OutOff" naming convention obscured the difference between
system-level window positioning offsets and internal content scrolling
(SetPixelOffset). The new nomenclature explicitly communicates that
these metrics strictly govern the device coordinate space origin.
This patch focuses strictly on the X-axis coordinate reads and cleans
up duplicated formatting signatures inside the CoordinateMapper header.
Impacted modules:
* include/vcl: Update public declarations in outdev.hxx and window.hxx.
* vcl/inc: Clean up CoordinateMapper.hxx whitespace and scaling hooks.
* Global: Patch dependent pixel coordinate reads across desktop, editeng,
sc, sfx2, svx, and vcl.
Change-Id: I546e1d255887e3b280ff15caca2e27ef10de52d7
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206509
Reviewed-by: Dan Williams <dcbw@libreoffice.org>
Tested-by: Jenkins
Calc imported Diagrams due to using mainly DrawingLayer
oox import code, but export, even of the unchanged
DomTrees, was missing (just never done). Thus in
versions before this being a Diagram was lost, it
just always was converted to a GroupHierarchy containing
the Shapes that were part of the Diagram.
Added to read the Diagram's name at Import at all for Calc
oox import, set and used now at the created Diagram.
Added to secure/save the DomTrees for the imported
ReplacementGraphic when importing oxx Calc, that was just
also never done, so it could not be exported as unchanged/
original data (and was not, so that was never noticed).
Added complete export of oox Diagram to Calc. This includes
unchanged versions, but also changed/added versions. This
may need more work, but own turn-around works already.
This mainly uses the same ExportContent, but that needed
some adaptions.
Doing this I also changed the ShapeImport of Calc to use
a single oox::drawingml::ShapeExport, before it created
a separate temporary one for every Shape that was imported.
Also added the checkMinimalDataDoms check to Calc oox
export that is already used in the other apps. As always,
there are huge differences in oox im/export for Calc
compared to the other apps, e.g. a completely different
Group ImportContext is used compared to Impress and I have
no idea why that is done.
Signed-off-by: Armin Le Grand (collabora) <Armin.LeGrand@collabora.com>
Change-Id: Ib7c1b73f7f72599f6054d0cf9203f46980eec5cf
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1887
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Armin Le Grand <armin.legrand@collabora.com>
(cherry picked from commit b1fbe49401e5e4dbe62ff25580ec7252c0376e88)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206019
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
We already did some improvements, but I wanted to clean
this up somewhat. Reason for the needed corrections was
in principle the sqrt()-based general calculation of
the HoldTime in the default implementation of
calculateCombinedHoldCyclesInSeconds. The original idea
was to hold huge data shorter due to memory constraints.
To solve that we added an adapted version to
CairoPixelProcessor2D.
With lessons learned I decided to remove that and
provide a revised general implementation based on linear
scaling of the HoldTime. Based on assuming the seen
huge Bitmap and estimating 20min for it, just create a
factor and multiply with SizeInBytes.
I checked that and it works as intended. It will spare
us from this problem re-occurring with future SDPRs.
NOTE: This still keeps the CairoSDPR-specific avoiding
of buffering of small Bitmaps when these are available
from Bitmap directly. This stays useful and is
Cairo-specific.
Signed-off-by: Armin Le Grand (collabora) <Armin.LeGrand@collabora.com>
Change-Id: I30c7361c6fbfaf0be90be353091cbaf831db5cd2
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2005
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
(cherry picked from commit a3d3ae5e931a04ff5718382ccffe9f16de336a42)
(cherry picked from commit 7550c6ea0bb82f7574e4b974f8d24bd1662a878b)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205991
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
shows up when running CppunitTest_sc_shapetest
probably from the recent changes here, when calling tryToGetCairoSurface.
Rather than doing explicit cleanup, lets follow the same path used in
include/vcl/cairo.hxx
and pass around a shared_ptr that makes cleanup automatic.
Change-Id: I1bec6f579af182b259cb0edbd86192627e5c61ea
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1858
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit 70966239f816d81cb9dcb208e7c02e08339da28c)
(cherry picked from commit ee2349dba8aa282e30ae65cbf5ffbb27b707e0ec)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205990
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
When isCairoCompatible and we can get cairo_surface_t
directly from Bitmap for small instances (used 160x100
here, can be adapted) use directly. There is no need to
prepare for MipMapping, so spare the
SystemDependentDataHolder buffering for that cases.
For more information, see comments in commit.
Change-Id: Ia9d51a5749124d7001daf2e5355ceec5afccb264
Reviewed-on: https://gerrit.collaboraoffice.com/c/core/+/1384
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Armin Le Grand <armin.legrand@collabora.com>
(cherry picked from commit 62dbd904fbea0dee4d54f1bb75601af40c6b91c4)
(cherry picked from commit a23e06360e796e1264f40d31c818d3ac3a5a1f54)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205989
Tested-by: Jenkins
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
If we have a really 'big' pixel-based graphic the cost for creating
the mip-map entries is high. If that is the case, force keeping this
entry alive and not getting flushed by using a large number of
seconds. In that case the local MipMap is more important than the
memory kept allocated for fast repaints.
To detect 'big' graphics, compare to an assumed ScreenSize (may also
be fetched from real screen if needed). To react, create a buffer
residing time of one hour (increase if needed).
NOTE: This will increase MemoryFootPrint if isCairoCompatible
is false by holding the local cairo_surface_t in CairoSurfaceHelper
longer than before.
Change-Id: I1cf726f00d459bc0cb19bb1d202e64e010061426
Reviewed-on: https://gerrit.collaboraoffice.com/c/core/+/1134
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
(cherry picked from commit 2e1b0a51a745e615ed7e2f22666cc4aa4e005451)
(cherry picked from commit c2c58c177ae822906fe2c558546851643fe54247)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205988
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
The tryToGetCairoSurface() path created a new CairoSurfaceHelper on
every call, bypassing the SystemDependentData cache, so mipmap surfaces
were recomputed per tile paint. Move zero-copy into the CairoSurfaceHelper
constructor so all bitmaps go through the caching path.
Also fix estimateUsageInBytes to account for bytes per pixel.
Change-Id: Ie21b12e92b07a43f4b34f13d22b3aeeaf34534ea
Reviewed-on: https://gerrit.collaboraoffice.com/c/core/+/1105
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Armin Le Grand <armin.legrand@collabora.com>
Reviewed-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Reviewed-by: Noel Grandin <noel.grandin@collabora.com>
(cherry picked from commit 09cad228f400e5dd7f3e06509a35c3c1729c41b9)
(cherry picked from commit ffc9820016c54d3c6d420a778eb8d0886e1cf36b)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205987
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>
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
When exporting to PDF a document with a background image on the page.
The image would always be exported as a bitmap at a fix resolution, even
if the original data had vector form (like a pdf or svg).
This ensures that the original vector data is also exported as it is
done with regularly inserted images.
Change-Id: I7f363614ba375e01a4b076c961ce91dae8c2351b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/202994
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
Replace index-based loops with range-based for loops in baseprocessor3d.cxx
and zbufferprocessor3d.cxx. This improves code readability and reduces the
risk of off-by-one errors. The change is purely refactoring: behavior and
output remain unchanged.
Change-Id: I5d30babac3a0fa5fdcca214e66481862a165d7c7
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/202301
Tested-by: Jenkins
Reviewed-by: Ilmari Lauhakangas <ilmari.lauhakangas@libreoffice.org>
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>