File: | home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx |
Warning: | line 163, column 36 Division by zero |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | |||
2 | /* | |||
3 | * This file is part of the LibreOffice project. | |||
4 | * | |||
5 | * This Source Code Form is subject to the terms of the Mozilla Public | |||
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. | |||
8 | * | |||
9 | * This file incorporates work covered by the following license notice: | |||
10 | * | |||
11 | * Licensed to the Apache Software Foundation (ASF) under one or more | |||
12 | * contributor license agreements. See the NOTICE file distributed | |||
13 | * with this work for additional information regarding copyright | |||
14 | * ownership. The ASF licenses this file to you under the Apache | |||
15 | * License, Version 2.0 (the "License"); you may not use this file | |||
16 | * except in compliance with the License. You may obtain a copy of | |||
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . | |||
18 | */ | |||
19 | ||||
20 | #include <skia/gdiimpl.hxx> | |||
21 | ||||
22 | #include <salgdi.hxx> | |||
23 | #include <skia/salbmp.hxx> | |||
24 | #include <vcl/idle.hxx> | |||
25 | #include <vcl/svapp.hxx> | |||
26 | #include <vcl/lazydelete.hxx> | |||
27 | #include <vcl/gradient.hxx> | |||
28 | #include <vcl/skia/SkiaHelper.hxx> | |||
29 | #include <skia/utils.hxx> | |||
30 | #include <skia/zone.hxx> | |||
31 | ||||
32 | #include <SkCanvas.h> | |||
33 | #include <SkGradientShader.h> | |||
34 | #include <SkPath.h> | |||
35 | #include <SkRegion.h> | |||
36 | #include <SkDashPathEffect.h> | |||
37 | #include <GrBackendSurface.h> | |||
38 | #include <SkTextBlob.h> | |||
39 | #include <SkRSXform.h> | |||
40 | ||||
41 | #include <numeric> | |||
42 | #include <basegfx/polygon/b2dpolygontools.hxx> | |||
43 | #include <basegfx/polygon/b2dpolypolygontools.hxx> | |||
44 | #include <basegfx/polygon/b2dpolypolygoncutter.hxx> | |||
45 | #include <o3tl/sorted_vector.hxx> | |||
46 | ||||
47 | namespace | |||
48 | { | |||
49 | // Create Skia Path from B2DPolygon | |||
50 | // Note that polygons generally have the complication that when used | |||
51 | // for area (fill) operations they usually miss the right-most and | |||
52 | // bottom-most line of pixels of the bounding rectangle (see | |||
53 | // https://lists.freedesktop.org/archives/libreoffice/2019-November/083709.html). | |||
54 | // So be careful with rectangle->polygon conversions (generally avoid them). | |||
55 | void addPolygonToPath(const basegfx::B2DPolygon& rPolygon, SkPath& rPath) | |||
56 | { | |||
57 | const sal_uInt32 nPointCount(rPolygon.count()); | |||
58 | ||||
59 | if (nPointCount <= 1) | |||
60 | return; | |||
61 | ||||
62 | const bool bClosePath(rPolygon.isClosed()); | |||
63 | const bool bHasCurves(rPolygon.areControlPointsUsed()); | |||
64 | ||||
65 | bool bFirst = true; | |||
66 | ||||
67 | sal_uInt32 nCurrentIndex = 0; | |||
68 | sal_uInt32 nPreviousIndex = nPointCount - 1; | |||
69 | ||||
70 | basegfx::B2DPoint aCurrentPoint; | |||
71 | basegfx::B2DPoint aPreviousPoint; | |||
72 | ||||
73 | for (sal_uInt32 nIndex = 0; nIndex <= nPointCount; nIndex++) | |||
74 | { | |||
75 | if (nIndex == nPointCount && !bClosePath) | |||
76 | continue; | |||
77 | ||||
78 | // Make sure we loop the last point to first point | |||
79 | nCurrentIndex = nIndex % nPointCount; | |||
80 | aCurrentPoint = rPolygon.getB2DPoint(nCurrentIndex); | |||
81 | ||||
82 | if (bFirst) | |||
83 | { | |||
84 | rPath.moveTo(aCurrentPoint.getX(), aCurrentPoint.getY()); | |||
85 | bFirst = false; | |||
86 | } | |||
87 | else if (!bHasCurves) | |||
88 | { | |||
89 | rPath.lineTo(aCurrentPoint.getX(), aCurrentPoint.getY()); | |||
90 | } | |||
91 | else | |||
92 | { | |||
93 | basegfx::B2DPoint aPreviousControlPoint = rPolygon.getNextControlPoint(nPreviousIndex); | |||
94 | basegfx::B2DPoint aCurrentControlPoint = rPolygon.getPrevControlPoint(nCurrentIndex); | |||
95 | ||||
96 | if (aPreviousControlPoint.equal(aPreviousPoint) | |||
97 | && aCurrentControlPoint.equal(aCurrentPoint)) | |||
98 | rPath.lineTo(aCurrentPoint.getX(), aCurrentPoint.getY()); // a straight line | |||
99 | else | |||
100 | { | |||
101 | if (aPreviousControlPoint.equal(aPreviousPoint)) | |||
102 | { | |||
103 | aPreviousControlPoint | |||
104 | = aPreviousPoint + ((aPreviousControlPoint - aCurrentPoint) * 0.0005); | |||
105 | } | |||
106 | if (aCurrentControlPoint.equal(aCurrentPoint)) | |||
107 | { | |||
108 | aCurrentControlPoint | |||
109 | = aCurrentPoint + ((aCurrentControlPoint - aPreviousPoint) * 0.0005); | |||
110 | } | |||
111 | rPath.cubicTo(aPreviousControlPoint.getX(), aPreviousControlPoint.getY(), | |||
112 | aCurrentControlPoint.getX(), aCurrentControlPoint.getY(), | |||
113 | aCurrentPoint.getX(), aCurrentPoint.getY()); | |||
114 | } | |||
115 | } | |||
116 | aPreviousPoint = aCurrentPoint; | |||
117 | nPreviousIndex = nCurrentIndex; | |||
118 | } | |||
119 | if (bClosePath) | |||
120 | { | |||
121 | rPath.close(); | |||
122 | } | |||
123 | } | |||
124 | ||||
125 | void addPolyPolygonToPath(const basegfx::B2DPolyPolygon& rPolyPolygon, SkPath& rPath) | |||
126 | { | |||
127 | const sal_uInt32 nPolygonCount(rPolyPolygon.count()); | |||
128 | ||||
129 | if (nPolygonCount == 0) | |||
130 | return; | |||
131 | ||||
132 | for (const auto& rPolygon : rPolyPolygon) | |||
133 | { | |||
134 | addPolygonToPath(rPolygon, rPath); | |||
135 | } | |||
136 | } | |||
137 | ||||
138 | // Check if the given polygon contains a straight line. If not, it consists | |||
139 | // solely of curves. | |||
140 | bool polygonContainsLine(const basegfx::B2DPolyPolygon& rPolyPolygon) | |||
141 | { | |||
142 | if (!rPolyPolygon.areControlPointsUsed()) | |||
143 | return true; // no curves at all | |||
144 | for (const auto& rPolygon : rPolyPolygon) | |||
145 | { | |||
146 | const sal_uInt32 nPointCount(rPolygon.count()); | |||
147 | bool bFirst = true; | |||
148 | ||||
149 | const bool bClosePath(rPolygon.isClosed()); | |||
150 | ||||
151 | sal_uInt32 nCurrentIndex = 0; | |||
152 | sal_uInt32 nPreviousIndex = nPointCount - 1; | |||
153 | ||||
154 | basegfx::B2DPoint aCurrentPoint; | |||
155 | basegfx::B2DPoint aPreviousPoint; | |||
156 | ||||
157 | for (sal_uInt32 nIndex = 0; nIndex
| |||
158 | { | |||
159 | if (nIndex == nPointCount && !bClosePath) | |||
160 | continue; | |||
161 | ||||
162 | // Make sure we loop the last point to first point | |||
163 | nCurrentIndex = nIndex % nPointCount; | |||
| ||||
164 | if (bFirst) | |||
165 | bFirst = false; | |||
166 | else | |||
167 | { | |||
168 | basegfx::B2DPoint aPreviousControlPoint | |||
169 | = rPolygon.getNextControlPoint(nPreviousIndex); | |||
170 | basegfx::B2DPoint aCurrentControlPoint | |||
171 | = rPolygon.getPrevControlPoint(nCurrentIndex); | |||
172 | ||||
173 | if (aPreviousControlPoint.equal(aPreviousPoint) | |||
174 | && aCurrentControlPoint.equal(aCurrentPoint)) | |||
175 | { | |||
176 | return true; // found a straight line | |||
177 | } | |||
178 | } | |||
179 | aPreviousPoint = aCurrentPoint; | |||
180 | nPreviousIndex = nCurrentIndex; | |||
181 | } | |||
182 | } | |||
183 | return false; // no straight line found | |||
184 | } | |||
185 | ||||
186 | SkColor toSkColor(Color color) | |||
187 | { | |||
188 | return SkColorSetARGB(255 - color.GetTransparency(), color.GetRed(), color.GetGreen(), | |||
189 | color.GetBlue()); | |||
190 | } | |||
191 | ||||
192 | SkColor toSkColorWithTransparency(Color aColor, double fTransparency) | |||
193 | { | |||
194 | return SkColorSetA(toSkColor(aColor), 255 * (1.0 - fTransparency)); | |||
195 | } | |||
196 | ||||
197 | SkColor toSkColorWithIntensity(Color color, int intensity) | |||
198 | { | |||
199 | return SkColorSetARGB(255 - color.GetTransparency(), color.GetRed() * intensity / 100, | |||
200 | color.GetGreen() * intensity / 100, color.GetBlue() * intensity / 100); | |||
201 | } | |||
202 | ||||
203 | Color fromSkColor(SkColor color) | |||
204 | { | |||
205 | return Color(255 - SkColorGetA(color)(((color) >> 24) & 0xFF), SkColorGetR(color)(((color) >> 16) & 0xFF), SkColorGetG(color)(((color) >> 8) & 0xFF), | |||
206 | SkColorGetB(color)(((color) >> 0) & 0xFF)); | |||
207 | } | |||
208 | ||||
209 | // returns true if the source or destination rectangles are invalid | |||
210 | bool checkInvalidSourceOrDestination(SalTwoRect const& rPosAry) | |||
211 | { | |||
212 | return rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0 | |||
213 | || rPosAry.mnDestHeight <= 0; | |||
214 | } | |||
215 | ||||
216 | } // end anonymous namespace | |||
217 | ||||
218 | // Class that triggers flushing the backing buffer when idle. | |||
219 | class SkiaFlushIdle : public Idle | |||
220 | { | |||
221 | SkiaSalGraphicsImpl* mpGraphics; | |||
222 | #ifndef NDEBUG | |||
223 | char* debugname; | |||
224 | #endif | |||
225 | ||||
226 | public: | |||
227 | explicit SkiaFlushIdle(SkiaSalGraphicsImpl* pGraphics) | |||
228 | : Idle(get_debug_name(pGraphics)) | |||
229 | , mpGraphics(pGraphics) | |||
230 | { | |||
231 | // We don't want to be swapping before we've painted. | |||
232 | SetPriority(TaskPriority::POST_PAINT); | |||
233 | } | |||
234 | #ifndef NDEBUG | |||
235 | virtual ~SkiaFlushIdle() { free(debugname); } | |||
236 | #endif | |||
237 | const char* get_debug_name(SkiaSalGraphicsImpl* pGraphics) | |||
238 | { | |||
239 | #ifndef NDEBUG | |||
240 | // Idle keeps just a pointer, so we need to store the string | |||
241 | debugname = strdup( | |||
242 | OString("skia idle 0x" + OString::number(reinterpret_cast<sal_uIntPtr>(pGraphics), 16)) | |||
243 | .getStr()); | |||
244 | return debugname; | |||
245 | #else | |||
246 | (void)pGraphics; | |||
247 | return "skia idle"; | |||
248 | #endif | |||
249 | } | |||
250 | ||||
251 | virtual void Invoke() override | |||
252 | { | |||
253 | mpGraphics->performFlush(); | |||
254 | Stop(); | |||
255 | SetPriority(TaskPriority::HIGHEST); | |||
256 | } | |||
257 | }; | |||
258 | ||||
259 | SkiaSalGraphicsImpl::SkiaSalGraphicsImpl(SalGraphics& rParent, SalGeometryProvider* pProvider) | |||
260 | : mParent(rParent) | |||
261 | , mProvider(pProvider) | |||
262 | , mIsGPU(false) | |||
263 | , mLineColor(SALCOLOR_NONE) | |||
264 | , mFillColor(SALCOLOR_NONE) | |||
265 | , mXorMode(false) | |||
266 | , mFlush(new SkiaFlushIdle(this)) | |||
267 | , mPendingOperationsToFlush(0) | |||
268 | { | |||
269 | } | |||
270 | ||||
271 | SkiaSalGraphicsImpl::~SkiaSalGraphicsImpl() | |||
272 | { | |||
273 | assert(!mSurface)(static_cast <bool> (!mSurface) ? void (0) : __assert_fail ("!mSurface", "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" , 273, __extension__ __PRETTY_FUNCTION__)); | |||
274 | assert(!mWindowContext)(static_cast <bool> (!mWindowContext) ? void (0) : __assert_fail ("!mWindowContext", "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" , 274, __extension__ __PRETTY_FUNCTION__)); | |||
275 | } | |||
276 | ||||
277 | void SkiaSalGraphicsImpl::Init() {} | |||
278 | ||||
279 | void SkiaSalGraphicsImpl::recreateSurface() | |||
280 | { | |||
281 | destroySurface(); | |||
282 | createSurface(); | |||
283 | } | |||
284 | ||||
285 | void SkiaSalGraphicsImpl::createSurface() | |||
286 | { | |||
287 | SkiaZone zone; | |||
288 | if (isOffscreen()) | |||
289 | createOffscreenSurface(); | |||
290 | else | |||
291 | createWindowSurface(); | |||
292 | mSurface->getCanvas()->save(); // see SetClipRegion() | |||
293 | mClipRegion = vcl::Region(tools::Rectangle(0, 0, GetWidth(), GetHeight())); | |||
294 | ||||
295 | // We don't want to be swapping before we've painted. | |||
296 | mFlush->Stop(); | |||
297 | mFlush->SetPriority(TaskPriority::POST_PAINT); | |||
298 | } | |||
299 | ||||
300 | void SkiaSalGraphicsImpl::createWindowSurface(bool forceRaster) | |||
301 | { | |||
302 | SkiaZone zone; | |||
303 | assert(!isOffscreen())(static_cast <bool> (!isOffscreen()) ? void (0) : __assert_fail ("!isOffscreen()", "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" , 303, __extension__ __PRETTY_FUNCTION__)); | |||
304 | assert(!mSurface)(static_cast <bool> (!mSurface) ? void (0) : __assert_fail ("!mSurface", "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" , 304, __extension__ __PRETTY_FUNCTION__)); | |||
305 | assert(!mWindowContext)(static_cast <bool> (!mWindowContext) ? void (0) : __assert_fail ("!mWindowContext", "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" , 305, __extension__ __PRETTY_FUNCTION__)); | |||
306 | createWindowContext(forceRaster); | |||
307 | if (mWindowContext) | |||
308 | mSurface = mWindowContext->getBackbufferSurface(); | |||
309 | if (!mSurface) | |||
310 | { | |||
311 | switch (SkiaHelper::renderMethodToUse()) | |||
312 | { | |||
313 | case SkiaHelper::RenderVulkan: | |||
314 | SAL_WARN("vcl.skia",do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl.skia")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "cannot create Vulkan GPU window surface, falling back to Raster" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.skia" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "315" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "cannot create Vulkan GPU window surface, falling back to Raster" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "cannot create Vulkan GPU window surface, falling back to Raster" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.skia" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "315" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "cannot create Vulkan GPU window surface, falling back to Raster" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.skia" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "315" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "cannot create Vulkan GPU window surface, falling back to Raster" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "cannot create Vulkan GPU window surface, falling back to Raster" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.skia" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "315" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
315 | "cannot create Vulkan GPU window surface, falling back to Raster")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl.skia")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "cannot create Vulkan GPU window surface, falling back to Raster" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.skia" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "315" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "cannot create Vulkan GPU window surface, falling back to Raster" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "cannot create Vulkan GPU window surface, falling back to Raster" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.skia" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "315" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "cannot create Vulkan GPU window surface, falling back to Raster" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.skia" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "315" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "cannot create Vulkan GPU window surface, falling back to Raster" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "cannot create Vulkan GPU window surface, falling back to Raster" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.skia" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "315" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
316 | destroySurface(); // destroys also WindowContext | |||
317 | return createWindowSurface(true); // try again | |||
318 | case SkiaHelper::RenderRaster: | |||
319 | abort(); // This should not really happen, do not even try to cope with it. | |||
320 | } | |||
321 | } | |||
322 | mIsGPU = mSurface->getCanvas()->getGrContext() != nullptr; | |||
323 | #ifdef DBG_UTIL | |||
324 | SkiaHelper::prefillSurface(mSurface); | |||
325 | #endif | |||
326 | } | |||
327 | ||||
328 | void SkiaSalGraphicsImpl::createOffscreenSurface() | |||
329 | { | |||
330 | SkiaZone zone; | |||
331 | assert(isOffscreen())(static_cast <bool> (isOffscreen()) ? void (0) : __assert_fail ("isOffscreen()", "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" , 331, __extension__ __PRETTY_FUNCTION__)); | |||
332 | assert(!mSurface)(static_cast <bool> (!mSurface) ? void (0) : __assert_fail ("!mSurface", "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" , 332, __extension__ __PRETTY_FUNCTION__)); | |||
333 | assert(!mWindowContext)(static_cast <bool> (!mWindowContext) ? void (0) : __assert_fail ("!mWindowContext", "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" , 333, __extension__ __PRETTY_FUNCTION__)); | |||
334 | // When created (especially on Windows), Init() gets called with size (0,0), which is invalid size | |||
335 | // for Skia. May happen also in rare cases such as shutting down (tdf#131939). | |||
336 | int width = std::max(1, GetWidth()); | |||
337 | int height = std::max(1, GetHeight()); | |||
338 | switch (SkiaHelper::renderMethodToUse()) | |||
339 | { | |||
340 | case SkiaHelper::RenderVulkan: | |||
341 | { | |||
342 | if (SkiaHelper::getSharedGrDirectContext()) | |||
343 | { | |||
344 | mSurface = SkiaHelper::createSkSurface(width, height); | |||
345 | if (mSurface) | |||
346 | { | |||
347 | mIsGPU = mSurface->getCanvas()->getGrContext() != nullptr; | |||
348 | return; | |||
349 | } | |||
350 | } | |||
351 | break; | |||
352 | } | |||
353 | default: | |||
354 | break; | |||
355 | } | |||
356 | // Create raster surface as a fallback. | |||
357 | mSurface = SkiaHelper::createSkSurface(width, height); | |||
358 | assert(mSurface)(static_cast <bool> (mSurface) ? void (0) : __assert_fail ("mSurface", "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" , 358, __extension__ __PRETTY_FUNCTION__)); | |||
359 | assert(!mSurface->getCanvas()->getGrContext())(static_cast <bool> (!mSurface->getCanvas()->getGrContext ()) ? void (0) : __assert_fail ("!mSurface->getCanvas()->getGrContext()" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 359 , __extension__ __PRETTY_FUNCTION__)); // is not GPU-backed | |||
360 | mIsGPU = false; | |||
361 | } | |||
362 | ||||
363 | void SkiaSalGraphicsImpl::destroySurface() | |||
364 | { | |||
365 | SkiaZone zone; | |||
366 | if (mSurface) | |||
367 | { | |||
368 | // check setClipRegion() invariant | |||
369 | assert(mSurface->getCanvas()->getSaveCount() == 2)(static_cast <bool> (mSurface->getCanvas()->getSaveCount () == 2) ? void (0) : __assert_fail ("mSurface->getCanvas()->getSaveCount() == 2" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 369 , __extension__ __PRETTY_FUNCTION__)); | |||
370 | // if this fails, something forgot to use SkAutoCanvasRestore | |||
371 | assert(mSurface->getCanvas()->getTotalMatrix().isIdentity())(static_cast <bool> (mSurface->getCanvas()->getTotalMatrix ().isIdentity()) ? void (0) : __assert_fail ("mSurface->getCanvas()->getTotalMatrix().isIdentity()" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 371 , __extension__ __PRETTY_FUNCTION__)); | |||
372 | } | |||
373 | // If we use e.g. Vulkan, we must destroy the surface before the context, | |||
374 | // otherwise destroying the surface will reference the context. This is | |||
375 | // handled by calling destroySurface() before destroying the context. | |||
376 | // However we also need to flush the surface before destroying it, | |||
377 | // otherwise when destroying the context later there still could be queued | |||
378 | // commands referring to the surface data. This is probably a Skia bug, | |||
379 | // but work around it here. | |||
380 | if (mSurface) | |||
381 | mSurface->flushAndSubmit(); | |||
382 | mSurface.reset(); | |||
383 | mWindowContext.reset(); | |||
384 | mIsGPU = false; | |||
385 | } | |||
386 | ||||
387 | void SkiaSalGraphicsImpl::DeInit() { destroySurface(); } | |||
388 | ||||
389 | void SkiaSalGraphicsImpl::preDraw() | |||
390 | { | |||
391 | assert(comphelper::SolarMutex::get()->IsCurrentThread())(static_cast <bool> (comphelper::SolarMutex::get()-> IsCurrentThread()) ? void (0) : __assert_fail ("comphelper::SolarMutex::get()->IsCurrentThread()" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 391 , __extension__ __PRETTY_FUNCTION__)); | |||
392 | SkiaZone::enter(); // matched in postDraw() | |||
393 | checkSurface(); | |||
394 | checkPendingDrawing(); | |||
395 | } | |||
396 | ||||
397 | void SkiaSalGraphicsImpl::postDraw() | |||
398 | { | |||
399 | scheduleFlush(); | |||
400 | // Skia (at least when using Vulkan) queues drawing commands and executes them only later. | |||
401 | // But tdf#136369 leads to creating and queueing many tiny bitmaps, which makes | |||
402 | // Skia slow, and may make it even run out of memory. So force a flush if such | |||
403 | // a problematic operation has been performed too many times without a flush. | |||
404 | if (mPendingOperationsToFlush > 1000) | |||
405 | { | |||
406 | mSurface->flushAndSubmit(); | |||
407 | mPendingOperationsToFlush = 0; | |||
408 | } | |||
409 | SkiaZone::leave(); // matched in preDraw() | |||
410 | // If there's a problem with the GPU context, abort. | |||
411 | if (GrContext* context = mSurface->getCanvas()->getGrContext()) | |||
412 | { | |||
413 | // Running out of memory on the GPU technically could be possibly recoverable, | |||
414 | // but we don't know the exact status of the surface (and what has or has not been drawn to it), | |||
415 | // so in practice this is unrecoverable without possible data loss. | |||
416 | if (context->oomed()) | |||
417 | { | |||
418 | SAL_WARN("vcl.skia", "GPU context has run out of memory, aborting.")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl.skia")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "GPU context has run out of memory, aborting." ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.skia" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "418" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "GPU context has run out of memory, aborting." ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GPU context has run out of memory, aborting."; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.skia"), ( "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "418" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "GPU context has run out of memory, aborting.") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.skia" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "418" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "GPU context has run out of memory, aborting." ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GPU context has run out of memory, aborting."; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.skia"), ( "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "418" ": "), sal_detail_stream, 0); }; std::abort(); break; } } } while (false); | |||
419 | abort(); | |||
420 | } | |||
421 | // Unrecoverable problem. | |||
422 | if (context->abandoned()) | |||
423 | { | |||
424 | SAL_WARN("vcl.skia", "GPU context has been abandoned, aborting.")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl.skia")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "GPU context has been abandoned, aborting." ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.skia" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "424" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "GPU context has been abandoned, aborting." ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GPU context has been abandoned, aborting."; ::sal:: detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.skia"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "424" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "GPU context has been abandoned, aborting.") == 1 ) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.skia" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "424" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "GPU context has been abandoned, aborting." ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GPU context has been abandoned, aborting."; ::sal:: detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.skia"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "424" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
425 | abort(); | |||
426 | } | |||
427 | } | |||
428 | } | |||
429 | ||||
430 | void SkiaSalGraphicsImpl::scheduleFlush() | |||
431 | { | |||
432 | if (!isOffscreen()) | |||
433 | { | |||
434 | if (!Application::IsInExecute()) | |||
435 | performFlush(); // otherwise nothing would trigger idle rendering | |||
436 | else if (!mFlush->IsActive()) | |||
437 | mFlush->Start(); | |||
438 | } | |||
439 | } | |||
440 | ||||
441 | // VCL can sometimes resize us without telling us, update the surface if needed. | |||
442 | // Also create the surface on demand if it has not been created yet (it is a waste | |||
443 | // to create it in Init() if it gets recreated later anyway). | |||
444 | void SkiaSalGraphicsImpl::checkSurface() | |||
445 | { | |||
446 | if (!mSurface) | |||
447 | { | |||
448 | createSurface(); | |||
449 | SAL_INFO("vcl.skia.trace",do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "create(" << this << "): " << Size(mSurface->width(), mSurface-> height())) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "450" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "create(" << this << "): " << Size(mSurface->width(), mSurface->height())), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "create(" << this << "): " << Size (mSurface->width(), mSurface->height()); ::sal::detail:: log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "450" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "create(" << this << "): " << Size (mSurface->width(), mSurface->height())) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "450" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "create(" << this << "): " << Size(mSurface->width(), mSurface->height())), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "create(" << this << "): " << Size (mSurface->width(), mSurface->height()); ::sal::detail:: log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "450" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
450 | "create(" << this << "): " << Size(mSurface->width(), mSurface->height()))do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "create(" << this << "): " << Size(mSurface->width(), mSurface-> height())) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "450" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "create(" << this << "): " << Size(mSurface->width(), mSurface->height())), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "create(" << this << "): " << Size (mSurface->width(), mSurface->height()); ::sal::detail:: log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "450" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "create(" << this << "): " << Size (mSurface->width(), mSurface->height())) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "450" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "create(" << this << "): " << Size(mSurface->width(), mSurface->height())), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "create(" << this << "): " << Size (mSurface->width(), mSurface->height()); ::sal::detail:: log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "450" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
451 | } | |||
452 | else if (GetWidth() != mSurface->width() || GetHeight() != mSurface->height()) | |||
453 | { | |||
454 | if (!avoidRecreateByResize()) | |||
455 | { | |||
456 | Size oldSize(mSurface->width(), mSurface->height()); | |||
457 | // Recreating a surface means that the old SkSurface contents will be lost. | |||
458 | // But if a window has been resized the windowing system may send repaint events | |||
459 | // only for changed parts and VCL would not repaint the whole area, assuming | |||
460 | // that some parts have not changed (this is what seems to cause tdf#131952). | |||
461 | // So carry over the old contents for windows, even though generally everything | |||
462 | // will be usually repainted anyway. | |||
463 | sk_sp<SkImage> snapshot; | |||
464 | if (!isOffscreen()) | |||
465 | { | |||
466 | flushDrawing(); | |||
467 | snapshot = SkiaHelper::makeCheckedImageSnapshot(mSurface); | |||
468 | } | |||
469 | recreateSurface(); | |||
470 | if (snapshot) | |||
471 | { | |||
472 | SkPaint paint; | |||
473 | paint.setBlendMode(SkBlendMode::kSrc); // copy as is | |||
474 | mSurface->getCanvas()->drawImage(snapshot, 0, 0, &paint); | |||
475 | } | |||
476 | SAL_INFO("vcl.skia.trace", "recreate(" << this << "): old " << oldSize << " new "do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface->width(), mSurface->height()) << " requested " << Size(GetWidth(), GetHeight())) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "479" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface-> width(), mSurface->height()) << " requested " << Size(GetWidth(), GetHeight())), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface->width(), mSurface->height()) << " requested " << Size(GetWidth(), GetHeight()); ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "479" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface->width(), mSurface->height()) << " requested " << Size( GetWidth(), GetHeight())) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "479" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface-> width(), mSurface->height()) << " requested " << Size(GetWidth(), GetHeight())), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface->width(), mSurface->height()) << " requested " << Size(GetWidth(), GetHeight()); ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "479" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
477 | << Size(mSurface->width(), mSurface->height())do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface->width(), mSurface->height()) << " requested " << Size(GetWidth(), GetHeight())) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "479" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface-> width(), mSurface->height()) << " requested " << Size(GetWidth(), GetHeight())), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface->width(), mSurface->height()) << " requested " << Size(GetWidth(), GetHeight()); ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "479" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface->width(), mSurface->height()) << " requested " << Size( GetWidth(), GetHeight())) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "479" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface-> width(), mSurface->height()) << " requested " << Size(GetWidth(), GetHeight())), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface->width(), mSurface->height()) << " requested " << Size(GetWidth(), GetHeight()); ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "479" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
478 | << " requested "do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface->width(), mSurface->height()) << " requested " << Size(GetWidth(), GetHeight())) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "479" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface-> width(), mSurface->height()) << " requested " << Size(GetWidth(), GetHeight())), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface->width(), mSurface->height()) << " requested " << Size(GetWidth(), GetHeight()); ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "479" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface->width(), mSurface->height()) << " requested " << Size( GetWidth(), GetHeight())) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "479" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface-> width(), mSurface->height()) << " requested " << Size(GetWidth(), GetHeight())), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface->width(), mSurface->height()) << " requested " << Size(GetWidth(), GetHeight()); ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "479" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
479 | << Size(GetWidth(), GetHeight()))do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface->width(), mSurface->height()) << " requested " << Size(GetWidth(), GetHeight())) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "479" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface-> width(), mSurface->height()) << " requested " << Size(GetWidth(), GetHeight())), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface->width(), mSurface->height()) << " requested " << Size(GetWidth(), GetHeight()); ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "479" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface->width(), mSurface->height()) << " requested " << Size( GetWidth(), GetHeight())) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "479" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface-> width(), mSurface->height()) << " requested " << Size(GetWidth(), GetHeight())), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "recreate(" << this << "): old " << oldSize << " new " << Size(mSurface->width(), mSurface->height()) << " requested " << Size(GetWidth(), GetHeight()); ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "479" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
480 | } | |||
481 | } | |||
482 | } | |||
483 | ||||
484 | void SkiaSalGraphicsImpl::flushDrawing() | |||
485 | { | |||
486 | if (!mSurface) | |||
487 | return; | |||
488 | checkPendingDrawing(); | |||
489 | if (mXorMode) | |||
490 | applyXor(); | |||
491 | mSurface->flushAndSubmit(); | |||
492 | mPendingOperationsToFlush = 0; | |||
493 | } | |||
494 | ||||
495 | bool SkiaSalGraphicsImpl::setClipRegion(const vcl::Region& region) | |||
496 | { | |||
497 | if (mClipRegion == region) | |||
498 | return true; | |||
499 | SkiaZone zone; | |||
500 | checkPendingDrawing(); | |||
501 | checkSurface(); | |||
502 | mClipRegion = region; | |||
503 | SAL_INFO("vcl.skia.trace", "setclipregion(" << this << "): " << region)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "setclipregion(" << this << "): " << region) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "503" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "setclipregion(" << this << "): " << region), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "setclipregion(" << this << "): " << region; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "503" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "setclipregion(" << this << "): " << region) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "503" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "setclipregion(" << this << "): " << region), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "setclipregion(" << this << "): " << region; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "503" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
504 | SkCanvas* canvas = mSurface->getCanvas(); | |||
505 | // SkCanvas::clipRegion() can only further reduce the clip region, | |||
506 | // but we need to set the given region, which may extend it. | |||
507 | // So handle that by always having the full clip region saved on the stack | |||
508 | // and always go back to that. SkCanvas::restore() only affects the clip | |||
509 | // and the matrix. | |||
510 | assert(canvas->getSaveCount() == 2)(static_cast <bool> (canvas->getSaveCount() == 2) ? void (0) : __assert_fail ("canvas->getSaveCount() == 2", "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" , 510, __extension__ __PRETTY_FUNCTION__)); // = there is just one save() | |||
511 | canvas->restore(); | |||
512 | canvas->save(); | |||
513 | setCanvasClipRegion(canvas, region); | |||
514 | return true; | |||
515 | } | |||
516 | ||||
517 | void SkiaSalGraphicsImpl::setCanvasClipRegion(SkCanvas* canvas, const vcl::Region& region) | |||
518 | { | |||
519 | SkiaZone zone; | |||
520 | SkPath path; | |||
521 | // Always use region rectangles, regardless of what the region uses internally. | |||
522 | // That's what other VCL backends do, and trying to use addPolyPolygonToPath() | |||
523 | // in case a polygon is used leads to off-by-one errors such as tdf#133208. | |||
524 | RectangleVector rectangles; | |||
525 | region.GetRegionRectangles(rectangles); | |||
526 | for (const tools::Rectangle& rectangle : rectangles) | |||
527 | path.addRect(SkRect::MakeXYWH(rectangle.getX(), rectangle.getY(), rectangle.GetWidth(), | |||
528 | rectangle.GetHeight())); | |||
529 | path.setFillType(SkPathFillType::kEvenOdd); | |||
530 | canvas->clipPath(path); | |||
531 | } | |||
532 | ||||
533 | void SkiaSalGraphicsImpl::ResetClipRegion() | |||
534 | { | |||
535 | setClipRegion(vcl::Region(tools::Rectangle(0, 0, GetWidth(), GetHeight()))); | |||
536 | } | |||
537 | ||||
538 | const vcl::Region& SkiaSalGraphicsImpl::getClipRegion() const { return mClipRegion; } | |||
539 | ||||
540 | sal_uInt16 SkiaSalGraphicsImpl::GetBitCount() const { return 32; } | |||
541 | ||||
542 | long SkiaSalGraphicsImpl::GetGraphicsWidth() const { return GetWidth(); } | |||
543 | ||||
544 | void SkiaSalGraphicsImpl::SetLineColor() | |||
545 | { | |||
546 | checkPendingDrawing(); | |||
547 | mLineColor = SALCOLOR_NONE; | |||
548 | } | |||
549 | ||||
550 | void SkiaSalGraphicsImpl::SetLineColor(Color nColor) | |||
551 | { | |||
552 | checkPendingDrawing(); | |||
553 | mLineColor = nColor; | |||
554 | } | |||
555 | ||||
556 | void SkiaSalGraphicsImpl::SetFillColor() | |||
557 | { | |||
558 | checkPendingDrawing(); | |||
559 | mFillColor = SALCOLOR_NONE; | |||
560 | } | |||
561 | ||||
562 | void SkiaSalGraphicsImpl::SetFillColor(Color nColor) | |||
563 | { | |||
564 | checkPendingDrawing(); | |||
565 | mFillColor = nColor; | |||
566 | } | |||
567 | ||||
568 | void SkiaSalGraphicsImpl::SetXORMode(bool set, bool) | |||
569 | { | |||
570 | if (mXorMode == set) | |||
571 | return; | |||
572 | checkPendingDrawing(); | |||
573 | SAL_INFO("vcl.skia.trace", "setxormode(" << this << "): " << set)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "setxormode(" << this << "): " << set) == 1) { ::sal_detail_log( ( ::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "573" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "setxormode(" << this << "): " << set), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "setxormode(" << this << "): " << set; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "573" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "setxormode(" << this << "): " << set) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO) , ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "573" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "setxormode(" << this << "): " << set), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "setxormode(" << this << "): " << set; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "573" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
574 | if (set) | |||
575 | mXorRegion.setEmpty(); | |||
576 | else | |||
577 | applyXor(); | |||
578 | mXorMode = set; | |||
579 | } | |||
580 | ||||
581 | SkCanvas* SkiaSalGraphicsImpl::getXorCanvas() | |||
582 | { | |||
583 | SkiaZone zone; | |||
584 | assert(mXorMode)(static_cast <bool> (mXorMode) ? void (0) : __assert_fail ("mXorMode", "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" , 584, __extension__ __PRETTY_FUNCTION__)); | |||
585 | // Skia does not implement xor drawing, so we need to handle it manually by redirecting | |||
586 | // to a temporary SkBitmap and then doing the xor operation on the data ourselves. | |||
587 | // There's no point in using SkSurface for GPU, we'd immediately need to get the pixels back. | |||
588 | if (!mXorCanvas) | |||
589 | { | |||
590 | // Use unpremultiplied alpha (see xor applying in applyXor()). | |||
591 | if (!mXorBitmap.tryAllocPixels(mSurface->imageInfo().makeAlphaType(kUnpremul_SkAlphaType))) | |||
592 | abort(); | |||
593 | mXorBitmap.eraseARGB(0, 0, 0, 0); | |||
594 | mXorCanvas = std::make_unique<SkCanvas>(mXorBitmap); | |||
595 | setCanvasClipRegion(mXorCanvas.get(), mClipRegion); | |||
596 | } | |||
597 | return mXorCanvas.get(); | |||
598 | } | |||
599 | ||||
600 | void SkiaSalGraphicsImpl::applyXor() | |||
601 | { | |||
602 | // Apply the result from the temporary bitmap manually. This is indeed | |||
603 | // slow, but it doesn't seem to be needed often and is optimized | |||
604 | // in each operation by extending mXorRegion with the area that should be | |||
605 | // updated. | |||
606 | assert(mXorMode)(static_cast <bool> (mXorMode) ? void (0) : __assert_fail ("mXorMode", "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" , 606, __extension__ __PRETTY_FUNCTION__)); | |||
607 | if (!mSurface || !mXorCanvas | |||
608 | || !mXorRegion.op(SkIRect::MakeXYWH(0, 0, mSurface->width(), mSurface->height()), | |||
609 | SkRegion::kIntersect_Op)) | |||
610 | { | |||
611 | mXorRegion.setEmpty(); | |||
612 | return; | |||
613 | } | |||
614 | SAL_INFO("vcl.skia.trace", "applyxor(" << this << "): " << mXorRegion)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "applyxor(" << this << "): " << mXorRegion) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "614" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "applyxor(" << this << "): " << mXorRegion), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "applyxor(" << this << "): " << mXorRegion; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "614" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "applyxor(" << this << "): " << mXorRegion) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "614" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "applyxor(" << this << "): " << mXorRegion), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "applyxor(" << this << "): " << mXorRegion; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "614" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
615 | // Copy the surface contents to another pixmap. | |||
616 | SkBitmap surfaceBitmap; | |||
617 | // Use unpremultiplied alpha format, so that we do not have to do the conversions to get | |||
618 | // the RGB and back (Skia will do it when converting, but it'll be presumably faster at it). | |||
619 | if (!surfaceBitmap.tryAllocPixels(mSurface->imageInfo().makeAlphaType(kUnpremul_SkAlphaType))) | |||
620 | abort(); | |||
621 | SkPaint paint; | |||
622 | paint.setBlendMode(SkBlendMode::kSrc); // copy as is | |||
623 | SkCanvas canvas(surfaceBitmap); | |||
624 | canvas.drawImageRect(SkiaHelper::makeCheckedImageSnapshot(mSurface), mXorRegion.getBounds(), | |||
625 | SkRect::Make(mXorRegion.getBounds()), &paint); | |||
626 | // xor to surfaceBitmap | |||
627 | assert(surfaceBitmap.info().alphaType() == kUnpremul_SkAlphaType)(static_cast <bool> (surfaceBitmap.info().alphaType() == kUnpremul_SkAlphaType) ? void (0) : __assert_fail ("surfaceBitmap.info().alphaType() == kUnpremul_SkAlphaType" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 627 , __extension__ __PRETTY_FUNCTION__)); | |||
628 | assert(mXorBitmap.info().alphaType() == kUnpremul_SkAlphaType)(static_cast <bool> (mXorBitmap.info().alphaType() == kUnpremul_SkAlphaType ) ? void (0) : __assert_fail ("mXorBitmap.info().alphaType() == kUnpremul_SkAlphaType" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 628 , __extension__ __PRETTY_FUNCTION__)); | |||
629 | assert(surfaceBitmap.bytesPerPixel() == 4)(static_cast <bool> (surfaceBitmap.bytesPerPixel() == 4 ) ? void (0) : __assert_fail ("surfaceBitmap.bytesPerPixel() == 4" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 629 , __extension__ __PRETTY_FUNCTION__)); | |||
630 | assert(mXorBitmap.bytesPerPixel() == 4)(static_cast <bool> (mXorBitmap.bytesPerPixel() == 4) ? void (0) : __assert_fail ("mXorBitmap.bytesPerPixel() == 4", "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 630 , __extension__ __PRETTY_FUNCTION__)); | |||
631 | for (SkRegion::Iterator it(mXorRegion); !it.done(); it.next()) | |||
632 | { | |||
633 | for (int y = it.rect().top(); y < it.rect().bottom(); ++y) | |||
634 | { | |||
635 | uint8_t* data = static_cast<uint8_t*>(surfaceBitmap.getAddr(it.rect().x(), y)); | |||
636 | const uint8_t* xordata = static_cast<uint8_t*>(mXorBitmap.getAddr(it.rect().x(), y)); | |||
637 | for (int x = 0; x < it.rect().width(); ++x) | |||
638 | { | |||
639 | *data++ ^= *xordata++; | |||
640 | *data++ ^= *xordata++; | |||
641 | *data++ ^= *xordata++; | |||
642 | // alpha is not xor-ed | |||
643 | data++; | |||
644 | xordata++; | |||
645 | } | |||
646 | } | |||
647 | } | |||
648 | surfaceBitmap.notifyPixelsChanged(); | |||
649 | mSurface->getCanvas()->drawBitmapRect(surfaceBitmap, mXorRegion.getBounds(), | |||
650 | SkRect::Make(mXorRegion.getBounds()), &paint); | |||
651 | mXorCanvas.reset(); | |||
652 | mXorBitmap.reset(); | |||
653 | mXorRegion.setEmpty(); | |||
654 | } | |||
655 | ||||
656 | void SkiaSalGraphicsImpl::SetROPLineColor(SalROPColor nROPColor) | |||
657 | { | |||
658 | checkPendingDrawing(); | |||
659 | switch (nROPColor) | |||
660 | { | |||
661 | case SalROPColor::N0: | |||
662 | mLineColor = Color(0, 0, 0); | |||
663 | break; | |||
664 | case SalROPColor::N1: | |||
665 | mLineColor = Color(0xff, 0xff, 0xff); | |||
666 | break; | |||
667 | case SalROPColor::Invert: | |||
668 | mLineColor = Color(0xff, 0xff, 0xff); | |||
669 | break; | |||
670 | } | |||
671 | } | |||
672 | ||||
673 | void SkiaSalGraphicsImpl::SetROPFillColor(SalROPColor nROPColor) | |||
674 | { | |||
675 | checkPendingDrawing(); | |||
676 | switch (nROPColor) | |||
677 | { | |||
678 | case SalROPColor::N0: | |||
679 | mFillColor = Color(0, 0, 0); | |||
680 | break; | |||
681 | case SalROPColor::N1: | |||
682 | mFillColor = Color(0xff, 0xff, 0xff); | |||
683 | break; | |||
684 | case SalROPColor::Invert: | |||
685 | mFillColor = Color(0xff, 0xff, 0xff); | |||
686 | break; | |||
687 | } | |||
688 | } | |||
689 | ||||
690 | void SkiaSalGraphicsImpl::drawPixel(long nX, long nY) { drawPixel(nX, nY, mLineColor); } | |||
691 | ||||
692 | void SkiaSalGraphicsImpl::drawPixel(long nX, long nY, Color nColor) | |||
693 | { | |||
694 | if (nColor == SALCOLOR_NONE) | |||
695 | return; | |||
696 | preDraw(); | |||
697 | SAL_INFO("vcl.skia.trace", "drawpixel(" << this << "): " << Point(nX, nY) << ":" << nColor)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "drawpixel(" << this << "): " << Point(nX, nY) << ":" << nColor) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "697" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "drawpixel(" << this << "): " << Point(nX, nY) << ":" << nColor), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawpixel(" << this << "): " << Point(nX, nY) << ":" << nColor; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "697" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "drawpixel(" << this << "): " << Point(nX, nY) << ":" << nColor) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "697" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "drawpixel(" << this << "): " << Point(nX, nY) << ":" << nColor), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawpixel(" << this << "): " << Point(nX, nY) << ":" << nColor; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "697" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
698 | addXorRegion(SkRect::MakeXYWH(nX, nY, 1, 1)); | |||
699 | SkPaint paint; | |||
700 | paint.setColor(toSkColor(nColor)); | |||
701 | // Apparently drawPixel() is actually expected to set the pixel and not draw it. | |||
702 | paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha | |||
703 | getDrawCanvas()->drawPoint(toSkX(nX), toSkY(nY), paint); | |||
704 | postDraw(); | |||
705 | } | |||
706 | ||||
707 | void SkiaSalGraphicsImpl::drawLine(long nX1, long nY1, long nX2, long nY2) | |||
708 | { | |||
709 | if (mLineColor == SALCOLOR_NONE) | |||
710 | return; | |||
711 | preDraw(); | |||
712 | SAL_INFO("vcl.skia.trace", "drawline(" << this << "): " << Point(nX1, nY1) << "->"do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "drawline(" << this << "): " << Point(nX1, nY1) << "->" << Point(nX2, nY2) << ":" << mLineColor) == 1) { :: sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "713" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "drawline(" << this << "): " << Point(nX1, nY1) << "->" << Point(nX2 , nY2) << ":" << mLineColor), 0); } else { ::std:: ostringstream sal_detail_stream; sal_detail_stream << "drawline(" << this << "): " << Point(nX1, nY1) << "->" << Point(nX2, nY2) << ":" << mLineColor ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "713" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "drawline(" << this << "): " << Point(nX1, nY1) << "->" << Point(nX2, nY2) << ":" << mLineColor) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "713" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "drawline(" << this << "): " << Point(nX1, nY1) << "->" << Point(nX2 , nY2) << ":" << mLineColor), 0); } else { ::std:: ostringstream sal_detail_stream; sal_detail_stream << "drawline(" << this << "): " << Point(nX1, nY1) << "->" << Point(nX2, nY2) << ":" << mLineColor ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "713" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
713 | << Point(nX2, nY2) << ":" << mLineColor)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "drawline(" << this << "): " << Point(nX1, nY1) << "->" << Point(nX2, nY2) << ":" << mLineColor) == 1) { :: sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "713" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "drawline(" << this << "): " << Point(nX1, nY1) << "->" << Point(nX2 , nY2) << ":" << mLineColor), 0); } else { ::std:: ostringstream sal_detail_stream; sal_detail_stream << "drawline(" << this << "): " << Point(nX1, nY1) << "->" << Point(nX2, nY2) << ":" << mLineColor ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "713" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "drawline(" << this << "): " << Point(nX1, nY1) << "->" << Point(nX2, nY2) << ":" << mLineColor) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "713" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "drawline(" << this << "): " << Point(nX1, nY1) << "->" << Point(nX2 , nY2) << ":" << mLineColor), 0); } else { ::std:: ostringstream sal_detail_stream; sal_detail_stream << "drawline(" << this << "): " << Point(nX1, nY1) << "->" << Point(nX2, nY2) << ":" << mLineColor ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "713" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
714 | addXorRegion(SkRect::MakeLTRB(nX1, nY1, nX2, nY2).makeSorted()); | |||
715 | SkPaint paint; | |||
716 | paint.setColor(toSkColor(mLineColor)); | |||
717 | paint.setAntiAlias(mParent.getAntiAlias()); | |||
718 | getDrawCanvas()->drawLine(toSkX(nX1), toSkY(nY1), toSkX(nX2), toSkY(nY2), paint); | |||
719 | postDraw(); | |||
720 | } | |||
721 | ||||
722 | void SkiaSalGraphicsImpl::privateDrawAlphaRect(long nX, long nY, long nWidth, long nHeight, | |||
723 | double fTransparency, bool blockAA) | |||
724 | { | |||
725 | preDraw(); | |||
726 | SAL_INFO("vcl.skia.trace",do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "privatedrawrect(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth , nHeight) << ":" << mLineColor << ":" << mFillColor << ":" << fTransparency) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "728" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "privatedrawrect(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth, nHeight) << ":" << mLineColor << ":" << mFillColor << ":" << fTransparency), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "privatedrawrect(" << this << "): " << SkIRect::MakeXYWH(nX, nY , nWidth, nHeight) << ":" << mLineColor << ":" << mFillColor << ":" << fTransparency; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "728" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "privatedrawrect(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth, nHeight) << ":" << mLineColor << ":" << mFillColor << ":" << fTransparency) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "728" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "privatedrawrect(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth, nHeight) << ":" << mLineColor << ":" << mFillColor << ":" << fTransparency), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "privatedrawrect(" << this << "): " << SkIRect::MakeXYWH(nX, nY , nWidth, nHeight) << ":" << mLineColor << ":" << mFillColor << ":" << fTransparency; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "728" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
727 | "privatedrawrect(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth, nHeight)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "privatedrawrect(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth , nHeight) << ":" << mLineColor << ":" << mFillColor << ":" << fTransparency) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "728" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "privatedrawrect(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth, nHeight) << ":" << mLineColor << ":" << mFillColor << ":" << fTransparency), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "privatedrawrect(" << this << "): " << SkIRect::MakeXYWH(nX, nY , nWidth, nHeight) << ":" << mLineColor << ":" << mFillColor << ":" << fTransparency; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "728" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "privatedrawrect(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth, nHeight) << ":" << mLineColor << ":" << mFillColor << ":" << fTransparency) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "728" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "privatedrawrect(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth, nHeight) << ":" << mLineColor << ":" << mFillColor << ":" << fTransparency), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "privatedrawrect(" << this << "): " << SkIRect::MakeXYWH(nX, nY , nWidth, nHeight) << ":" << mLineColor << ":" << mFillColor << ":" << fTransparency; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "728" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
728 | << ":" << mLineColor << ":" << mFillColor << ":" << fTransparency)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "privatedrawrect(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth , nHeight) << ":" << mLineColor << ":" << mFillColor << ":" << fTransparency) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "728" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "privatedrawrect(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth, nHeight) << ":" << mLineColor << ":" << mFillColor << ":" << fTransparency), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "privatedrawrect(" << this << "): " << SkIRect::MakeXYWH(nX, nY , nWidth, nHeight) << ":" << mLineColor << ":" << mFillColor << ":" << fTransparency; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "728" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "privatedrawrect(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth, nHeight) << ":" << mLineColor << ":" << mFillColor << ":" << fTransparency) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "728" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "privatedrawrect(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth, nHeight) << ":" << mLineColor << ":" << mFillColor << ":" << fTransparency), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "privatedrawrect(" << this << "): " << SkIRect::MakeXYWH(nX, nY , nWidth, nHeight) << ":" << mLineColor << ":" << mFillColor << ":" << fTransparency; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "728" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
729 | addXorRegion(SkRect::MakeXYWH(nX, nY, nWidth, nHeight)); | |||
730 | SkCanvas* canvas = getDrawCanvas(); | |||
731 | SkPaint paint; | |||
732 | paint.setAntiAlias(!blockAA && mParent.getAntiAlias()); | |||
733 | if (mFillColor != SALCOLOR_NONE) | |||
734 | { | |||
735 | paint.setColor(toSkColorWithTransparency(mFillColor, fTransparency)); | |||
736 | paint.setStyle(SkPaint::kFill_Style); | |||
737 | // HACK: If the polygon is just a line, it still should be drawn. But when filling | |||
738 | // Skia doesn't draw empty polygons, so in that case ensure the line is drawn. | |||
739 | if (mLineColor == SALCOLOR_NONE && SkSize::Make(nWidth, nHeight).isEmpty()) | |||
740 | paint.setStyle(SkPaint::kStroke_Style); | |||
741 | canvas->drawIRect(SkIRect::MakeXYWH(nX, nY, nWidth, nHeight), paint); | |||
742 | } | |||
743 | if (mLineColor != SALCOLOR_NONE) | |||
744 | { | |||
745 | paint.setColor(toSkColorWithTransparency(mLineColor, fTransparency)); | |||
746 | paint.setStyle(SkPaint::kStroke_Style); | |||
747 | // The obnoxious "-1 DrawRect()" hack that I don't understand the purpose of (and I'm not sure | |||
748 | // if anybody does), but without it some cases do not work. The max() is needed because Skia | |||
749 | // will not draw anything if width or height is 0. | |||
750 | canvas->drawIRect( | |||
751 | SkIRect::MakeXYWH(nX, nY, std::max(1L, nWidth - 1), std::max(1L, nHeight - 1)), paint); | |||
752 | } | |||
753 | postDraw(); | |||
754 | } | |||
755 | ||||
756 | void SkiaSalGraphicsImpl::drawRect(long nX, long nY, long nWidth, long nHeight) | |||
757 | { | |||
758 | privateDrawAlphaRect(nX, nY, nWidth, nHeight, 0.0, true); | |||
759 | } | |||
760 | ||||
761 | void SkiaSalGraphicsImpl::drawPolyLine(sal_uInt32 nPoints, const SalPoint* pPtAry) | |||
762 | { | |||
763 | basegfx::B2DPolygon aPolygon; | |||
764 | aPolygon.append(basegfx::B2DPoint(pPtAry->mnX, pPtAry->mnY), nPoints); | |||
765 | for (sal_uInt32 i = 1; i < nPoints; ++i) | |||
766 | aPolygon.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].mnX, pPtAry[i].mnY)); | |||
767 | aPolygon.setClosed(false); | |||
768 | ||||
769 | drawPolyLine(basegfx::B2DHomMatrix(), aPolygon, 0.0, 1.0, nullptr, basegfx::B2DLineJoin::Miter, | |||
770 | css::drawing::LineCap_BUTT, basegfx::deg2rad(15.0) /*default*/, false); | |||
771 | } | |||
772 | ||||
773 | void SkiaSalGraphicsImpl::drawPolygon(sal_uInt32 nPoints, const SalPoint* pPtAry) | |||
774 | { | |||
775 | basegfx::B2DPolygon aPolygon; | |||
776 | aPolygon.append(basegfx::B2DPoint(pPtAry->mnX, pPtAry->mnY), nPoints); | |||
777 | for (sal_uInt32 i = 1; i < nPoints; ++i) | |||
778 | aPolygon.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].mnX, pPtAry[i].mnY)); | |||
779 | ||||
780 | drawPolyPolygon(basegfx::B2DHomMatrix(), basegfx::B2DPolyPolygon(aPolygon), 0.0); | |||
781 | } | |||
782 | ||||
783 | void SkiaSalGraphicsImpl::drawPolyPolygon(sal_uInt32 nPoly, const sal_uInt32* pPoints, | |||
784 | PCONSTSALPOINT* pPtAry) | |||
785 | { | |||
786 | basegfx::B2DPolyPolygon aPolyPolygon; | |||
787 | for (sal_uInt32 nPolygon = 0; nPolygon < nPoly; ++nPolygon) | |||
| ||||
788 | { | |||
789 | sal_uInt32 nPoints = pPoints[nPolygon]; | |||
790 | if (nPoints) | |||
791 | { | |||
792 | PCONSTSALPOINT pSalPoints = pPtAry[nPolygon]; | |||
793 | basegfx::B2DPolygon aPolygon; | |||
794 | aPolygon.append(basegfx::B2DPoint(pSalPoints->mnX, pSalPoints->mnY), nPoints); | |||
795 | for (sal_uInt32 i = 1; i < nPoints; ++i) | |||
796 | aPolygon.setB2DPoint(i, basegfx::B2DPoint(pSalPoints[i].mnX, pSalPoints[i].mnY)); | |||
797 | ||||
798 | aPolyPolygon.append(aPolygon); | |||
799 | } | |||
800 | } | |||
801 | ||||
802 | drawPolyPolygon(basegfx::B2DHomMatrix(), aPolyPolygon, 0.0); | |||
803 | } | |||
804 | ||||
805 | bool SkiaSalGraphicsImpl::drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice, | |||
806 | const basegfx::B2DPolyPolygon& rPolyPolygon, | |||
807 | double fTransparency) | |||
808 | { | |||
809 | const bool bHasFill(mFillColor != SALCOLOR_NONE); | |||
810 | const bool bHasLine(mLineColor != SALCOLOR_NONE); | |||
811 | ||||
812 | if (rPolyPolygon.count() == 0 || !(bHasFill
| |||
813 | || fTransparency >= 1.0) | |||
814 | return true; | |||
815 | ||||
816 | basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon); | |||
817 | aPolyPolygon.transform(rObjectToDevice); | |||
818 | ||||
819 | SAL_INFO("vcl.skia.trace", "drawpolypolygon(" << this << "): " << aPolyPolygon << ":"do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "drawpolypolygon(" << this << "): " << aPolyPolygon << ":" << mLineColor << ":" << mFillColor) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "820" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "drawpolypolygon(" << this << "): " << aPolyPolygon << ":" << mLineColor << ":" << mFillColor), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawpolypolygon(" << this << "): " << aPolyPolygon << ":" << mLineColor << ":" << mFillColor; ::sal:: detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "820" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "drawpolypolygon(" << this << "): " << aPolyPolygon << ":" << mLineColor << ":" << mFillColor) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "820" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "drawpolypolygon(" << this << "): " << aPolyPolygon << ":" << mLineColor << ":" << mFillColor), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawpolypolygon(" << this << "): " << aPolyPolygon << ":" << mLineColor << ":" << mFillColor; ::sal:: detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "820" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
820 | << mLineColor << ":" << mFillColor)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "drawpolypolygon(" << this << "): " << aPolyPolygon << ":" << mLineColor << ":" << mFillColor) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "820" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "drawpolypolygon(" << this << "): " << aPolyPolygon << ":" << mLineColor << ":" << mFillColor), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawpolypolygon(" << this << "): " << aPolyPolygon << ":" << mLineColor << ":" << mFillColor; ::sal:: detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "820" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "drawpolypolygon(" << this << "): " << aPolyPolygon << ":" << mLineColor << ":" << mFillColor) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "820" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "drawpolypolygon(" << this << "): " << aPolyPolygon << ":" << mLineColor << ":" << mFillColor), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawpolypolygon(" << this << "): " << aPolyPolygon << ":" << mLineColor << ":" << mFillColor; ::sal:: detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "820" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
821 | ||||
822 | if (delayDrawPolyPolygon(aPolyPolygon, fTransparency)) | |||
823 | { | |||
824 | scheduleFlush(); | |||
825 | return true; | |||
826 | } | |||
827 | ||||
828 | performDrawPolyPolygon(aPolyPolygon, fTransparency, mParent.getAntiAlias()); | |||
829 | return true; | |||
830 | } | |||
831 | ||||
832 | void SkiaSalGraphicsImpl::performDrawPolyPolygon(const basegfx::B2DPolyPolygon& aPolyPolygon, | |||
833 | double fTransparency, bool useAA) | |||
834 | { | |||
835 | preDraw(); | |||
836 | ||||
837 | SkPath polygonPath; | |||
838 | addPolyPolygonToPath(aPolyPolygon, polygonPath); | |||
839 | polygonPath.setFillType(SkPathFillType::kEvenOdd); | |||
840 | addXorRegion(polygonPath.getBounds()); | |||
841 | ||||
842 | SkPaint aPaint; | |||
843 | aPaint.setAntiAlias(useAA); | |||
844 | // We normally use pixel at their center positions, but slightly off (see toSkX/Y()). | |||
845 | // With AA lines that "slightly off" causes tiny changes of color, making some tests | |||
846 | // fail. Since moving AA-ed line slightly to a side doesn't cause any real visual | |||
847 | // difference, just place exactly at the center. tdf#134346 | |||
848 | const SkScalar posFix = useAA ? toSkXYFix : 0; | |||
849 | if (mFillColor != SALCOLOR_NONE) | |||
850 | { | |||
851 | SkPath path; | |||
852 | polygonPath.offset(toSkX(0) + posFix, toSkY(0) + posFix, &path); | |||
853 | aPaint.setColor(toSkColorWithTransparency(mFillColor, fTransparency)); | |||
854 | aPaint.setStyle(SkPaint::kFill_Style); | |||
855 | // HACK: If the polygon is just a line, it still should be drawn. But when filling | |||
856 | // Skia doesn't draw empty polygons, so in that case ensure the line is drawn. | |||
857 | if (mLineColor == SALCOLOR_NONE && path.getBounds().isEmpty()) | |||
858 | aPaint.setStyle(SkPaint::kStroke_Style); | |||
859 | getDrawCanvas()->drawPath(path, aPaint); | |||
860 | } | |||
861 | if (mLineColor != SALCOLOR_NONE) | |||
862 | { | |||
863 | SkPath path; | |||
864 | polygonPath.offset(toSkX(0) + posFix, toSkY(0) + posFix, &path); | |||
865 | aPaint.setColor(toSkColorWithTransparency(mLineColor, fTransparency)); | |||
866 | aPaint.setStyle(SkPaint::kStroke_Style); | |||
867 | getDrawCanvas()->drawPath(path, aPaint); | |||
868 | } | |||
869 | postDraw(); | |||
870 | #if defined LINUX1 | |||
871 | // WORKAROUND: The logo in the about dialog has drawing errors. This seems to happen | |||
872 | // only on Linux (not Windows on the same machine), with both AMDGPU and Mesa, | |||
873 | // and only when antialiasing is enabled. Flushing seems to avoid the problem. | |||
874 | if (useAA && SkiaHelper::getVendor() == DriverBlocklist::VendorAMD) | |||
875 | mSurface->flushAndSubmit(); | |||
876 | #endif | |||
877 | } | |||
878 | ||||
879 | namespace | |||
880 | { | |||
881 | struct LessThan | |||
882 | { | |||
883 | bool operator()(const basegfx::B2DPoint& point1, const basegfx::B2DPoint& point2) const | |||
884 | { | |||
885 | if (basegfx::fTools::equal(point1.getX(), point2.getX())) | |||
886 | return basegfx::fTools::less(point1.getY(), point2.getY()); | |||
887 | return basegfx::fTools::less(point1.getX(), point2.getX()); | |||
888 | } | |||
889 | }; | |||
890 | } // namespace | |||
891 | ||||
892 | bool SkiaSalGraphicsImpl::delayDrawPolyPolygon(const basegfx::B2DPolyPolygon& aPolyPolygon, | |||
893 | double fTransparency) | |||
894 | { | |||
895 | // There is some code that needlessly subdivides areas into adjacent rectangles, | |||
896 | // but Skia doesn't line them up perfectly if AA is enabled (e.g. Cairo, Qt5 do, | |||
897 | // but Skia devs claim it's working as intended | |||
898 | // https://groups.google.com/d/msg/skia-discuss/NlKpD2X_5uc/Vuwd-kyYBwAJ). | |||
899 | // An example is tdf#133016, which triggers SvgStyleAttributes::add_stroke() | |||
900 | // implementing a line stroke as a bunch of polygons instead of just one, and | |||
901 | // SvgLinearAtomPrimitive2D::create2DDecomposition() creates a gradient | |||
902 | // as a series of polygons of gradually changing color. Those places should be | |||
903 | // changed, but try to merge those split polygons back into the original one, | |||
904 | // where the needlessly created edges causing problems will not exist. | |||
905 | // This means drawing of such polygons needs to be delayed, so that they can | |||
906 | // be possibly merged with the next one. | |||
907 | // Merge only polygons of the same properties (color, etc.), so the gradient problem | |||
908 | // actually isn't handled here. | |||
909 | ||||
910 | // Only AA polygons need merging, because they do not line up well because of the AA of the edges. | |||
911 | if (!mParent.getAntiAlias()) | |||
912 | return false; | |||
913 | // Only filled polygons without an outline are problematic. | |||
914 | if (mFillColor == SALCOLOR_NONE || mLineColor != SALCOLOR_NONE) | |||
915 | return false; | |||
916 | // Merge only simple polygons, real polypolygons most likely aren't needlessly split, | |||
917 | // so they do not need joining. | |||
918 | if (aPolyPolygon.count() != 1) | |||
919 | return false; | |||
920 | // If the polygon is not closed, it doesn't mark an area to be filled. | |||
921 | if (!aPolyPolygon.isClosed()) | |||
922 | return false; | |||
923 | // If a polygon does not contain a straight line, i.e. it's all curves, then do not merge. | |||
924 | // First of all that's even more expensive, and second it's very unlikely that it's a polygon | |||
925 | // split into more polygons. | |||
926 | if (!polygonContainsLine(aPolyPolygon)) | |||
927 | return false; | |||
928 | ||||
929 | if (mLastPolyPolygonInfo.polygons.size() != 0 | |||
930 | && (mLastPolyPolygonInfo.transparency != fTransparency | |||
931 | || !mLastPolyPolygonInfo.bounds.overlaps(aPolyPolygon.getB2DRange()))) | |||
932 | { | |||
933 | checkPendingDrawing(); // Cannot be parts of the same larger polygon, draw the last and reset. | |||
934 | } | |||
935 | if (!mLastPolyPolygonInfo.polygons.empty()) | |||
936 | { | |||
937 | assert(aPolyPolygon.count() == 1)(static_cast <bool> (aPolyPolygon.count() == 1) ? void ( 0) : __assert_fail ("aPolyPolygon.count() == 1", "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" , 937, __extension__ __PRETTY_FUNCTION__)); | |||
938 | assert(mLastPolyPolygonInfo.polygons.back().count() == 1)(static_cast <bool> (mLastPolyPolygonInfo.polygons.back ().count() == 1) ? void (0) : __assert_fail ("mLastPolyPolygonInfo.polygons.back().count() == 1" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 938 , __extension__ __PRETTY_FUNCTION__)); | |||
939 | // Check if the new and the previous polygon share at least one point. If not, then they | |||
940 | // cannot be adjacent polygons, so there's no point in trying to merge them. | |||
941 | bool sharePoint = false; | |||
942 | const basegfx::B2DPolygon& poly1 = aPolyPolygon.getB2DPolygon(0); | |||
943 | const basegfx::B2DPolygon& poly2 = mLastPolyPolygonInfo.polygons.back().getB2DPolygon(0); | |||
944 | o3tl::sorted_vector<basegfx::B2DPoint, LessThan> poly1Points; // for O(n log n) | |||
945 | poly1Points.reserve(poly1.count()); | |||
946 | for (sal_uInt32 i = 0; i < poly1.count(); ++i) | |||
947 | poly1Points.insert(poly1.getB2DPoint(i)); | |||
948 | for (sal_uInt32 i = 0; i < poly2.count(); ++i) | |||
949 | if (poly1Points.find(poly2.getB2DPoint(i)) != poly1Points.end()) | |||
950 | { | |||
951 | sharePoint = true; | |||
952 | break; | |||
953 | } | |||
954 | if (!sharePoint) | |||
955 | checkPendingDrawing(); // Draw the previous one and reset. | |||
956 | } | |||
957 | // Collect the polygons that can be possibly merged. Do the merging only once at the end, | |||
958 | // because it's not a cheap operation. | |||
959 | mLastPolyPolygonInfo.polygons.push_back(aPolyPolygon); | |||
960 | mLastPolyPolygonInfo.bounds.expand(aPolyPolygon.getB2DRange()); | |||
961 | mLastPolyPolygonInfo.transparency = fTransparency; | |||
962 | return true; | |||
963 | } | |||
964 | ||||
965 | void SkiaSalGraphicsImpl::checkPendingDrawing() | |||
966 | { | |||
967 | if (mLastPolyPolygonInfo.polygons.size() != 0) | |||
968 | { // Flush any pending polygon drawing. | |||
969 | basegfx::B2DPolyPolygonVector polygons; | |||
970 | std::swap(polygons, mLastPolyPolygonInfo.polygons); | |||
971 | double transparency = mLastPolyPolygonInfo.transparency; | |||
972 | mLastPolyPolygonInfo.bounds.reset(); | |||
973 | if (polygons.size() == 1) | |||
974 | performDrawPolyPolygon(polygons.front(), transparency, true); | |||
975 | else | |||
976 | // TODO: tdf#136222 shows that basegfx::utils::mergeToSinglePolyPolygon() is unreliable | |||
977 | // in corner cases, possibly either a bug or rounding errors somewhere. | |||
978 | performDrawPolyPolygon(basegfx::utils::mergeToSinglePolyPolygon(polygons), transparency, | |||
979 | true); | |||
980 | } | |||
981 | } | |||
982 | ||||
983 | bool SkiaSalGraphicsImpl::drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice, | |||
984 | const basegfx::B2DPolygon& rPolyLine, double fTransparency, | |||
985 | double fLineWidth, const std::vector<double>* pStroke, | |||
986 | basegfx::B2DLineJoin eLineJoin, | |||
987 | css::drawing::LineCap eLineCap, double fMiterMinimumAngle, | |||
988 | bool bPixelSnapHairline) | |||
989 | { | |||
990 | if (!rPolyLine.count() || fTransparency < 0.0 || fTransparency > 1.0 | |||
991 | || mLineColor == SALCOLOR_NONE) | |||
992 | { | |||
993 | return true; | |||
994 | } | |||
995 | ||||
996 | preDraw(); | |||
997 | SAL_INFO("vcl.skia.trace", "drawpolyline(" << this << "): " << rPolyLine << ":" << mLineColor)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "drawpolyline(" << this << "): " << rPolyLine << ":" << mLineColor) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "997" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "drawpolyline(" << this << "): " << rPolyLine << ":" << mLineColor), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawpolyline(" << this << "): " << rPolyLine << ":" << mLineColor; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "997" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "drawpolyline(" << this << "): " << rPolyLine << ":" << mLineColor) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "997" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "drawpolyline(" << this << "): " << rPolyLine << ":" << mLineColor), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawpolyline(" << this << "): " << rPolyLine << ":" << mLineColor; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "997" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
998 | ||||
999 | // tdf#124848 get correct LineWidth in discrete coordinates, | |||
1000 | if (fLineWidth == 0) // hairline | |||
1001 | fLineWidth = 1.0; | |||
1002 | else // Adjust line width for object-to-device scale. | |||
1003 | fLineWidth = (rObjectToDevice * basegfx::B2DVector(fLineWidth, 0)).getLength(); | |||
1004 | ||||
1005 | // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline | |||
1006 | basegfx::B2DPolyPolygon aPolyPolygonLine; | |||
1007 | aPolyPolygonLine.append(rPolyLine); | |||
1008 | aPolyPolygonLine.transform(rObjectToDevice); | |||
1009 | if (bPixelSnapHairline) | |||
1010 | { | |||
1011 | aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine); | |||
1012 | } | |||
1013 | ||||
1014 | // Setup Line Join | |||
1015 | SkPaint::Join eSkLineJoin = SkPaint::kMiter_Join; | |||
1016 | switch (eLineJoin) | |||
1017 | { | |||
1018 | case basegfx::B2DLineJoin::Bevel: | |||
1019 | eSkLineJoin = SkPaint::kBevel_Join; | |||
1020 | break; | |||
1021 | case basegfx::B2DLineJoin::Round: | |||
1022 | eSkLineJoin = SkPaint::kRound_Join; | |||
1023 | break; | |||
1024 | case basegfx::B2DLineJoin::NONE: | |||
1025 | case basegfx::B2DLineJoin::Miter: | |||
1026 | eSkLineJoin = SkPaint::kMiter_Join; | |||
1027 | break; | |||
1028 | } | |||
1029 | ||||
1030 | // convert miter minimum angle to miter limit | |||
1031 | double fMiterLimit = 1.0 / std::sin(fMiterMinimumAngle / 2.0); | |||
1032 | ||||
1033 | // Setup Line Cap | |||
1034 | SkPaint::Cap eSkLineCap(SkPaint::kButt_Cap); | |||
1035 | ||||
1036 | switch (eLineCap) | |||
1037 | { | |||
1038 | case css::drawing::LineCap_ROUND: | |||
1039 | eSkLineCap = SkPaint::kRound_Cap; | |||
1040 | break; | |||
1041 | case css::drawing::LineCap_SQUARE: | |||
1042 | eSkLineCap = SkPaint::kSquare_Cap; | |||
1043 | break; | |||
1044 | default: // css::drawing::LineCap_BUTT: | |||
1045 | eSkLineCap = SkPaint::kButt_Cap; | |||
1046 | break; | |||
1047 | } | |||
1048 | ||||
1049 | SkPaint aPaint; | |||
1050 | aPaint.setStyle(SkPaint::kStroke_Style); | |||
1051 | aPaint.setStrokeCap(eSkLineCap); | |||
1052 | aPaint.setStrokeJoin(eSkLineJoin); | |||
1053 | aPaint.setColor(toSkColorWithTransparency(mLineColor, fTransparency)); | |||
1054 | aPaint.setStrokeMiter(fMiterLimit); | |||
1055 | aPaint.setStrokeWidth(fLineWidth); | |||
1056 | aPaint.setAntiAlias(mParent.getAntiAlias()); | |||
1057 | // See the tdf#134346 comment above. | |||
1058 | const SkScalar posFix = mParent.getAntiAlias() ? toSkXYFix : 0; | |||
1059 | ||||
1060 | if (pStroke && std::accumulate(pStroke->begin(), pStroke->end(), 0.0) != 0) | |||
1061 | { | |||
1062 | std::vector<SkScalar> intervals; | |||
1063 | // Transform size by the matrix. | |||
1064 | for (double stroke : *pStroke) | |||
1065 | intervals.push_back((rObjectToDevice * basegfx::B2DVector(stroke, 0)).getLength()); | |||
1066 | aPaint.setPathEffect(SkDashPathEffect::Make(intervals.data(), intervals.size(), 0)); | |||
1067 | } | |||
1068 | ||||
1069 | // Skia does not support basegfx::B2DLineJoin::NONE, so in that case batch only if lines | |||
1070 | // are not wider than a pixel. | |||
1071 | if (eLineJoin != basegfx::B2DLineJoin::NONE || fLineWidth <= 1.0) | |||
1072 | { | |||
1073 | SkPath aPath; | |||
1074 | aPath.setFillType(SkPathFillType::kEvenOdd); | |||
1075 | for (sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++) | |||
1076 | addPolygonToPath(aPolyPolygonLine.getB2DPolygon(a), aPath); | |||
1077 | aPath.offset(toSkX(0) + posFix, toSkY(0) + posFix, nullptr); | |||
1078 | addXorRegion(aPath.getBounds()); | |||
1079 | getDrawCanvas()->drawPath(aPath, aPaint); | |||
1080 | } | |||
1081 | else | |||
1082 | { | |||
1083 | for (sal_uInt32 i = 0; i < aPolyPolygonLine.count(); ++i) | |||
1084 | { | |||
1085 | const basegfx::B2DPolygon& rPolygon = aPolyPolygonLine.getB2DPolygon(i); | |||
1086 | sal_uInt32 nPoints = rPolygon.count(); | |||
1087 | bool bClosed = rPolygon.isClosed(); | |||
1088 | for (sal_uInt32 j = 0; j < (bClosed ? nPoints : nPoints - 1); ++j) | |||
1089 | { | |||
1090 | sal_uInt32 index1 = (j + 0) % nPoints; | |||
1091 | sal_uInt32 index2 = (j + 1) % nPoints; | |||
1092 | SkPath aPath; | |||
1093 | aPath.moveTo(rPolygon.getB2DPoint(index1).getX(), | |||
1094 | rPolygon.getB2DPoint(index1).getY()); | |||
1095 | aPath.lineTo(rPolygon.getB2DPoint(index2).getX(), | |||
1096 | rPolygon.getB2DPoint(index2).getY()); | |||
1097 | ||||
1098 | aPath.offset(toSkX(0) + posFix, toSkY(0) + posFix, nullptr); | |||
1099 | addXorRegion(aPath.getBounds()); | |||
1100 | getDrawCanvas()->drawPath(aPath, aPaint); | |||
1101 | } | |||
1102 | } | |||
1103 | } | |||
1104 | ||||
1105 | postDraw(); | |||
1106 | ||||
1107 | return true; | |||
1108 | } | |||
1109 | ||||
1110 | bool SkiaSalGraphicsImpl::drawPolyLineBezier(sal_uInt32, const SalPoint*, const PolyFlags*) | |||
1111 | { | |||
1112 | return false; | |||
1113 | } | |||
1114 | ||||
1115 | bool SkiaSalGraphicsImpl::drawPolygonBezier(sal_uInt32, const SalPoint*, const PolyFlags*) | |||
1116 | { | |||
1117 | return false; | |||
1118 | } | |||
1119 | ||||
1120 | bool SkiaSalGraphicsImpl::drawPolyPolygonBezier(sal_uInt32, const sal_uInt32*, | |||
1121 | const SalPoint* const*, const PolyFlags* const*) | |||
1122 | { | |||
1123 | return false; | |||
1124 | } | |||
1125 | ||||
1126 | static void copyArea(SkCanvas* canvas, sk_sp<SkSurface> surface, long nDestX, long nDestY, | |||
1127 | long nSrcX, long nSrcY, long nSrcWidth, long nSrcHeight, bool srcIsRaster, | |||
1128 | bool destIsRaster) | |||
1129 | { | |||
1130 | // Using SkSurface::draw() should be more efficient than SkSurface::makeImageSnapshot(), | |||
1131 | // because it may detect copying to itself and avoid some needless copies. | |||
1132 | // But it has problems with drawing to itself | |||
1133 | // (https://groups.google.com/forum/#!topic/skia-discuss/6yiuw24jv0I) and also | |||
1134 | // raster surfaces do not avoid a copy of the source | |||
1135 | // (https://groups.google.com/forum/#!topic/skia-discuss/S3FMpCi82k0). | |||
1136 | // Finally, there's not much point if one of them is raster and the other is not (chrome/m86 even crashes). | |||
1137 | if (canvas == surface->getCanvas() || srcIsRaster || (srcIsRaster != destIsRaster)) | |||
1138 | { | |||
1139 | SkPaint paint; | |||
1140 | paint.setBlendMode(SkBlendMode::kSrc); // copy as is, including alpha | |||
1141 | canvas->drawImageRect(SkiaHelper::makeCheckedImageSnapshot(surface), | |||
1142 | SkIRect::MakeXYWH(nSrcX, nSrcY, nSrcWidth, nSrcHeight), | |||
1143 | SkRect::MakeXYWH(nDestX, nDestY, nSrcWidth, nSrcHeight), &paint); | |||
1144 | return; | |||
1145 | } | |||
1146 | // SkCanvas::draw() cannot do a subrectangle, so clip. | |||
1147 | canvas->save(); | |||
1148 | canvas->clipRect(SkRect::MakeXYWH(nDestX, nDestY, nSrcWidth, nSrcHeight)); | |||
1149 | SkPaint paint; | |||
1150 | paint.setBlendMode(SkBlendMode::kSrc); // copy as is, including alpha | |||
1151 | surface->draw(canvas, nDestX - nSrcX, nDestY - nSrcY, &paint); | |||
1152 | canvas->restore(); | |||
1153 | } | |||
1154 | ||||
1155 | void SkiaSalGraphicsImpl::copyArea(long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth, | |||
1156 | long nSrcHeight, bool /*bWindowInvalidate*/) | |||
1157 | { | |||
1158 | if (nDestX == nSrcX && nDestY == nSrcY) | |||
1159 | return; | |||
1160 | preDraw(); | |||
1161 | SAL_INFO("vcl.skia.trace", "copyarea("do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "copyarea(" << this << "): " << Point(nSrcX, nSrcY) << "->" << SkIRect::MakeXYWH(nDestX, nDestY, nSrcWidth, nSrcHeight )) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ( "vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1163" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "copyarea(" << this << "): " << Point(nSrcX, nSrcY) << "->" << SkIRect ::MakeXYWH(nDestX, nDestY, nSrcWidth, nSrcHeight)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "copyarea(" << this << "): " << Point(nSrcX , nSrcY) << "->" << SkIRect::MakeXYWH(nDestX, nDestY , nSrcWidth, nSrcHeight); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1163" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "copyarea(" << this << "): " << Point(nSrcX, nSrcY) << "->" << SkIRect::MakeXYWH (nDestX, nDestY, nSrcWidth, nSrcHeight)) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1163" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "copyarea(" << this << "): " << Point(nSrcX, nSrcY) << "->" << SkIRect ::MakeXYWH(nDestX, nDestY, nSrcWidth, nSrcHeight)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "copyarea(" << this << "): " << Point(nSrcX , nSrcY) << "->" << SkIRect::MakeXYWH(nDestX, nDestY , nSrcWidth, nSrcHeight); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1163" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
1162 | << this << "): " << Point(nSrcX, nSrcY) << "->"do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "copyarea(" << this << "): " << Point(nSrcX, nSrcY) << "->" << SkIRect::MakeXYWH(nDestX, nDestY, nSrcWidth, nSrcHeight )) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ( "vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1163" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "copyarea(" << this << "): " << Point(nSrcX, nSrcY) << "->" << SkIRect ::MakeXYWH(nDestX, nDestY, nSrcWidth, nSrcHeight)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "copyarea(" << this << "): " << Point(nSrcX , nSrcY) << "->" << SkIRect::MakeXYWH(nDestX, nDestY , nSrcWidth, nSrcHeight); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1163" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "copyarea(" << this << "): " << Point(nSrcX, nSrcY) << "->" << SkIRect::MakeXYWH (nDestX, nDestY, nSrcWidth, nSrcHeight)) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1163" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "copyarea(" << this << "): " << Point(nSrcX, nSrcY) << "->" << SkIRect ::MakeXYWH(nDestX, nDestY, nSrcWidth, nSrcHeight)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "copyarea(" << this << "): " << Point(nSrcX , nSrcY) << "->" << SkIRect::MakeXYWH(nDestX, nDestY , nSrcWidth, nSrcHeight); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1163" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
1163 | << SkIRect::MakeXYWH(nDestX, nDestY, nSrcWidth, nSrcHeight))do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "copyarea(" << this << "): " << Point(nSrcX, nSrcY) << "->" << SkIRect::MakeXYWH(nDestX, nDestY, nSrcWidth, nSrcHeight )) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ( "vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1163" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "copyarea(" << this << "): " << Point(nSrcX, nSrcY) << "->" << SkIRect ::MakeXYWH(nDestX, nDestY, nSrcWidth, nSrcHeight)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "copyarea(" << this << "): " << Point(nSrcX , nSrcY) << "->" << SkIRect::MakeXYWH(nDestX, nDestY , nSrcWidth, nSrcHeight); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1163" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "copyarea(" << this << "): " << Point(nSrcX, nSrcY) << "->" << SkIRect::MakeXYWH (nDestX, nDestY, nSrcWidth, nSrcHeight)) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1163" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "copyarea(" << this << "): " << Point(nSrcX, nSrcY) << "->" << SkIRect ::MakeXYWH(nDestX, nDestY, nSrcWidth, nSrcHeight)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "copyarea(" << this << "): " << Point(nSrcX , nSrcY) << "->" << SkIRect::MakeXYWH(nDestX, nDestY , nSrcWidth, nSrcHeight); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1163" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1164 | assert(!mXorMode)(static_cast <bool> (!mXorMode) ? void (0) : __assert_fail ("!mXorMode", "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" , 1164, __extension__ __PRETTY_FUNCTION__)); | |||
1165 | ::copyArea(getDrawCanvas(), mSurface, nDestX, nDestY, nSrcX, nSrcY, nSrcWidth, nSrcHeight, | |||
1166 | !isGPU(), !isGPU()); | |||
1167 | postDraw(); | |||
1168 | } | |||
1169 | ||||
1170 | void SkiaSalGraphicsImpl::copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics) | |||
1171 | { | |||
1172 | preDraw(); | |||
1173 | SkiaSalGraphicsImpl* src; | |||
1174 | if (pSrcGraphics) | |||
1175 | { | |||
1176 | assert(dynamic_cast<SkiaSalGraphicsImpl*>(pSrcGraphics->GetImpl()))(static_cast <bool> (dynamic_cast<SkiaSalGraphicsImpl *>(pSrcGraphics->GetImpl())) ? void (0) : __assert_fail ("dynamic_cast<SkiaSalGraphicsImpl*>(pSrcGraphics->GetImpl())" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 1176 , __extension__ __PRETTY_FUNCTION__)); | |||
1177 | src = static_cast<SkiaSalGraphicsImpl*>(pSrcGraphics->GetImpl()); | |||
1178 | src->checkSurface(); | |||
1179 | src->flushDrawing(); | |||
1180 | } | |||
1181 | else | |||
1182 | { | |||
1183 | src = this; | |||
1184 | assert(!mXorMode)(static_cast <bool> (!mXorMode) ? void (0) : __assert_fail ("!mXorMode", "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" , 1184, __extension__ __PRETTY_FUNCTION__)); | |||
1185 | } | |||
1186 | if (rPosAry.mnSrcWidth == rPosAry.mnDestWidth && rPosAry.mnSrcHeight == rPosAry.mnDestHeight) | |||
1187 | { | |||
1188 | auto srcDebug = [&]() -> std::string { | |||
1189 | if (src == this) | |||
1190 | return "(self)"; | |||
1191 | else | |||
1192 | { | |||
1193 | std::ostringstream stream; | |||
1194 | stream << "(" << src << ")"; | |||
1195 | return stream.str(); | |||
1196 | } | |||
1197 | }; | |||
1198 | SAL_INFO("vcl.skia.trace",do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "copybits(" << this << "): " << srcDebug() << " copy area: " << rPosAry) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1199" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "copybits(" << this << "): " << srcDebug() << " copy area: " << rPosAry ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "copybits(" << this << "): " << srcDebug () << " copy area: " << rPosAry; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1199" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "copybits(" << this << "): " << srcDebug() << " copy area: " << rPosAry) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1199" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "copybits(" << this << "): " << srcDebug() << " copy area: " << rPosAry ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "copybits(" << this << "): " << srcDebug () << " copy area: " << rPosAry; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1199" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
1199 | "copybits(" << this << "): " << srcDebug() << " copy area: " << rPosAry)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "copybits(" << this << "): " << srcDebug() << " copy area: " << rPosAry) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1199" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "copybits(" << this << "): " << srcDebug() << " copy area: " << rPosAry ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "copybits(" << this << "): " << srcDebug () << " copy area: " << rPosAry; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1199" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "copybits(" << this << "): " << srcDebug() << " copy area: " << rPosAry) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1199" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "copybits(" << this << "): " << srcDebug() << " copy area: " << rPosAry ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "copybits(" << this << "): " << srcDebug () << " copy area: " << rPosAry; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1199" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1200 | ::copyArea(getDrawCanvas(), src->mSurface, rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnSrcX, | |||
1201 | rPosAry.mnSrcY, rPosAry.mnDestWidth, rPosAry.mnDestHeight, !src->isGPU(), | |||
1202 | !isGPU()); | |||
1203 | } | |||
1204 | else | |||
1205 | { | |||
1206 | SAL_INFO("vcl.skia.trace", "copybits(" << this << "): (" << src << "): " << rPosAry)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "copybits(" << this << "): (" << src << "): " << rPosAry ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1206" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "copybits(" << this << "): (" << src << "): " << rPosAry), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "copybits(" << this << "): (" << src << "): " << rPosAry; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1206" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "copybits(" << this << "): (" << src << "): " << rPosAry) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1206" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "copybits(" << this << "): (" << src << "): " << rPosAry), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "copybits(" << this << "): (" << src << "): " << rPosAry; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1206" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1207 | // Do not use makeImageSnapshot(rect), as that one may make a needless data copy. | |||
1208 | sk_sp<SkImage> image = SkiaHelper::makeCheckedImageSnapshot(src->mSurface); | |||
1209 | SkPaint paint; | |||
1210 | paint.setBlendMode(SkBlendMode::kSrc); // copy as is, including alpha | |||
1211 | if (rPosAry.mnSrcWidth != rPosAry.mnDestWidth | |||
1212 | || rPosAry.mnSrcHeight != rPosAry.mnDestHeight) | |||
1213 | paint.setFilterQuality(kHigh_SkFilterQuality); | |||
1214 | getDrawCanvas()->drawImageRect(image, | |||
1215 | SkIRect::MakeXYWH(rPosAry.mnSrcX, rPosAry.mnSrcY, | |||
1216 | rPosAry.mnSrcWidth, rPosAry.mnSrcHeight), | |||
1217 | SkRect::MakeXYWH(rPosAry.mnDestX, rPosAry.mnDestY, | |||
1218 | rPosAry.mnDestWidth, rPosAry.mnDestHeight), | |||
1219 | &paint); | |||
1220 | } | |||
1221 | assert(!mXorMode)(static_cast <bool> (!mXorMode) ? void (0) : __assert_fail ("!mXorMode", "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" , 1221, __extension__ __PRETTY_FUNCTION__)); | |||
1222 | postDraw(); | |||
1223 | } | |||
1224 | ||||
1225 | bool SkiaSalGraphicsImpl::blendBitmap(const SalTwoRect& rPosAry, const SalBitmap& rBitmap) | |||
1226 | { | |||
1227 | if (checkInvalidSourceOrDestination(rPosAry)) | |||
1228 | return false; | |||
1229 | ||||
1230 | assert(dynamic_cast<const SkiaSalBitmap*>(&rBitmap))(static_cast <bool> (dynamic_cast<const SkiaSalBitmap *>(&rBitmap)) ? void (0) : __assert_fail ("dynamic_cast<const SkiaSalBitmap*>(&rBitmap)" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 1230 , __extension__ __PRETTY_FUNCTION__)); | |||
1231 | const SkiaSalBitmap& rSkiaBitmap = static_cast<const SkiaSalBitmap&>(rBitmap); | |||
1232 | // This is used by VirtualDevice in the alpha mode for the "alpha" layer which | |||
1233 | // is actually one-minus-alpha (opacity). Therefore white=0xff=transparent, | |||
1234 | // black=0x00=opaque. So the result is transparent only if both the inputs | |||
1235 | // are transparent. Since for blending operations white=1.0 and black=0.0, | |||
1236 | // kMultiply should handle exactly that (transparent*transparent=transparent, | |||
1237 | // opaque*transparent=opaque). And guessing from the "floor" in TYPE_BLEND in opengl's | |||
1238 | // combinedTextureFragmentShader.glsl, the layer is not even alpha values but | |||
1239 | // simply yes-or-no mask. | |||
1240 | // See also blendAlphaBitmap(). | |||
1241 | if (rSkiaBitmap.IsFullyOpaqueAsAlpha()) | |||
1242 | { | |||
1243 | // Optimization. If the bitmap means fully opaque, it's all zero's. In CPU | |||
1244 | // mode it should be faster to just copy instead of SkBlendMode::kMultiply. | |||
1245 | drawBitmap(rPosAry, rSkiaBitmap); | |||
1246 | } | |||
1247 | else | |||
1248 | drawBitmap(rPosAry, rSkiaBitmap, SkBlendMode::kMultiply); | |||
1249 | return true; | |||
1250 | } | |||
1251 | ||||
1252 | bool SkiaSalGraphicsImpl::blendAlphaBitmap(const SalTwoRect& rPosAry, | |||
1253 | const SalBitmap& rSourceBitmap, | |||
1254 | const SalBitmap& rMaskBitmap, | |||
1255 | const SalBitmap& rAlphaBitmap) | |||
1256 | { | |||
1257 | if (checkInvalidSourceOrDestination(rPosAry)) | |||
1258 | return false; | |||
1259 | ||||
1260 | assert(dynamic_cast<const SkiaSalBitmap*>(&rSourceBitmap))(static_cast <bool> (dynamic_cast<const SkiaSalBitmap *>(&rSourceBitmap)) ? void (0) : __assert_fail ("dynamic_cast<const SkiaSalBitmap*>(&rSourceBitmap)" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 1260 , __extension__ __PRETTY_FUNCTION__)); | |||
1261 | assert(dynamic_cast<const SkiaSalBitmap*>(&rMaskBitmap))(static_cast <bool> (dynamic_cast<const SkiaSalBitmap *>(&rMaskBitmap)) ? void (0) : __assert_fail ("dynamic_cast<const SkiaSalBitmap*>(&rMaskBitmap)" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 1261 , __extension__ __PRETTY_FUNCTION__)); | |||
1262 | assert(dynamic_cast<const SkiaSalBitmap*>(&rAlphaBitmap))(static_cast <bool> (dynamic_cast<const SkiaSalBitmap *>(&rAlphaBitmap)) ? void (0) : __assert_fail ("dynamic_cast<const SkiaSalBitmap*>(&rAlphaBitmap)" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 1262 , __extension__ __PRETTY_FUNCTION__)); | |||
1263 | const SkiaSalBitmap& rSkiaSourceBitmap = static_cast<const SkiaSalBitmap&>(rSourceBitmap); | |||
1264 | const SkiaSalBitmap& rSkiaMaskBitmap = static_cast<const SkiaSalBitmap&>(rMaskBitmap); | |||
1265 | const SkiaSalBitmap& rSkiaAlphaBitmap = static_cast<const SkiaSalBitmap&>(rAlphaBitmap); | |||
1266 | ||||
1267 | if (rSkiaMaskBitmap.IsFullyOpaqueAsAlpha()) | |||
1268 | { | |||
1269 | // Optimization. If the mask of the bitmap to be blended means it's actually opaque, | |||
1270 | // just draw the bitmap directly (that's what the math below will result in). | |||
1271 | drawBitmap(rPosAry, rSkiaSourceBitmap); | |||
1272 | return true; | |||
1273 | } | |||
1274 | // This was originally implemented for the OpenGL drawing method and it is poorly documented. | |||
1275 | // The source and mask bitmaps are the usual data and alpha bitmaps, and 'alpha' | |||
1276 | // is the "alpha" layer of the VirtualDevice (the alpha in VirtualDevice is also stored | |||
1277 | // as a separate bitmap). Now if I understand it correctly these two alpha masks first need | |||
1278 | // to be combined into the actual alpha mask to be used. The formula for TYPE_BLEND | |||
1279 | // in opengl's combinedTextureFragmentShader.glsl is | |||
1280 | // "result_alpha = 1.0 - (1.0 - floor(alpha)) * mask". | |||
1281 | // See also blendBitmap(). | |||
1282 | ||||
1283 | // First do the "( 1 - alpha ) * mask" | |||
1284 | // (no idea how to do "floor", but hopefully not needed in practice). | |||
1285 | sk_sp<SkShader> shaderAlpha | |||
1286 | = SkShaders::Blend(SkBlendMode::kDstOut, rSkiaMaskBitmap.GetAlphaSkShader(), | |||
1287 | rSkiaAlphaBitmap.GetAlphaSkShader()); | |||
1288 | // And now draw the bitmap with "1 - x", where x is the "( 1 - alpha ) * mask". | |||
1289 | sk_sp<SkShader> shader | |||
1290 | = SkShaders::Blend(SkBlendMode::kSrcOut, shaderAlpha, rSkiaSourceBitmap.GetSkShader()); | |||
1291 | drawShader(rPosAry, shader); | |||
1292 | return true; | |||
1293 | } | |||
1294 | ||||
1295 | void SkiaSalGraphicsImpl::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap) | |||
1296 | { | |||
1297 | if (checkInvalidSourceOrDestination(rPosAry)) | |||
1298 | return; | |||
1299 | ||||
1300 | assert(dynamic_cast<const SkiaSalBitmap*>(&rSalBitmap))(static_cast <bool> (dynamic_cast<const SkiaSalBitmap *>(&rSalBitmap)) ? void (0) : __assert_fail ("dynamic_cast<const SkiaSalBitmap*>(&rSalBitmap)" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 1300 , __extension__ __PRETTY_FUNCTION__)); | |||
1301 | const SkiaSalBitmap& rSkiaSourceBitmap = static_cast<const SkiaSalBitmap&>(rSalBitmap); | |||
1302 | ||||
1303 | drawBitmap(rPosAry, rSkiaSourceBitmap); | |||
1304 | } | |||
1305 | ||||
1306 | void SkiaSalGraphicsImpl::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, | |||
1307 | const SalBitmap& rMaskBitmap) | |||
1308 | { | |||
1309 | drawAlphaBitmap(rPosAry, rSalBitmap, rMaskBitmap); | |||
1310 | } | |||
1311 | ||||
1312 | void SkiaSalGraphicsImpl::drawMask(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, | |||
1313 | Color nMaskColor) | |||
1314 | { | |||
1315 | assert(dynamic_cast<const SkiaSalBitmap*>(&rSalBitmap))(static_cast <bool> (dynamic_cast<const SkiaSalBitmap *>(&rSalBitmap)) ? void (0) : __assert_fail ("dynamic_cast<const SkiaSalBitmap*>(&rSalBitmap)" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 1315 , __extension__ __PRETTY_FUNCTION__)); | |||
1316 | const SkiaSalBitmap& skiaBitmap = static_cast<const SkiaSalBitmap&>(rSalBitmap); | |||
1317 | drawShader(rPosAry, | |||
1318 | SkShaders::Blend(SkBlendMode::kDstOut, // VCL alpha is one-minus-alpha. | |||
1319 | SkShaders::Color(toSkColor(nMaskColor)), | |||
1320 | skiaBitmap.GetAlphaSkShader())); | |||
1321 | } | |||
1322 | ||||
1323 | std::shared_ptr<SalBitmap> SkiaSalGraphicsImpl::getBitmap(long nX, long nY, long nWidth, | |||
1324 | long nHeight) | |||
1325 | { | |||
1326 | SkiaZone zone; | |||
1327 | checkSurface(); | |||
1328 | SAL_INFO("vcl.skia.trace",do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "getbitmap(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth , nHeight)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1329" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "getbitmap(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth, nHeight)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "getbitmap(" << this << "): " << SkIRect:: MakeXYWH(nX, nY, nWidth, nHeight); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1329" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "getbitmap(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth, nHeight)) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1329" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "getbitmap(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth, nHeight)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "getbitmap(" << this << "): " << SkIRect:: MakeXYWH(nX, nY, nWidth, nHeight); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1329" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
1329 | "getbitmap(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth, nHeight))do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "getbitmap(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth , nHeight)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1329" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "getbitmap(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth, nHeight)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "getbitmap(" << this << "): " << SkIRect:: MakeXYWH(nX, nY, nWidth, nHeight); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1329" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "getbitmap(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth, nHeight)) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1329" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "getbitmap(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth, nHeight)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "getbitmap(" << this << "): " << SkIRect:: MakeXYWH(nX, nY, nWidth, nHeight); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1329" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1330 | flushDrawing(); | |||
1331 | // TODO makeImageSnapshot(rect) may copy the data, which may be a waste if this is used | |||
1332 | // e.g. for VirtualDevice's lame alpha blending, in which case the image will eventually end up | |||
1333 | // in blendAlphaBitmap(), where we could simply use the proper rect of the image. | |||
1334 | sk_sp<SkImage> image = SkiaHelper::makeCheckedImageSnapshot( | |||
1335 | mSurface, SkIRect::MakeXYWH(nX, nY, nWidth, nHeight)); | |||
1336 | return std::make_shared<SkiaSalBitmap>(image); | |||
1337 | } | |||
1338 | ||||
1339 | Color SkiaSalGraphicsImpl::getPixel(long nX, long nY) | |||
1340 | { | |||
1341 | SkiaZone zone; | |||
1342 | checkSurface(); | |||
1343 | SAL_INFO("vcl.skia.trace", "getpixel(" << this << "): " << Point(nX, nY))do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "getpixel(" << this << "): " << Point(nX, nY)) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1343" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "getpixel(" << this << "): " << Point(nX, nY)), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "getpixel(" << this << "): " << Point(nX, nY); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1343" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "getpixel(" << this << "): " << Point(nX, nY)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1343" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "getpixel(" << this << "): " << Point(nX, nY)), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "getpixel(" << this << "): " << Point(nX, nY); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1343" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1344 | flushDrawing(); | |||
1345 | // This is presumably slow, but getPixel() should be generally used only by unit tests. | |||
1346 | SkBitmap bitmap; | |||
1347 | if (!bitmap.tryAllocN32Pixels(GetWidth(), GetHeight())) | |||
1348 | abort(); | |||
1349 | if (!mSurface->readPixels(bitmap, 0, 0)) | |||
1350 | abort(); | |||
1351 | return fromSkColor(bitmap.getColor(nX, nY)); | |||
1352 | } | |||
1353 | ||||
1354 | void SkiaSalGraphicsImpl::invert(basegfx::B2DPolygon const& rPoly, SalInvert eFlags) | |||
1355 | { | |||
1356 | preDraw(); | |||
1357 | SAL_INFO("vcl.skia.trace", "invert(" << this << "): " << rPoly << ":" << int(eFlags))do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "invert(" << this << "): " << rPoly << ":" << int(eFlags )) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ( "vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1357" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "invert(" << this << "): " << rPoly << ":" << int(eFlags)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "invert(" << this << "): " << rPoly << ":" << int(eFlags); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1357" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "invert(" << this << "): " << rPoly << ":" << int(eFlags)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1357" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "invert(" << this << "): " << rPoly << ":" << int(eFlags)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "invert(" << this << "): " << rPoly << ":" << int(eFlags); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1357" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1358 | assert(!mXorMode)(static_cast <bool> (!mXorMode) ? void (0) : __assert_fail ("!mXorMode", "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" , 1358, __extension__ __PRETTY_FUNCTION__)); | |||
1359 | // Intel Vulkan drivers (up to current 0.401.3889) have a problem | |||
1360 | // with SkBlendMode::kDifference(?) and surfaces wider than 1024 pixels, resulting | |||
1361 | // in drawing errors. Work that around by fetching the relevant part of the surface | |||
1362 | // and drawing using CPU. | |||
1363 | bool intelHack | |||
1364 | = (isGPU() && SkiaHelper::getVendor() == DriverBlocklist::VendorIntel && !mXorMode); | |||
1365 | // TrackFrame just inverts a dashed path around the polygon | |||
1366 | if (eFlags == SalInvert::TrackFrame) | |||
1367 | { | |||
1368 | SkPath aPath; | |||
1369 | addPolygonToPath(rPoly, aPath); | |||
1370 | aPath.setFillType(SkPathFillType::kEvenOdd); | |||
1371 | // TrackFrame is not supposed to paint outside of the polygon (usually rectangle), | |||
1372 | // but wider stroke width usually results in that, so ensure the requirement | |||
1373 | // by clipping. | |||
1374 | SkAutoCanvasRestore autoRestore(getDrawCanvas(), true); | |||
1375 | getDrawCanvas()->clipRect(aPath.getBounds(), SkClipOp::kIntersect, false); | |||
1376 | SkPaint aPaint; | |||
1377 | aPaint.setStrokeWidth(2); | |||
1378 | float intervals[] = { 4.0f, 4.0f }; | |||
1379 | aPaint.setStyle(SkPaint::kStroke_Style); | |||
1380 | aPaint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals)(sizeof(SkArrayCountHelper(intervals))), 0)); | |||
1381 | aPaint.setColor(SkColorSetARGB(255, 255, 255, 255)); | |||
1382 | aPaint.setBlendMode(SkBlendMode::kDifference); | |||
1383 | if (!intelHack) | |||
1384 | getDrawCanvas()->drawPath(aPath, aPaint); | |||
1385 | else | |||
1386 | { | |||
1387 | SkRect area; | |||
1388 | aPath.getBounds().roundOut(&area); | |||
1389 | SkRect size = SkRect::MakeWH(area.width(), area.height()); | |||
1390 | sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(area.width(), area.height()); | |||
1391 | SkPaint copy; | |||
1392 | copy.setBlendMode(SkBlendMode::kSrc); | |||
1393 | flushDrawing(); | |||
1394 | surface->getCanvas()->drawImageRect(SkiaHelper::makeCheckedImageSnapshot(mSurface), | |||
1395 | area, size, ©); | |||
1396 | aPath.offset(-area.x(), -area.y()); | |||
1397 | surface->getCanvas()->drawPath(aPath, aPaint); | |||
1398 | getDrawCanvas()->drawImageRect(SkiaHelper::makeCheckedImageSnapshot(surface), size, | |||
1399 | area, ©); | |||
1400 | } | |||
1401 | } | |||
1402 | else | |||
1403 | { | |||
1404 | SkPath aPath; | |||
1405 | addPolygonToPath(rPoly, aPath); | |||
1406 | aPath.setFillType(SkPathFillType::kEvenOdd); | |||
1407 | SkPaint aPaint; | |||
1408 | aPaint.setColor(SkColorSetARGB(255, 255, 255, 255)); | |||
1409 | aPaint.setStyle(SkPaint::kFill_Style); | |||
1410 | aPaint.setBlendMode(SkBlendMode::kDifference); | |||
1411 | ||||
1412 | // N50 inverts in checker pattern | |||
1413 | if (eFlags == SalInvert::N50) | |||
1414 | { | |||
1415 | // This creates 2x2 checker pattern bitmap | |||
1416 | // TODO Use SkiaHelper::createSkSurface() and cache the image | |||
1417 | SkBitmap aBitmap; | |||
1418 | aBitmap.allocN32Pixels(2, 2); | |||
1419 | const SkPMColor white = SkPreMultiplyARGB(0xFF, 0xFF, 0xFF, 0xFF); | |||
1420 | const SkPMColor black = SkPreMultiplyARGB(0xFF, 0x00, 0x00, 0x00); | |||
1421 | SkPMColor* scanline; | |||
1422 | scanline = aBitmap.getAddr32(0, 0); | |||
1423 | *scanline++ = white; | |||
1424 | *scanline++ = black; | |||
1425 | scanline = aBitmap.getAddr32(0, 1); | |||
1426 | *scanline++ = black; | |||
1427 | *scanline++ = white; | |||
1428 | aBitmap.setImmutable(); | |||
1429 | // The bitmap is repeated in both directions the checker pattern is as big | |||
1430 | // as the polygon (usually rectangle) | |||
1431 | aPaint.setShader(aBitmap.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat)); | |||
1432 | } | |||
1433 | if (!intelHack) | |||
1434 | getDrawCanvas()->drawPath(aPath, aPaint); | |||
1435 | else | |||
1436 | { | |||
1437 | SkRect area; | |||
1438 | aPath.getBounds().roundOut(&area); | |||
1439 | SkRect size = SkRect::MakeWH(area.width(), area.height()); | |||
1440 | sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(area.width(), area.height()); | |||
1441 | SkPaint copy; | |||
1442 | copy.setBlendMode(SkBlendMode::kSrc); | |||
1443 | flushDrawing(); | |||
1444 | surface->getCanvas()->drawImageRect(SkiaHelper::makeCheckedImageSnapshot(mSurface), | |||
1445 | area, size, ©); | |||
1446 | aPath.offset(-area.x(), -area.y()); | |||
1447 | surface->getCanvas()->drawPath(aPath, aPaint); | |||
1448 | getDrawCanvas()->drawImageRect(SkiaHelper::makeCheckedImageSnapshot(surface), size, | |||
1449 | area, ©); | |||
1450 | } | |||
1451 | } | |||
1452 | postDraw(); | |||
1453 | } | |||
1454 | ||||
1455 | void SkiaSalGraphicsImpl::invert(long nX, long nY, long nWidth, long nHeight, SalInvert eFlags) | |||
1456 | { | |||
1457 | basegfx::B2DRectangle aRectangle(nX, nY, nX + nWidth, nY + nHeight); | |||
1458 | auto aRect = basegfx::utils::createPolygonFromRect(aRectangle); | |||
1459 | invert(aRect, eFlags); | |||
1460 | } | |||
1461 | ||||
1462 | void SkiaSalGraphicsImpl::invert(sal_uInt32 nPoints, const SalPoint* pPointArray, SalInvert eFlags) | |||
1463 | { | |||
1464 | basegfx::B2DPolygon aPolygon; | |||
1465 | aPolygon.append(basegfx::B2DPoint(pPointArray[0].mnX, pPointArray[0].mnY), nPoints); | |||
1466 | for (sal_uInt32 i = 1; i < nPoints; ++i) | |||
1467 | { | |||
1468 | aPolygon.setB2DPoint(i, basegfx::B2DPoint(pPointArray[i].mnX, pPointArray[i].mnY)); | |||
1469 | } | |||
1470 | aPolygon.setClosed(true); | |||
1471 | ||||
1472 | invert(aPolygon, eFlags); | |||
1473 | } | |||
1474 | ||||
1475 | bool SkiaSalGraphicsImpl::drawEPS(long, long, long, long, void*, sal_uInt32) { return false; } | |||
1476 | ||||
1477 | // Create SkImage from a bitmap and possibly an alpha mask (the usual VCL one-minus-alpha), | |||
1478 | // with the given target size. Result will be possibly cached, unless disabled. | |||
1479 | sk_sp<SkImage> SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitmap, | |||
1480 | const SkiaSalBitmap* alphaBitmap, | |||
1481 | const Size targetSize) | |||
1482 | { | |||
1483 | sk_sp<SkImage> image; | |||
1484 | // GPU-accelerated drawing with SkShader should be fast enough to not need caching. | |||
1485 | if (isGPU()) | |||
1486 | return image; | |||
1487 | if (targetSize.IsEmpty()) | |||
1488 | return image; | |||
1489 | if (alphaBitmap && alphaBitmap->IsFullyOpaqueAsAlpha()) | |||
1490 | alphaBitmap = nullptr; // the alpha can be ignored | |||
1491 | // Probably not much point in caching of just doing a copy. | |||
1492 | if (alphaBitmap == nullptr && targetSize == bitmap.GetSize()) | |||
1493 | return image; | |||
1494 | // Image too small to be worth caching if not scaling. | |||
1495 | if (targetSize == bitmap.GetSize() && targetSize.Width() < 100 && targetSize.Height() < 100) | |||
1496 | return image; | |||
1497 | // In some cases (tdf#134237) the target size may be very large. In that case it's | |||
1498 | // better to rely on Skia to clip and draw only the necessary, rather than prepare | |||
1499 | // a very large image only to not use most of it. | |||
1500 | const Size drawAreaSize = mClipRegion.GetBoundRect().GetSize(); | |||
1501 | if (targetSize.Width() > drawAreaSize.Width() || targetSize.Height() > drawAreaSize.Height()) | |||
1502 | { | |||
1503 | // This is a bit tricky. The condition above just checks that at least a part of the resulting | |||
1504 | // image will not be used (it's larger then our drawing area). But this may often happen | |||
1505 | // when just scrolling a document with a large image, where the caching may very well be worth it. | |||
1506 | // Since the problem is mainly the cost of upscaling and then the size of the resulting bitmap, | |||
1507 | // compute a ratio of how much this is going to be scaled up, how much this is larger than | |||
1508 | // the drawing area, and then refuse to cache if it's too much. | |||
1509 | const double upscaleRatio | |||
1510 | = std::max(1.0, 1.0 * targetSize.Width() / bitmap.GetSize().Width() | |||
1511 | * targetSize.Height() / bitmap.GetSize().Height()); | |||
1512 | const double oversizeRatio = 1.0 * targetSize.Width() / drawAreaSize.Width() | |||
1513 | * targetSize.Height() / drawAreaSize.Height(); | |||
1514 | const double ratio = upscaleRatio * oversizeRatio; | |||
1515 | if (ratio > 4) | |||
1516 | { | |||
1517 | SAL_INFO("vcl.skia.trace", "mergecachebitmaps("do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1520" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1520" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1520" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1520" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
1518 | << this << "): not caching, ratio:" << ratio << ", "do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1520" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1520" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1520" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1520" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
1519 | << bitmap.GetSize() << "->" << targetSize << " in "do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1520" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1520" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1520" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1520" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
1520 | << drawAreaSize)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1520" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1520" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1520" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "mergecachebitmaps(" << this << "): not caching, ratio:" << ratio << ", " << bitmap.GetSize() << "->" << targetSize << " in " << drawAreaSize; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1520" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1521 | return image; | |||
1522 | } | |||
1523 | } | |||
1524 | // Do not cache the result if it would take most of the cache and thus get evicted soon. | |||
1525 | if (targetSize.Width() * targetSize.Height() * 4 > SkiaHelper::MAX_CACHE_SIZE * 0.7) | |||
1526 | return image; | |||
1527 | OString key; | |||
1528 | OStringBuffer keyBuf; | |||
1529 | keyBuf.append(targetSize.Width()) | |||
1530 | .append("x") | |||
1531 | .append(targetSize.Height()) | |||
1532 | .append("_") | |||
1533 | .append(bitmap.GetImageKey()); | |||
1534 | if (alphaBitmap) | |||
1535 | keyBuf.append("_").append(alphaBitmap->GetAlphaImageKey()); | |||
1536 | key = keyBuf.makeStringAndClear(); | |||
1537 | image = SkiaHelper::findCachedImage(key); | |||
1538 | if (image) | |||
1539 | { | |||
1540 | assert(image->width() == targetSize.Width() && image->height() == targetSize.Height())(static_cast <bool> (image->width() == targetSize.Width () && image->height() == targetSize.Height()) ? void (0) : __assert_fail ("image->width() == targetSize.Width() && image->height() == targetSize.Height()" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 1540 , __extension__ __PRETTY_FUNCTION__)); | |||
1541 | return image; | |||
1542 | } | |||
1543 | sk_sp<SkSurface> tmpSurface = SkiaHelper::createSkSurface(targetSize); | |||
1544 | if (!tmpSurface) | |||
1545 | return nullptr; | |||
1546 | SkCanvas* canvas = tmpSurface->getCanvas(); | |||
1547 | SkAutoCanvasRestore autoRestore(canvas, true); | |||
1548 | SkPaint paint; | |||
1549 | if (targetSize != bitmap.GetSize()) | |||
1550 | { | |||
1551 | SkMatrix matrix; | |||
1552 | matrix.set(SkMatrix::kMScaleX, 1.0 * targetSize.Width() / bitmap.GetSize().Width()); | |||
1553 | matrix.set(SkMatrix::kMScaleY, 1.0 * targetSize.Height() / bitmap.GetSize().Height()); | |||
1554 | canvas->concat(matrix); | |||
1555 | paint.setFilterQuality(kHigh_SkFilterQuality); | |||
1556 | } | |||
1557 | if (alphaBitmap != nullptr) | |||
1558 | { | |||
1559 | canvas->clear(SK_ColorTRANSPARENT); | |||
1560 | paint.setShader(SkShaders::Blend(SkBlendMode::kDstOut, bitmap.GetSkShader(), | |||
1561 | alphaBitmap->GetAlphaSkShader())); | |||
1562 | canvas->drawPaint(paint); | |||
1563 | } | |||
1564 | else if (bitmap.PreferSkShader()) | |||
1565 | { | |||
1566 | paint.setShader(bitmap.GetSkShader()); | |||
1567 | canvas->drawPaint(paint); | |||
1568 | } | |||
1569 | else | |||
1570 | canvas->drawImage(bitmap.GetSkImage(), 0, 0, &paint); | |||
1571 | image = SkiaHelper::makeCheckedImageSnapshot(tmpSurface); | |||
1572 | SkiaHelper::addCachedImage(key, image); | |||
1573 | return image; | |||
1574 | } | |||
1575 | ||||
1576 | bool SkiaSalGraphicsImpl::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSourceBitmap, | |||
1577 | const SalBitmap& rAlphaBitmap) | |||
1578 | { | |||
1579 | assert(dynamic_cast<const SkiaSalBitmap*>(&rSourceBitmap))(static_cast <bool> (dynamic_cast<const SkiaSalBitmap *>(&rSourceBitmap)) ? void (0) : __assert_fail ("dynamic_cast<const SkiaSalBitmap*>(&rSourceBitmap)" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 1579 , __extension__ __PRETTY_FUNCTION__)); | |||
1580 | assert(dynamic_cast<const SkiaSalBitmap*>(&rAlphaBitmap))(static_cast <bool> (dynamic_cast<const SkiaSalBitmap *>(&rAlphaBitmap)) ? void (0) : __assert_fail ("dynamic_cast<const SkiaSalBitmap*>(&rAlphaBitmap)" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 1580 , __extension__ __PRETTY_FUNCTION__)); | |||
1581 | const SkiaSalBitmap& rSkiaSourceBitmap = static_cast<const SkiaSalBitmap&>(rSourceBitmap); | |||
1582 | const SkiaSalBitmap& rSkiaAlphaBitmap = static_cast<const SkiaSalBitmap&>(rAlphaBitmap); | |||
1583 | // In raster mode use mergeCacheBitmaps(), which will cache the result, avoiding repeated | |||
1584 | // alpha blending or scaling. In GPU mode it is simpler to just use SkShader. | |||
1585 | SalTwoRect imagePosAry(rPosAry); | |||
1586 | Size imageSize = rSourceBitmap.GetSize(); | |||
1587 | // If the bitmap will be scaled, prefer to do it in mergeCacheBitmaps(), if possible. | |||
1588 | if ((rPosAry.mnSrcWidth != rPosAry.mnDestWidth || rPosAry.mnSrcHeight != rPosAry.mnDestHeight) | |||
1589 | && rPosAry.mnSrcX == 0 && rPosAry.mnSrcY == 0 | |||
1590 | && rPosAry.mnSrcWidth == rSourceBitmap.GetSize().Width() | |||
1591 | && rPosAry.mnSrcHeight == rSourceBitmap.GetSize().Height()) | |||
1592 | { | |||
1593 | imagePosAry.mnSrcWidth = imagePosAry.mnDestWidth; | |||
1594 | imagePosAry.mnSrcHeight = imagePosAry.mnDestHeight; | |||
1595 | imageSize = Size(imagePosAry.mnSrcWidth, imagePosAry.mnSrcHeight); | |||
1596 | } | |||
1597 | sk_sp<SkImage> image = mergeCacheBitmaps(rSkiaSourceBitmap, &rSkiaAlphaBitmap, imageSize); | |||
1598 | if (image) | |||
1599 | drawImage(imagePosAry, image); | |||
1600 | else if (rSkiaAlphaBitmap.IsFullyOpaqueAsAlpha()) // alpha can be ignored | |||
1601 | drawBitmap(rPosAry, rSkiaSourceBitmap); | |||
1602 | else | |||
1603 | drawShader(rPosAry, | |||
1604 | SkShaders::Blend(SkBlendMode::kDstOut, // VCL alpha is one-minus-alpha. | |||
1605 | rSkiaSourceBitmap.GetSkShader(), | |||
1606 | rSkiaAlphaBitmap.GetAlphaSkShader())); | |||
1607 | return true; | |||
1608 | } | |||
1609 | ||||
1610 | void SkiaSalGraphicsImpl::drawBitmap(const SalTwoRect& rPosAry, const SkiaSalBitmap& bitmap, | |||
1611 | SkBlendMode blendMode) | |||
1612 | { | |||
1613 | if (bitmap.PreferSkShader()) | |||
1614 | drawShader(rPosAry, bitmap.GetSkShader(), blendMode); | |||
1615 | else | |||
1616 | drawImage(rPosAry, bitmap.GetSkImage(), blendMode); | |||
1617 | } | |||
1618 | ||||
1619 | void SkiaSalGraphicsImpl::drawImage(const SalTwoRect& rPosAry, const sk_sp<SkImage>& aImage, | |||
1620 | SkBlendMode eBlendMode) | |||
1621 | { | |||
1622 | SkRect aSourceRect | |||
1623 | = SkRect::MakeXYWH(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight); | |||
1624 | SkRect aDestinationRect = SkRect::MakeXYWH(rPosAry.mnDestX, rPosAry.mnDestY, | |||
1625 | rPosAry.mnDestWidth, rPosAry.mnDestHeight); | |||
1626 | ||||
1627 | SkPaint aPaint; | |||
1628 | aPaint.setBlendMode(eBlendMode); | |||
1629 | if (rPosAry.mnSrcWidth != rPosAry.mnDestWidth || rPosAry.mnSrcHeight != rPosAry.mnDestHeight) | |||
1630 | aPaint.setFilterQuality(kHigh_SkFilterQuality); | |||
1631 | ||||
1632 | preDraw(); | |||
1633 | SAL_INFO("vcl.skia.trace",do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "drawimage(" << this << "): " << rPosAry << ":" << SkBlendMode_Name (eBlendMode)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1634" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "drawimage(" << this << "): " << rPosAry << ":" << SkBlendMode_Name(eBlendMode )), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawimage(" << this << "): " << rPosAry << ":" << SkBlendMode_Name(eBlendMode); ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1634" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "drawimage(" << this << "): " << rPosAry << ":" << SkBlendMode_Name(eBlendMode)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1634" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "drawimage(" << this << "): " << rPosAry << ":" << SkBlendMode_Name(eBlendMode )), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawimage(" << this << "): " << rPosAry << ":" << SkBlendMode_Name(eBlendMode); ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1634" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
1634 | "drawimage(" << this << "): " << rPosAry << ":" << SkBlendMode_Name(eBlendMode))do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "drawimage(" << this << "): " << rPosAry << ":" << SkBlendMode_Name (eBlendMode)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1634" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "drawimage(" << this << "): " << rPosAry << ":" << SkBlendMode_Name(eBlendMode )), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawimage(" << this << "): " << rPosAry << ":" << SkBlendMode_Name(eBlendMode); ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1634" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "drawimage(" << this << "): " << rPosAry << ":" << SkBlendMode_Name(eBlendMode)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1634" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "drawimage(" << this << "): " << rPosAry << ":" << SkBlendMode_Name(eBlendMode )), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawimage(" << this << "): " << rPosAry << ":" << SkBlendMode_Name(eBlendMode); ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1634" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1635 | addXorRegion(aDestinationRect); | |||
1636 | getDrawCanvas()->drawImageRect(aImage, aSourceRect, aDestinationRect, &aPaint); | |||
1637 | ++mPendingOperationsToFlush; // tdf#136369 | |||
1638 | postDraw(); | |||
1639 | } | |||
1640 | ||||
1641 | // SkShader can be used to merge multiple bitmaps with appropriate blend modes (e.g. when | |||
1642 | // merging a bitmap with its alpha mask). | |||
1643 | void SkiaSalGraphicsImpl::drawShader(const SalTwoRect& rPosAry, const sk_sp<SkShader>& shader, | |||
1644 | SkBlendMode blendMode) | |||
1645 | { | |||
1646 | preDraw(); | |||
1647 | SAL_INFO("vcl.skia.trace", "drawshader(" << this << "): " << rPosAry)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "drawshader(" << this << "): " << rPosAry) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1647" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "drawshader(" << this << "): " << rPosAry), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "drawshader(" << this << "): " << rPosAry; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1647" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "drawshader(" << this << "): " << rPosAry) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1647" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "drawshader(" << this << "): " << rPosAry), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "drawshader(" << this << "): " << rPosAry; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1647" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1648 | SkRect destinationRect = SkRect::MakeXYWH(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, | |||
1649 | rPosAry.mnDestHeight); | |||
1650 | addXorRegion(destinationRect); | |||
1651 | SkPaint paint; | |||
1652 | paint.setBlendMode(blendMode); | |||
1653 | paint.setShader(shader); | |||
1654 | if (rPosAry.mnSrcWidth != rPosAry.mnDestWidth || rPosAry.mnSrcHeight != rPosAry.mnDestHeight) | |||
1655 | paint.setFilterQuality(kHigh_SkFilterQuality); | |||
1656 | SkCanvas* canvas = getDrawCanvas(); | |||
1657 | // Scaling needs to be done explicitly using a matrix. | |||
1658 | SkAutoCanvasRestore autoRestore(canvas, true); | |||
1659 | SkMatrix matrix = SkMatrix::Translate(rPosAry.mnDestX, rPosAry.mnDestY) | |||
1660 | * SkMatrix::Scale(1.0 * rPosAry.mnDestWidth / rPosAry.mnSrcWidth, | |||
1661 | 1.0 * rPosAry.mnDestHeight / rPosAry.mnSrcHeight) | |||
1662 | * SkMatrix::Translate(-rPosAry.mnSrcX, -rPosAry.mnSrcY); | |||
1663 | assert(matrix.mapXY(rPosAry.mnSrcX, rPosAry.mnSrcY)(static_cast <bool> (matrix.mapXY(rPosAry.mnSrcX, rPosAry .mnSrcY) == SkPoint::Make(rPosAry.mnDestX, rPosAry.mnDestY)) ? void (0) : __assert_fail ("matrix.mapXY(rPosAry.mnSrcX, rPosAry.mnSrcY) == SkPoint::Make(rPosAry.mnDestX, rPosAry.mnDestY)" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 1664 , __extension__ __PRETTY_FUNCTION__)) | |||
1664 | == SkPoint::Make(rPosAry.mnDestX, rPosAry.mnDestY))(static_cast <bool> (matrix.mapXY(rPosAry.mnSrcX, rPosAry .mnSrcY) == SkPoint::Make(rPosAry.mnDestX, rPosAry.mnDestY)) ? void (0) : __assert_fail ("matrix.mapXY(rPosAry.mnSrcX, rPosAry.mnSrcY) == SkPoint::Make(rPosAry.mnDestX, rPosAry.mnDestY)" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 1664 , __extension__ __PRETTY_FUNCTION__)); | |||
1665 | assert(matrix.mapXY(rPosAry.mnSrcX + rPosAry.mnSrcWidth, rPosAry.mnSrcY + rPosAry.mnSrcHeight)(static_cast <bool> (matrix.mapXY(rPosAry.mnSrcX + rPosAry .mnSrcWidth, rPosAry.mnSrcY + rPosAry.mnSrcHeight) == SkPoint ::Make(rPosAry.mnDestX + rPosAry.mnDestWidth, rPosAry.mnDestY + rPosAry.mnDestHeight)) ? void (0) : __assert_fail ("matrix.mapXY(rPosAry.mnSrcX + rPosAry.mnSrcWidth, rPosAry.mnSrcY + rPosAry.mnSrcHeight) == SkPoint::Make(rPosAry.mnDestX + rPosAry.mnDestWidth, rPosAry.mnDestY + rPosAry.mnDestHeight)" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 1667 , __extension__ __PRETTY_FUNCTION__)) | |||
1666 | == SkPoint::Make(rPosAry.mnDestX + rPosAry.mnDestWidth,(static_cast <bool> (matrix.mapXY(rPosAry.mnSrcX + rPosAry .mnSrcWidth, rPosAry.mnSrcY + rPosAry.mnSrcHeight) == SkPoint ::Make(rPosAry.mnDestX + rPosAry.mnDestWidth, rPosAry.mnDestY + rPosAry.mnDestHeight)) ? void (0) : __assert_fail ("matrix.mapXY(rPosAry.mnSrcX + rPosAry.mnSrcWidth, rPosAry.mnSrcY + rPosAry.mnSrcHeight) == SkPoint::Make(rPosAry.mnDestX + rPosAry.mnDestWidth, rPosAry.mnDestY + rPosAry.mnDestHeight)" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 1667 , __extension__ __PRETTY_FUNCTION__)) | |||
1667 | rPosAry.mnDestY + rPosAry.mnDestHeight))(static_cast <bool> (matrix.mapXY(rPosAry.mnSrcX + rPosAry .mnSrcWidth, rPosAry.mnSrcY + rPosAry.mnSrcHeight) == SkPoint ::Make(rPosAry.mnDestX + rPosAry.mnDestWidth, rPosAry.mnDestY + rPosAry.mnDestHeight)) ? void (0) : __assert_fail ("matrix.mapXY(rPosAry.mnSrcX + rPosAry.mnSrcWidth, rPosAry.mnSrcY + rPosAry.mnSrcHeight) == SkPoint::Make(rPosAry.mnDestX + rPosAry.mnDestWidth, rPosAry.mnDestY + rPosAry.mnDestHeight)" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 1667 , __extension__ __PRETTY_FUNCTION__)); | |||
1668 | canvas->concat(matrix); | |||
1669 | SkRect sourceRect | |||
1670 | = SkRect::MakeXYWH(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight); | |||
1671 | canvas->drawRect(sourceRect, paint); | |||
1672 | postDraw(); | |||
1673 | } | |||
1674 | ||||
1675 | bool SkiaSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull, | |||
1676 | const basegfx::B2DPoint& rX, | |||
1677 | const basegfx::B2DPoint& rY, | |||
1678 | const SalBitmap& rSourceBitmap, | |||
1679 | const SalBitmap* pAlphaBitmap) | |||
1680 | { | |||
1681 | assert(dynamic_cast<const SkiaSalBitmap*>(&rSourceBitmap))(static_cast <bool> (dynamic_cast<const SkiaSalBitmap *>(&rSourceBitmap)) ? void (0) : __assert_fail ("dynamic_cast<const SkiaSalBitmap*>(&rSourceBitmap)" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 1681 , __extension__ __PRETTY_FUNCTION__)); | |||
1682 | assert(!pAlphaBitmap || dynamic_cast<const SkiaSalBitmap*>(pAlphaBitmap))(static_cast <bool> (!pAlphaBitmap || dynamic_cast<const SkiaSalBitmap*>(pAlphaBitmap)) ? void (0) : __assert_fail ("!pAlphaBitmap || dynamic_cast<const SkiaSalBitmap*>(pAlphaBitmap)" , "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx", 1682 , __extension__ __PRETTY_FUNCTION__)); | |||
1683 | ||||
1684 | const SkiaSalBitmap& rSkiaBitmap = static_cast<const SkiaSalBitmap&>(rSourceBitmap); | |||
1685 | const SkiaSalBitmap* pSkiaAlphaBitmap = static_cast<const SkiaSalBitmap*>(pAlphaBitmap); | |||
1686 | ||||
1687 | if (pSkiaAlphaBitmap && pSkiaAlphaBitmap->IsFullyOpaqueAsAlpha()) | |||
1688 | pSkiaAlphaBitmap = nullptr; // the alpha can be ignored | |||
1689 | ||||
1690 | // Setup the image transformation, | |||
1691 | // using the rNull, rX, rY points as destinations for the (0,0), (Width,0), (0,Height) source points. | |||
1692 | const basegfx::B2DVector aXRel = rX - rNull; | |||
1693 | const basegfx::B2DVector aYRel = rY - rNull; | |||
1694 | ||||
1695 | preDraw(); | |||
1696 | SAL_INFO("vcl.skia.trace", "drawtransformedbitmap(" << this << "): " << rSourceBitmap.GetSize()do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "drawtransformedbitmap(" << this << "): " << rSourceBitmap.GetSize( ) << " " << rNull << ":" << rX << ":" << rY) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1697" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "drawtransformedbitmap(" << this << "): " << rSourceBitmap.GetSize() << " " << rNull << ":" << rX << ":" << rY), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawtransformedbitmap(" << this << "): " << rSourceBitmap.GetSize() << " " << rNull << ":" << rX << ":" << rY; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1697" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "drawtransformedbitmap(" << this << "): " << rSourceBitmap.GetSize() << " " << rNull << ":" << rX << ":" << rY) == 1) { :: sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1697" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "drawtransformedbitmap(" << this << "): " << rSourceBitmap.GetSize() << " " << rNull << ":" << rX << ":" << rY), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawtransformedbitmap(" << this << "): " << rSourceBitmap.GetSize() << " " << rNull << ":" << rX << ":" << rY; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1697" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
1697 | << " " << rNull << ":" << rX << ":" << rY)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "drawtransformedbitmap(" << this << "): " << rSourceBitmap.GetSize( ) << " " << rNull << ":" << rX << ":" << rY) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1697" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "drawtransformedbitmap(" << this << "): " << rSourceBitmap.GetSize() << " " << rNull << ":" << rX << ":" << rY), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawtransformedbitmap(" << this << "): " << rSourceBitmap.GetSize() << " " << rNull << ":" << rX << ":" << rY; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1697" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "drawtransformedbitmap(" << this << "): " << rSourceBitmap.GetSize() << " " << rNull << ":" << rX << ":" << rY) == 1) { :: sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1697" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "drawtransformedbitmap(" << this << "): " << rSourceBitmap.GetSize() << " " << rNull << ":" << rX << ":" << rY), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawtransformedbitmap(" << this << "): " << rSourceBitmap.GetSize() << " " << rNull << ":" << rX << ":" << rY; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1697" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1698 | ||||
1699 | addXorRegion(SkRect::MakeWH(GetWidth(), GetHeight())); // can't tell, use whole area | |||
1700 | // In raster mode scaling and alpha blending is still somewhat expensive if done repeatedly, | |||
1701 | // so use mergeCacheBitmaps(), which will cache the result if useful. | |||
1702 | // It is better to use SkShader if in GPU mode, if the operation is simple or if the temporary | |||
1703 | // image would be very large. | |||
1704 | sk_sp<SkImage> imageToDraw = mergeCacheBitmaps( | |||
1705 | rSkiaBitmap, pSkiaAlphaBitmap, Size(round(aXRel.getLength()), round(aYRel.getLength()))); | |||
1706 | if (imageToDraw) | |||
1707 | { | |||
1708 | SkMatrix matrix; | |||
1709 | // Round sizes for scaling, so that sub-pixel differences don't | |||
1710 | // trigger unnecessary scaling. Image has already been scaled | |||
1711 | // by mergeCacheBitmaps() and we shouldn't scale here again | |||
1712 | // unless the drawing is also skewed. | |||
1713 | matrix.set(SkMatrix::kMScaleX, round(aXRel.getX()) / imageToDraw->width()); | |||
1714 | matrix.set(SkMatrix::kMScaleY, round(aYRel.getY()) / imageToDraw->height()); | |||
1715 | matrix.set(SkMatrix::kMSkewY, aXRel.getY() / imageToDraw->width()); | |||
1716 | matrix.set(SkMatrix::kMSkewX, aYRel.getX() / imageToDraw->height()); | |||
1717 | matrix.set(SkMatrix::kMTransX, rNull.getX()); | |||
1718 | matrix.set(SkMatrix::kMTransY, rNull.getY()); | |||
1719 | SkCanvas* canvas = getDrawCanvas(); | |||
1720 | SkAutoCanvasRestore autoRestore(canvas, true); | |||
1721 | canvas->concat(matrix); | |||
1722 | SkPaint paint; | |||
1723 | if (!matrix.isTranslate()) | |||
1724 | paint.setFilterQuality(kHigh_SkFilterQuality); | |||
1725 | canvas->drawImage(imageToDraw, 0, 0, &paint); | |||
1726 | } | |||
1727 | else | |||
1728 | { | |||
1729 | SkMatrix matrix; | |||
1730 | const Size aSize = rSourceBitmap.GetSize(); | |||
1731 | matrix.set(SkMatrix::kMScaleX, aXRel.getX() / aSize.Width()); | |||
1732 | matrix.set(SkMatrix::kMScaleY, aYRel.getY() / aSize.Height()); | |||
1733 | matrix.set(SkMatrix::kMSkewY, aXRel.getY() / aSize.Width()); | |||
1734 | matrix.set(SkMatrix::kMSkewX, aYRel.getX() / aSize.Height()); | |||
1735 | matrix.set(SkMatrix::kMTransX, rNull.getX()); | |||
1736 | matrix.set(SkMatrix::kMTransY, rNull.getY()); | |||
1737 | SkCanvas* canvas = getDrawCanvas(); | |||
1738 | SkAutoCanvasRestore autoRestore(canvas, true); | |||
1739 | canvas->concat(matrix); | |||
1740 | SkPaint paint; | |||
1741 | if (!matrix.isTranslate()) | |||
1742 | paint.setFilterQuality(kHigh_SkFilterQuality); | |||
1743 | if (pSkiaAlphaBitmap) | |||
1744 | { | |||
1745 | paint.setShader(SkShaders::Blend(SkBlendMode::kDstOut, // VCL alpha is one-minus-alpha. | |||
1746 | rSkiaBitmap.GetSkShader(), | |||
1747 | pSkiaAlphaBitmap->GetAlphaSkShader())); | |||
1748 | canvas->drawRect(SkRect::MakeWH(aSize.Width(), aSize.Height()), paint); | |||
1749 | } | |||
1750 | else if (rSkiaBitmap.PreferSkShader()) | |||
1751 | { | |||
1752 | paint.setShader(rSkiaBitmap.GetSkShader()); | |||
1753 | canvas->drawRect(SkRect::MakeWH(aSize.Width(), aSize.Height()), paint); | |||
1754 | } | |||
1755 | else | |||
1756 | { | |||
1757 | canvas->drawImage(rSkiaBitmap.GetSkImage(), 0, 0, &paint); | |||
1758 | } | |||
1759 | } | |||
1760 | postDraw(); | |||
1761 | return true; | |||
1762 | } | |||
1763 | ||||
1764 | bool SkiaSalGraphicsImpl::drawAlphaRect(long nX, long nY, long nWidth, long nHeight, | |||
1765 | sal_uInt8 nTransparency) | |||
1766 | { | |||
1767 | privateDrawAlphaRect(nX, nY, nWidth, nHeight, nTransparency / 100.0); | |||
1768 | return true; | |||
1769 | } | |||
1770 | ||||
1771 | bool SkiaSalGraphicsImpl::drawGradient(const tools::PolyPolygon& rPolyPolygon, | |||
1772 | const Gradient& rGradient) | |||
1773 | { | |||
1774 | if (rGradient.GetStyle() != GradientStyle::Linear | |||
1775 | && rGradient.GetStyle() != GradientStyle::Radial) | |||
1776 | return false; // unsupported | |||
1777 | if (rGradient.GetSteps() != 0) | |||
1778 | return false; // We can't tell Skia how many colors to use in the gradient. | |||
1779 | preDraw(); | |||
1780 | SAL_INFO("vcl.skia.trace", "drawgradient(" << this << "): " << rPolyPolygon.getB2DPolyPolygon()do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "drawgradient(" << this << "): " << rPolyPolygon.getB2DPolyPolygon( ) << ":" << static_cast<int>(rGradient.GetStyle ())) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1781" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "drawgradient(" << this << "): " << rPolyPolygon.getB2DPolyPolygon() << ":" << static_cast<int>(rGradient.GetStyle())), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawgradient(" << this << "): " << rPolyPolygon.getB2DPolyPolygon() << ":" << static_cast <int>(rGradient.GetStyle()); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1781" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "drawgradient(" << this << "): " << rPolyPolygon.getB2DPolyPolygon() << ":" << static_cast <int>(rGradient.GetStyle())) == 1) { ::sal_detail_log( ( ::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1781" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "drawgradient(" << this << "): " << rPolyPolygon.getB2DPolyPolygon() << ":" << static_cast<int>(rGradient.GetStyle())), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawgradient(" << this << "): " << rPolyPolygon.getB2DPolyPolygon() << ":" << static_cast <int>(rGradient.GetStyle()); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1781" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
1781 | << ":" << static_cast<int>(rGradient.GetStyle()))do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "drawgradient(" << this << "): " << rPolyPolygon.getB2DPolyPolygon( ) << ":" << static_cast<int>(rGradient.GetStyle ())) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1781" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "drawgradient(" << this << "): " << rPolyPolygon.getB2DPolyPolygon() << ":" << static_cast<int>(rGradient.GetStyle())), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawgradient(" << this << "): " << rPolyPolygon.getB2DPolyPolygon() << ":" << static_cast <int>(rGradient.GetStyle()); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1781" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "drawgradient(" << this << "): " << rPolyPolygon.getB2DPolyPolygon() << ":" << static_cast <int>(rGradient.GetStyle())) == 1) { ::sal_detail_log( ( ::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1781" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "drawgradient(" << this << "): " << rPolyPolygon.getB2DPolyPolygon() << ":" << static_cast<int>(rGradient.GetStyle())), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawgradient(" << this << "): " << rPolyPolygon.getB2DPolyPolygon() << ":" << static_cast <int>(rGradient.GetStyle()); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1781" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1782 | tools::Rectangle boundRect(rPolyPolygon.GetBoundRect()); | |||
1783 | if (boundRect.IsEmpty()) | |||
1784 | return true; | |||
1785 | SkPath path; | |||
1786 | if (rPolyPolygon.IsRect()) | |||
1787 | { | |||
1788 | // Rect->Polygon conversion loses the right and bottom edge, fix that. | |||
1789 | path.addRect(SkRect::MakeXYWH(boundRect.getX(), boundRect.getY(), boundRect.GetWidth(), | |||
1790 | boundRect.GetHeight())); | |||
1791 | boundRect.AdjustRight(1); | |||
1792 | boundRect.AdjustBottom(1); | |||
1793 | } | |||
1794 | else | |||
1795 | addPolyPolygonToPath(rPolyPolygon.getB2DPolyPolygon(), path); | |||
1796 | path.setFillType(SkPathFillType::kEvenOdd); | |||
1797 | addXorRegion(path.getBounds()); | |||
1798 | ||||
1799 | Gradient aGradient(rGradient); | |||
1800 | tools::Rectangle aBoundRect; | |||
1801 | Point aCenter; | |||
1802 | aGradient.SetAngle(aGradient.GetAngle() + 2700); | |||
1803 | aGradient.GetBoundRect(boundRect, aBoundRect, aCenter); | |||
1804 | ||||
1805 | SkColor startColor | |||
1806 | = toSkColorWithIntensity(rGradient.GetStartColor(), rGradient.GetStartIntensity()); | |||
1807 | SkColor endColor = toSkColorWithIntensity(rGradient.GetEndColor(), rGradient.GetEndIntensity()); | |||
1808 | ||||
1809 | sk_sp<SkShader> shader; | |||
1810 | if (rGradient.GetStyle() == GradientStyle::Linear) | |||
1811 | { | |||
1812 | tools::Polygon aPoly(aBoundRect); | |||
1813 | aPoly.Rotate(aCenter, aGradient.GetAngle() % 3600); | |||
1814 | SkPoint points[2] = { SkPoint::Make(toSkX(aPoly[0].X()), toSkY(aPoly[0].Y())), | |||
1815 | SkPoint::Make(toSkX(aPoly[1].X()), toSkY(aPoly[1].Y())) }; | |||
1816 | SkColor colors[2] = { startColor, endColor }; | |||
1817 | SkScalar pos[2] = { SkDoubleToScalar(aGradient.GetBorder() / 100.0)sk_double_to_float(aGradient.GetBorder() / 100.0), 1.0 }; | |||
1818 | shader = SkGradientShader::MakeLinear(points, colors, pos, 2, SkTileMode::kClamp); | |||
1819 | } | |||
1820 | else | |||
1821 | { | |||
1822 | // Move the center by (-1,-1) (the default VCL algorithm is a bit off-center that way, | |||
1823 | // Skia is the opposite way). | |||
1824 | SkPoint center = SkPoint::Make(toSkX(aCenter.X()) - 1, toSkY(aCenter.Y()) - 1); | |||
1825 | SkScalar radius = std::max(aBoundRect.GetWidth() / 2.0, aBoundRect.GetHeight() / 2.0); | |||
1826 | SkColor colors[2] = { endColor, startColor }; | |||
1827 | SkScalar pos[2] = { SkDoubleToScalar(aGradient.GetBorder() / 100.0)sk_double_to_float(aGradient.GetBorder() / 100.0), 1.0 }; | |||
1828 | shader = SkGradientShader::MakeRadial(center, radius, colors, pos, 2, SkTileMode::kClamp); | |||
1829 | } | |||
1830 | ||||
1831 | SkPaint paint; | |||
1832 | paint.setAntiAlias(mParent.getAntiAlias()); | |||
1833 | paint.setShader(shader); | |||
1834 | getDrawCanvas()->drawPath(path, paint); | |||
1835 | postDraw(); | |||
1836 | return true; | |||
1837 | } | |||
1838 | ||||
1839 | bool SkiaSalGraphicsImpl::implDrawGradient(const basegfx::B2DPolyPolygon& rPolyPolygon, | |||
1840 | const SalGradient& rGradient) | |||
1841 | { | |||
1842 | preDraw(); | |||
1843 | SAL_INFO("vcl.skia.trace",do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "impldrawgradient(" << this << "): " << rPolyPolygon << ":" << rGradient.maPoint1 << "->" << rGradient.maPoint2 << ":" << rGradient.maStops.size()) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1845" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "impldrawgradient(" << this << "): " << rPolyPolygon << ":" << rGradient. maPoint1 << "->" << rGradient.maPoint2 << ":" << rGradient.maStops.size()), 0); } else { ::std:: ostringstream sal_detail_stream; sal_detail_stream << "impldrawgradient(" << this << "): " << rPolyPolygon << ":" << rGradient.maPoint1 << "->" << rGradient .maPoint2 << ":" << rGradient.maStops.size(); ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1845" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "impldrawgradient(" << this << "): " << rPolyPolygon << ":" << rGradient.maPoint1 << "->" << rGradient.maPoint2 << ":" << rGradient .maStops.size()) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1845" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "impldrawgradient(" << this << "): " << rPolyPolygon << ":" << rGradient. maPoint1 << "->" << rGradient.maPoint2 << ":" << rGradient.maStops.size()), 0); } else { ::std:: ostringstream sal_detail_stream; sal_detail_stream << "impldrawgradient(" << this << "): " << rPolyPolygon << ":" << rGradient.maPoint1 << "->" << rGradient .maPoint2 << ":" << rGradient.maStops.size(); ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1845" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
1844 | "impldrawgradient(" << this << "): " << rPolyPolygon << ":" << rGradient.maPoint1do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "impldrawgradient(" << this << "): " << rPolyPolygon << ":" << rGradient.maPoint1 << "->" << rGradient.maPoint2 << ":" << rGradient.maStops.size()) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1845" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "impldrawgradient(" << this << "): " << rPolyPolygon << ":" << rGradient. maPoint1 << "->" << rGradient.maPoint2 << ":" << rGradient.maStops.size()), 0); } else { ::std:: ostringstream sal_detail_stream; sal_detail_stream << "impldrawgradient(" << this << "): " << rPolyPolygon << ":" << rGradient.maPoint1 << "->" << rGradient .maPoint2 << ":" << rGradient.maStops.size(); ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1845" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "impldrawgradient(" << this << "): " << rPolyPolygon << ":" << rGradient.maPoint1 << "->" << rGradient.maPoint2 << ":" << rGradient .maStops.size()) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1845" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "impldrawgradient(" << this << "): " << rPolyPolygon << ":" << rGradient. maPoint1 << "->" << rGradient.maPoint2 << ":" << rGradient.maStops.size()), 0); } else { ::std:: ostringstream sal_detail_stream; sal_detail_stream << "impldrawgradient(" << this << "): " << rPolyPolygon << ":" << rGradient.maPoint1 << "->" << rGradient .maPoint2 << ":" << rGradient.maStops.size(); ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1845" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
1845 | << "->" << rGradient.maPoint2 << ":" << rGradient.maStops.size())do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "impldrawgradient(" << this << "): " << rPolyPolygon << ":" << rGradient.maPoint1 << "->" << rGradient.maPoint2 << ":" << rGradient.maStops.size()) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1845" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "impldrawgradient(" << this << "): " << rPolyPolygon << ":" << rGradient. maPoint1 << "->" << rGradient.maPoint2 << ":" << rGradient.maStops.size()), 0); } else { ::std:: ostringstream sal_detail_stream; sal_detail_stream << "impldrawgradient(" << this << "): " << rPolyPolygon << ":" << rGradient.maPoint1 << "->" << rGradient .maPoint2 << ":" << rGradient.maStops.size(); ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1845" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "impldrawgradient(" << this << "): " << rPolyPolygon << ":" << rGradient.maPoint1 << "->" << rGradient.maPoint2 << ":" << rGradient .maStops.size()) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1845" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "impldrawgradient(" << this << "): " << rPolyPolygon << ":" << rGradient. maPoint1 << "->" << rGradient.maPoint2 << ":" << rGradient.maStops.size()), 0); } else { ::std:: ostringstream sal_detail_stream; sal_detail_stream << "impldrawgradient(" << this << "): " << rPolyPolygon << ":" << rGradient.maPoint1 << "->" << rGradient .maPoint2 << ":" << rGradient.maStops.size(); ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1845" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1846 | ||||
1847 | SkPath path; | |||
1848 | addPolyPolygonToPath(rPolyPolygon, path); | |||
1849 | path.setFillType(SkPathFillType::kEvenOdd); | |||
1850 | ||||
1851 | SkPoint points[2] | |||
1852 | = { SkPoint::Make(toSkX(rGradient.maPoint1.getX()), toSkY(rGradient.maPoint1.getY())), | |||
1853 | SkPoint::Make(toSkX(rGradient.maPoint2.getX()), toSkY(rGradient.maPoint2.getY())) }; | |||
1854 | std::vector<SkColor> colors; | |||
1855 | std::vector<SkScalar> pos; | |||
1856 | for (const SalGradientStop& stop : rGradient.maStops) | |||
1857 | { | |||
1858 | colors.emplace_back(toSkColor(stop.maColor)); | |||
1859 | pos.emplace_back(stop.mfOffset); | |||
1860 | } | |||
1861 | sk_sp<SkShader> shader = SkGradientShader::MakeLinear(points, colors.data(), pos.data(), | |||
1862 | colors.size(), SkTileMode::kDecal); | |||
1863 | SkPaint paint; | |||
1864 | paint.setAntiAlias(mParent.getAntiAlias()); | |||
1865 | paint.setShader(shader); | |||
1866 | getDrawCanvas()->drawPath(path, paint); | |||
1867 | addXorRegion(path.getBounds()); | |||
1868 | postDraw(); | |||
1869 | return true; | |||
1870 | } | |||
1871 | ||||
1872 | static double toRadian(int degree10th) { return (3600 - degree10th) * M_PI3.14159265358979323846 / 1800.0; } | |||
1873 | static double toCos(int degree10th) { return SkScalarCos(toRadian(degree10th))(float)cosf(toRadian(degree10th)); } | |||
1874 | static double toSin(int degree10th) { return SkScalarSin(toRadian(degree10th))(float)sinf(toRadian(degree10th)); } | |||
1875 | ||||
1876 | void SkiaSalGraphicsImpl::drawGenericLayout(const GenericSalLayout& layout, Color textColor, | |||
1877 | const SkFont& font, GlyphOrientation glyphOrientation) | |||
1878 | { | |||
1879 | SkiaZone zone; | |||
1880 | std::vector<SkGlyphID> glyphIds; | |||
1881 | std::vector<SkRSXform> glyphForms; | |||
1882 | glyphIds.reserve(256); | |||
1883 | glyphForms.reserve(256); | |||
1884 | Point aPos; | |||
1885 | const GlyphItem* pGlyph; | |||
1886 | int nStart = 0; | |||
1887 | while (layout.GetNextGlyph(&pGlyph, aPos, nStart)) | |||
1888 | { | |||
1889 | glyphIds.push_back(pGlyph->glyphId()); | |||
1890 | int angle = 0; // 10th of degree | |||
1891 | if (glyphOrientation == GlyphOrientation::Apply) | |||
1892 | { | |||
1893 | angle = layout.GetOrientation(); | |||
1894 | if (pGlyph->IsVertical()) | |||
1895 | angle += 900; // 90 degree | |||
1896 | } | |||
1897 | SkRSXform form = SkRSXform::Make(toCos(angle), toSin(angle), aPos.X(), aPos.Y()); | |||
1898 | glyphForms.emplace_back(std::move(form)); | |||
1899 | } | |||
1900 | if (glyphIds.empty()) | |||
1901 | return; | |||
1902 | sk_sp<SkTextBlob> textBlob | |||
1903 | = SkTextBlob::MakeFromRSXform(glyphIds.data(), glyphIds.size() * sizeof(SkGlyphID), | |||
1904 | glyphForms.data(), font, SkTextEncoding::kGlyphID); | |||
1905 | preDraw(); | |||
1906 | SAL_INFO("vcl.skia.trace",do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "drawtextblob(" << this << "): " << textBlob->bounds() << ":" << textColor) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1907" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "drawtextblob(" << this << "): " << textBlob->bounds() << ":" << textColor ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawtextblob(" << this << "): " << textBlob->bounds() << ":" << textColor; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1907" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "drawtextblob(" << this << "): " << textBlob->bounds() << ":" << textColor) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1907" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "drawtextblob(" << this << "): " << textBlob->bounds() << ":" << textColor ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawtextblob(" << this << "): " << textBlob->bounds() << ":" << textColor; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1907" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
1907 | "drawtextblob(" << this << "): " << textBlob->bounds() << ":" << textColor)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.skia.trace")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "drawtextblob(" << this << "): " << textBlob->bounds() << ":" << textColor) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.skia.trace"), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1907" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "drawtextblob(" << this << "): " << textBlob->bounds() << ":" << textColor ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawtextblob(" << this << "): " << textBlob->bounds() << ":" << textColor; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1907" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "drawtextblob(" << this << "): " << textBlob->bounds() << ":" << textColor) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1907" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "drawtextblob(" << this << "): " << textBlob->bounds() << ":" << textColor ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "drawtextblob(" << this << "): " << textBlob->bounds() << ":" << textColor; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.skia.trace" ), ("/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" ":" "1907" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1908 | addXorRegion(textBlob->bounds()); | |||
1909 | SkPaint paint; | |||
1910 | paint.setColor(toSkColor(textColor)); | |||
1911 | getDrawCanvas()->drawTextBlob(textBlob, 0, 0, paint); | |||
1912 | postDraw(); | |||
1913 | } | |||
1914 | ||||
1915 | bool SkiaSalGraphicsImpl::supportsOperation(OutDevSupportType eType) const | |||
1916 | { | |||
1917 | switch (eType) | |||
1918 | { | |||
1919 | case OutDevSupportType::B2DDraw: | |||
1920 | case OutDevSupportType::TransparentRect: | |||
1921 | return true; | |||
1922 | default: | |||
1923 | return false; | |||
1924 | } | |||
1925 | } | |||
1926 | ||||
1927 | #ifdef DBG_UTIL | |||
1928 | void SkiaSalGraphicsImpl::dump(const char* file) const | |||
1929 | { | |||
1930 | assert(mSurface.get())(static_cast <bool> (mSurface.get()) ? void (0) : __assert_fail ("mSurface.get()", "/home/maarten/src/libreoffice/core/vcl/skia/gdiimpl.cxx" , 1930, __extension__ __PRETTY_FUNCTION__)); | |||
1931 | SkiaHelper::dump(mSurface, file); | |||
1932 | } | |||
1933 | #endif | |||
1934 | ||||
1935 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |