1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "core/fxge/skia/fx_skia_device.h"
6
7 #include <algorithm>
8 #include <utility>
9 #include <vector>
10
11 #include "build/build_config.h"
12 #include "core/fpdfapi/page/cpdf_expintfunc.h"
13 #include "core/fpdfapi/page/cpdf_function.h"
14 #include "core/fpdfapi/page/cpdf_meshstream.h"
15 #include "core/fpdfapi/page/cpdf_sampledfunc.h"
16 #include "core/fpdfapi/page/cpdf_shadingpattern.h"
17 #include "core/fpdfapi/page/cpdf_stitchfunc.h"
18 #include "core/fpdfapi/parser/cpdf_array.h"
19 #include "core/fpdfapi/parser/cpdf_dictionary.h"
20 #include "core/fpdfapi/parser/cpdf_stream.h"
21 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
22 #include "core/fxcrt/cfx_bitstream.h"
23 #include "core/fxcrt/fx_memory_wrappers.h"
24 #include "core/fxcrt/fx_system.h"
25 #include "core/fxge/cfx_defaultrenderdevice.h"
26 #include "core/fxge/cfx_font.h"
27 #include "core/fxge/cfx_graphstatedata.h"
28 #include "core/fxge/cfx_pathdata.h"
29 #include "core/fxge/cfx_renderdevice.h"
30 #include "core/fxge/dib/cfx_bitmapcomposer.h"
31 #include "core/fxge/dib/cfx_dibitmap.h"
32 #include "core/fxge/dib/cfx_imagerenderer.h"
33 #include "core/fxge/dib/cfx_imagestretcher.h"
34 #include "core/fxge/text_char_pos.h"
35 #include "third_party/base/logging.h"
36 #include "third_party/base/ptr_util.h"
37 #include "third_party/skia/include/core/SkCanvas.h"
38 #include "third_party/skia/include/core/SkClipOp.h"
39 #include "third_party/skia/include/core/SkColorPriv.h"
40 #include "third_party/skia/include/core/SkImage.h"
41 #include "third_party/skia/include/core/SkPaint.h"
42 #include "third_party/skia/include/core/SkPath.h"
43 #include "third_party/skia/include/core/SkRSXform.h"
44 #include "third_party/skia/include/core/SkShader.h"
45 #include "third_party/skia/include/core/SkStream.h"
46 #include "third_party/skia/include/core/SkTextBlob.h"
47 #include "third_party/skia/include/core/SkTypeface.h"
48 #include "third_party/skia/include/effects/SkDashPathEffect.h"
49 #include "third_party/skia/include/effects/SkGradientShader.h"
50 #include "third_party/skia/include/pathops/SkPathOps.h"
51
52 #ifdef _SKIA_SUPPORT_PATHS_
53 #include "core/fxge/cfx_cliprgn.h"
54 #endif // _SKIA_SUPPORT_PATHS_
55
56 #ifdef _SKIA_SUPPORT_
57 #include "third_party/skia/include/core/SkColorFilter.h"
58 #include "third_party/skia/include/core/SkMaskFilter.h"
59 #include "third_party/skia/include/core/SkPictureRecorder.h"
60 #endif // _SKIA_SUPPORT_
61
62 namespace {
63
64 #ifdef _SKIA_SUPPORT_PATHS_
RgbByteOrderTransferBitmap(const RetainPtr<CFX_DIBitmap> & pBitmap,int dest_left,int dest_top,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)65 void RgbByteOrderTransferBitmap(const RetainPtr<CFX_DIBitmap>& pBitmap,
66 int dest_left,
67 int dest_top,
68 int width,
69 int height,
70 const RetainPtr<CFX_DIBBase>& pSrcBitmap,
71 int src_left,
72 int src_top) {
73 if (!pBitmap)
74 return;
75
76 if (!pBitmap->GetOverlapRect(dest_left, dest_top, width, height,
77 pSrcBitmap->GetWidth(), pSrcBitmap->GetHeight(),
78 src_left, src_top, nullptr)) {
79 return;
80 }
81
82 int Bpp = pBitmap->GetBPP() / 8;
83 FXDIB_Format dest_format = pBitmap->GetFormat();
84 FXDIB_Format src_format = pSrcBitmap->GetFormat();
85 int pitch = pBitmap->GetPitch();
86 uint8_t* buffer = pBitmap->GetBuffer();
87 if (dest_format == src_format) {
88 for (int row = 0; row < height; row++) {
89 uint8_t* dest_scan = buffer + (dest_top + row) * pitch + dest_left * Bpp;
90 const uint8_t* src_scan =
91 pSrcBitmap->GetScanline(src_top + row) + src_left * Bpp;
92 if (Bpp == 4) {
93 for (int col = 0; col < width; col++) {
94 FXARGB_SETDIB(dest_scan, ArgbEncode(src_scan[3], src_scan[0],
95 src_scan[1], src_scan[2]));
96 dest_scan += 4;
97 src_scan += 4;
98 }
99 } else {
100 for (int col = 0; col < width; col++) {
101 *dest_scan++ = src_scan[2];
102 *dest_scan++ = src_scan[1];
103 *dest_scan++ = src_scan[0];
104 src_scan += 3;
105 }
106 }
107 }
108 return;
109 }
110
111 uint8_t* dest_buf = buffer + dest_top * pitch + dest_left * Bpp;
112 if (dest_format == FXDIB_Rgb) {
113 if (src_format == FXDIB_Rgb32) {
114 for (int row = 0; row < height; row++) {
115 uint8_t* dest_scan = dest_buf + row * pitch;
116 const uint8_t* src_scan =
117 pSrcBitmap->GetScanline(src_top + row) + src_left * 4;
118 for (int col = 0; col < width; col++) {
119 *dest_scan++ = src_scan[2];
120 *dest_scan++ = src_scan[1];
121 *dest_scan++ = src_scan[0];
122 src_scan += 4;
123 }
124 }
125 } else {
126 NOTREACHED();
127 }
128 return;
129 }
130
131 if (dest_format == FXDIB_Argb || dest_format == FXDIB_Rgb32) {
132 if (src_format == FXDIB_Rgb) {
133 for (int row = 0; row < height; row++) {
134 uint8_t* dest_scan = (uint8_t*)(dest_buf + row * pitch);
135 const uint8_t* src_scan =
136 pSrcBitmap->GetScanline(src_top + row) + src_left * 3;
137 for (int col = 0; col < width; col++) {
138 FXARGB_SETDIB(dest_scan, ArgbEncode(0xff, src_scan[0], src_scan[1],
139 src_scan[2]));
140 dest_scan += 4;
141 src_scan += 3;
142 }
143 }
144 } else if (src_format == FXDIB_Rgb32) {
145 ASSERT(dest_format == FXDIB_Argb);
146 for (int row = 0; row < height; row++) {
147 uint8_t* dest_scan = dest_buf + row * pitch;
148 const uint8_t* src_scan =
149 pSrcBitmap->GetScanline(src_top + row) + src_left * 4;
150 for (int col = 0; col < width; col++) {
151 FXARGB_SETDIB(dest_scan, ArgbEncode(0xff, src_scan[0], src_scan[1],
152 src_scan[2]));
153 src_scan += 4;
154 dest_scan += 4;
155 }
156 }
157 }
158 return;
159 }
160
161 NOTREACHED();
162 }
163
164 #endif // _SKIA_SUPPORT_PATHS_
165
166 #define SHOW_SKIA_PATH 0 // set to 1 to print the path contents
167 #if SHOW_SKIA_PATH
168 #define SHOW_SKIA_PATH_SHORTHAND 0 // set to 1 for abbreviated path contents
169 #endif
170 #define DRAW_SKIA_CLIP 0 // set to 1 to draw a green rectangle around the clip
171 #define SHOW_TEXT_GLYPHS 0 // set to 1 to print unichar equivalent of glyph
172
173 #if SHOW_SKIA_PATH
DebugShowSkiaPaint(const SkPaint & paint)174 void DebugShowSkiaPaint(const SkPaint& paint) {
175 if (SkPaint::kFill_Style == paint.getStyle()) {
176 printf("fill 0x%08x\n", paint.getColor());
177 } else {
178 printf("stroke 0x%08x width %g\n", paint.getColor(),
179 paint.getStrokeWidth());
180 }
181 }
182 #endif // SHOW_SKIA_PATH
183
DebugShowSkiaPath(const SkPath & path)184 void DebugShowSkiaPath(const SkPath& path) {
185 #if SHOW_SKIA_PATH
186 #if SHOW_SKIA_PATH_SHORTHAND
187 printf(" **\n");
188 #else
189 SkDynamicMemoryWStream stream;
190 path.dump(&stream, false, false);
191 std::unique_ptr<char, FxFreeDeleter> storage;
192 storage.reset(FX_Alloc(char, stream.bytesWritten()));
193 stream.copyTo(storage.get());
194 printf("%.*s", (int)stream.bytesWritten(), storage.get());
195 #endif // SHOW_SKIA_PATH_SHORTHAND
196 #endif // SHOW_SKIA_PATH
197 }
198
DebugShowCanvasClip(CFX_SkiaDeviceDriver * driver,const SkCanvas * canvas)199 void DebugShowCanvasClip(CFX_SkiaDeviceDriver* driver, const SkCanvas* canvas) {
200 #if SHOW_SKIA_PATH
201 SkMatrix matrix = canvas->getTotalMatrix();
202 SkScalar m[9];
203 matrix.get9(m);
204 printf("matrix (%g,%g,%g) (%g,%g,%g) (%g,%g,%g)\n", m[0], m[1], m[2], m[3],
205 m[4], m[5], m[6], m[7], m[8]);
206 SkRect local = canvas->getLocalClipBounds();
207 SkIRect device = canvas->getDeviceClipBounds();
208
209 printf("local bounds %g %g %g %g\n", local.fLeft, local.fTop, local.fRight,
210 local.fBottom);
211 printf("device bounds %d %d %d %d\n", device.fLeft, device.fTop,
212 device.fRight, device.fBottom);
213 FX_RECT clipBox;
214 driver->GetClipBox(&clipBox);
215 printf("reported bounds %d %d %d %d\n", clipBox.left, clipBox.top,
216 clipBox.right, clipBox.bottom);
217 #endif // SHOW_SKIA_PATH
218 }
219
DebugShowSkiaDrawPath(CFX_SkiaDeviceDriver * driver,const SkCanvas * canvas,const SkPaint & paint,const SkPath & path)220 void DebugShowSkiaDrawPath(CFX_SkiaDeviceDriver* driver,
221 const SkCanvas* canvas,
222 const SkPaint& paint,
223 const SkPath& path) {
224 #if SHOW_SKIA_PATH
225 DebugShowSkiaPaint(paint);
226 DebugShowCanvasClip(driver, canvas);
227 DebugShowSkiaPath(path);
228 printf("\n");
229 #endif // SHOW_SKIA_PATH
230 }
231
DebugShowSkiaDrawRect(CFX_SkiaDeviceDriver * driver,const SkCanvas * canvas,const SkPaint & paint,const SkRect & rect)232 void DebugShowSkiaDrawRect(CFX_SkiaDeviceDriver* driver,
233 const SkCanvas* canvas,
234 const SkPaint& paint,
235 const SkRect& rect) {
236 #if SHOW_SKIA_PATH
237 DebugShowSkiaPaint(paint);
238 DebugShowCanvasClip(driver, canvas);
239 printf("rect %g %g %g %g\n", rect.fLeft, rect.fTop, rect.fRight,
240 rect.fBottom);
241 #endif // SHOW_SKIA_PATH
242 }
243
244 #if DRAW_SKIA_CLIP
245
DebugClipPaint()246 SkPaint DebugClipPaint() {
247 SkPaint paint;
248 paint.setAntiAlias(true);
249 paint.setColor(SK_ColorGREEN);
250 paint.setStyle(SkPaint::kStroke_Style);
251 return paint;
252 }
253
DebugDrawSkiaClipRect(SkCanvas * canvas,const SkRect & rect)254 void DebugDrawSkiaClipRect(SkCanvas* canvas, const SkRect& rect) {
255 SkPaint paint = DebugClipPaint();
256 canvas->drawRect(rect, paint);
257 }
258
DebugDrawSkiaClipPath(SkCanvas * canvas,const SkPath & path)259 void DebugDrawSkiaClipPath(SkCanvas* canvas, const SkPath& path) {
260 SkPaint paint = DebugClipPaint();
261 canvas->drawPath(path, paint);
262 }
263
264 #else // DRAW_SKIA_CLIP
265
DebugDrawSkiaClipRect(SkCanvas * canvas,const SkRect & rect)266 void DebugDrawSkiaClipRect(SkCanvas* canvas, const SkRect& rect) {}
267
DebugDrawSkiaClipPath(SkCanvas * canvas,const SkPath & path)268 void DebugDrawSkiaClipPath(SkCanvas* canvas, const SkPath& path) {}
269
270 #endif // DRAW_SKIA_CLIP
271
272 #ifdef _SKIA_SUPPORT_
DebugValidate(const RetainPtr<CFX_DIBitmap> & bitmap,const RetainPtr<CFX_DIBitmap> & device)273 static void DebugValidate(const RetainPtr<CFX_DIBitmap>& bitmap,
274 const RetainPtr<CFX_DIBitmap>& device) {
275 if (bitmap) {
276 ASSERT(bitmap->GetBPP() == 8 || bitmap->GetBPP() == 32);
277 if (bitmap->GetBPP() == 32) {
278 bitmap->DebugVerifyBitmapIsPreMultiplied(nullptr);
279 }
280 }
281 if (device) {
282 ASSERT(device->GetBPP() == 8 || device->GetBPP() == 32);
283 if (device->GetBPP() == 32) {
284 device->DebugVerifyBitmapIsPreMultiplied(nullptr);
285 }
286 }
287 }
288 #endif // _SKIA_SUPPORT_
289
290 constexpr int kAlternateOrWindingFillModeMask =
291 FXFILL_ALTERNATE | FXFILL_WINDING;
292
GetAlternateOrWindingFillMode(int fill_mode)293 int GetAlternateOrWindingFillMode(int fill_mode) {
294 return fill_mode & kAlternateOrWindingFillModeMask;
295 }
296
IsAlternateFillMode(int fill_mode)297 bool IsAlternateFillMode(int fill_mode) {
298 // TODO(thestig): This function should be able to assert
299 // GetAlternateOrWindingFillMode(fill_mode) != 0.
300 return GetAlternateOrWindingFillMode(fill_mode) == FXFILL_ALTERNATE;
301 }
302
GetAlternateOrWindingFillType(int fill_mode)303 SkPathFillType GetAlternateOrWindingFillType(int fill_mode) {
304 return IsAlternateFillMode(fill_mode) ? SkPathFillType::kEvenOdd
305 : SkPathFillType::kWinding;
306 }
307
IsEvenOddFillType(SkPathFillType fill)308 bool IsEvenOddFillType(SkPathFillType fill) {
309 return fill == SkPathFillType::kEvenOdd ||
310 fill == SkPathFillType::kInverseEvenOdd;
311 }
312
BuildPath(const CFX_PathData * pPathData)313 SkPath BuildPath(const CFX_PathData* pPathData) {
314 SkPath skPath;
315 const CFX_PathData* pFPath = pPathData;
316 const std::vector<FX_PATHPOINT>& pPoints = pFPath->GetPoints();
317 for (size_t i = 0; i < pPoints.size(); i++) {
318 CFX_PointF point = pPoints[i].m_Point;
319 FXPT_TYPE point_type = pPoints[i].m_Type;
320 if (point_type == FXPT_TYPE::MoveTo) {
321 skPath.moveTo(point.x, point.y);
322 } else if (point_type == FXPT_TYPE::LineTo) {
323 skPath.lineTo(point.x, point.y);
324 } else if (point_type == FXPT_TYPE::BezierTo) {
325 CFX_PointF point2 = pPoints[i + 1].m_Point;
326 CFX_PointF point3 = pPoints[i + 2].m_Point;
327 skPath.cubicTo(point.x, point.y, point2.x, point2.y, point3.x, point3.y);
328 i += 2;
329 }
330 if (pPoints[i].m_CloseFigure)
331 skPath.close();
332 }
333 return skPath;
334 }
335
ToSkMatrix(const CFX_Matrix & m)336 SkMatrix ToSkMatrix(const CFX_Matrix& m) {
337 SkMatrix skMatrix;
338 skMatrix.setAll(m.a, m.c, m.e, m.b, m.d, m.f, 0, 0, 1);
339 return skMatrix;
340 }
341
342 // use when pdf's y-axis points up instead of down
ToFlippedSkMatrix(const CFX_Matrix & m,SkScalar flip)343 SkMatrix ToFlippedSkMatrix(const CFX_Matrix& m, SkScalar flip) {
344 SkMatrix skMatrix;
345 skMatrix.setAll(m.a * flip, -m.c * flip, m.e, m.b * flip, -m.d * flip, m.f, 0,
346 0, 1);
347 return skMatrix;
348 }
349
GetSkiaBlendMode(BlendMode blend_type)350 SkBlendMode GetSkiaBlendMode(BlendMode blend_type) {
351 switch (blend_type) {
352 case BlendMode::kMultiply:
353 return SkBlendMode::kMultiply;
354 case BlendMode::kScreen:
355 return SkBlendMode::kScreen;
356 case BlendMode::kOverlay:
357 return SkBlendMode::kOverlay;
358 case BlendMode::kDarken:
359 return SkBlendMode::kDarken;
360 case BlendMode::kLighten:
361 return SkBlendMode::kLighten;
362 case BlendMode::kColorDodge:
363 return SkBlendMode::kColorDodge;
364 case BlendMode::kColorBurn:
365 return SkBlendMode::kColorBurn;
366 case BlendMode::kHardLight:
367 return SkBlendMode::kHardLight;
368 case BlendMode::kSoftLight:
369 return SkBlendMode::kSoftLight;
370 case BlendMode::kDifference:
371 return SkBlendMode::kDifference;
372 case BlendMode::kExclusion:
373 return SkBlendMode::kExclusion;
374 case BlendMode::kHue:
375 return SkBlendMode::kHue;
376 case BlendMode::kSaturation:
377 return SkBlendMode::kSaturation;
378 case BlendMode::kColor:
379 return SkBlendMode::kColor;
380 case BlendMode::kLuminosity:
381 return SkBlendMode::kLuminosity;
382 case BlendMode::kNormal:
383 default:
384 return SkBlendMode::kSrcOver;
385 }
386 }
387
388 // Add begin & end colors into |skColors| array for each gradient transition.
389 //
390 // |is_encode_reversed| must be set to true when the parent function of |pFunc|
391 // has an Encode array, and the matching pair of encode values for |pFunc| are
392 // in decreasing order.
AddColors(const CPDF_ExpIntFunc * pFunc,SkTDArray<SkColor> * skColors,bool is_encode_reversed)393 bool AddColors(const CPDF_ExpIntFunc* pFunc,
394 SkTDArray<SkColor>* skColors,
395 bool is_encode_reversed) {
396 if (pFunc->CountInputs() != 1)
397 return false;
398 if (pFunc->m_Exponent != 1)
399 return false;
400 if (pFunc->m_nOrigOutputs != 3)
401 return false;
402
403 auto begin_values = pFunc->m_BeginValues.begin();
404 auto end_values = pFunc->m_EndValues.begin();
405 if (is_encode_reversed)
406 std::swap(begin_values, end_values);
407
408 skColors->push_back(SkColorSetARGB(0xFF,
409 SkUnitScalarClampToByte(begin_values[0]),
410 SkUnitScalarClampToByte(begin_values[1]),
411 SkUnitScalarClampToByte(begin_values[2])));
412 skColors->push_back(SkColorSetARGB(0xFF,
413 SkUnitScalarClampToByte(end_values[0]),
414 SkUnitScalarClampToByte(end_values[1]),
415 SkUnitScalarClampToByte(end_values[2])));
416 return true;
417 }
418
FloatToByte(float f)419 uint8_t FloatToByte(float f) {
420 ASSERT(f >= 0);
421 ASSERT(f <= 1);
422 return (uint8_t)(f * 255.99f);
423 }
424
AddSamples(const CPDF_SampledFunc * pFunc,SkTDArray<SkColor> * skColors,SkTDArray<SkScalar> * skPos)425 bool AddSamples(const CPDF_SampledFunc* pFunc,
426 SkTDArray<SkColor>* skColors,
427 SkTDArray<SkScalar>* skPos) {
428 if (pFunc->CountInputs() != 1)
429 return false;
430 if (pFunc->CountOutputs() != 3) // expect rgb
431 return false;
432 if (pFunc->GetEncodeInfo().empty())
433 return false;
434 const CPDF_SampledFunc::SampleEncodeInfo& encodeInfo =
435 pFunc->GetEncodeInfo()[0];
436 if (encodeInfo.encode_min != 0)
437 return false;
438 if (encodeInfo.encode_max != encodeInfo.sizes - 1)
439 return false;
440 uint32_t sampleSize = pFunc->GetBitsPerSample();
441 uint32_t sampleCount = encodeInfo.sizes;
442 if (sampleCount != 1U << sampleSize)
443 return false;
444 if (pFunc->GetSampleStream()->GetSize() < sampleCount * 3 * sampleSize / 8)
445 return false;
446
447 float colorsMin[3];
448 float colorsMax[3];
449 for (int i = 0; i < 3; ++i) {
450 colorsMin[i] = pFunc->GetRange(i * 2);
451 colorsMax[i] = pFunc->GetRange(i * 2 + 1);
452 }
453 pdfium::span<const uint8_t> pSampleData = pFunc->GetSampleStream()->GetSpan();
454 CFX_BitStream bitstream(pSampleData);
455 for (uint32_t i = 0; i < sampleCount; ++i) {
456 float floatColors[3];
457 for (uint32_t j = 0; j < 3; ++j) {
458 float sample = static_cast<float>(bitstream.GetBits(sampleSize));
459 float interp = sample / (sampleCount - 1);
460 floatColors[j] = colorsMin[j] + (colorsMax[j] - colorsMin[j]) * interp;
461 }
462 SkColor color =
463 SkPackARGB32(0xFF, FloatToByte(floatColors[0]),
464 FloatToByte(floatColors[1]), FloatToByte(floatColors[2]));
465 skColors->push_back(color);
466 skPos->push_back((float)i / (sampleCount - 1));
467 }
468 return true;
469 }
470
AddStitching(const CPDF_StitchFunc * pFunc,SkTDArray<SkColor> * skColors,SkTDArray<SkScalar> * skPos)471 bool AddStitching(const CPDF_StitchFunc* pFunc,
472 SkTDArray<SkColor>* skColors,
473 SkTDArray<SkScalar>* skPos) {
474 float boundsStart = pFunc->GetDomain(0);
475
476 const auto& subFunctions = pFunc->GetSubFunctions();
477 int subFunctionCount = subFunctions.size();
478 for (int i = 0; i < subFunctionCount; ++i) {
479 const CPDF_ExpIntFunc* pSubFunc = subFunctions[i]->ToExpIntFunc();
480 if (!pSubFunc)
481 return false;
482 // Check if the matching encode values are reversed
483 bool is_encode_reversed =
484 pFunc->GetEncode(2 * i) > pFunc->GetEncode(2 * i + 1);
485 if (!AddColors(pSubFunc, skColors, is_encode_reversed))
486 return false;
487 float boundsEnd =
488 i < subFunctionCount - 1 ? pFunc->GetBound(i + 1) : pFunc->GetDomain(1);
489 skPos->push_back(boundsStart);
490 skPos->push_back(boundsEnd);
491 boundsStart = boundsEnd;
492 }
493 return true;
494 }
495
496 // see https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
LineSide(const SkPoint line[2],const SkPoint & pt)497 SkScalar LineSide(const SkPoint line[2], const SkPoint& pt) {
498 return (line[1].fY - line[0].fY) * pt.fX - (line[1].fX - line[0].fX) * pt.fY +
499 line[1].fX * line[0].fY - line[1].fY * line[0].fX;
500 }
501
IntersectSides(const SkPoint & parallelPt,const SkVector & paraRay,const SkPoint & perpendicularPt)502 SkPoint IntersectSides(const SkPoint& parallelPt,
503 const SkVector& paraRay,
504 const SkPoint& perpendicularPt) {
505 SkVector perpRay = {paraRay.fY, -paraRay.fX};
506 SkScalar denom = perpRay.fY * paraRay.fX - paraRay.fY * perpRay.fX;
507 if (!denom) {
508 SkPoint zeroPt = {0, 0};
509 return zeroPt;
510 }
511 SkVector ab0 = parallelPt - perpendicularPt;
512 SkScalar numerA = ab0.fY * perpRay.fX - perpRay.fY * ab0.fX;
513 numerA /= denom;
514 SkPoint result = {parallelPt.fX + paraRay.fX * numerA,
515 parallelPt.fY + paraRay.fY * numerA};
516 return result;
517 }
518
ClipAngledGradient(const SkPoint pts[2],SkPoint rectPts[4],bool clipStart,bool clipEnd,SkPath * clip)519 void ClipAngledGradient(const SkPoint pts[2],
520 SkPoint rectPts[4],
521 bool clipStart,
522 bool clipEnd,
523 SkPath* clip) {
524 // find the corners furthest from the gradient perpendiculars
525 SkScalar minPerpDist = SK_ScalarMax;
526 SkScalar maxPerpDist = SK_ScalarMin;
527 int minPerpPtIndex = -1;
528 int maxPerpPtIndex = -1;
529 SkVector slope = pts[1] - pts[0];
530 SkPoint startPerp[2] = {pts[0], {pts[0].fX + slope.fY, pts[0].fY - slope.fX}};
531 SkPoint endPerp[2] = {pts[1], {pts[1].fX + slope.fY, pts[1].fY - slope.fX}};
532 for (int i = 0; i < 4; ++i) {
533 SkScalar sDist = LineSide(startPerp, rectPts[i]);
534 SkScalar eDist = LineSide(endPerp, rectPts[i]);
535 if (sDist * eDist <= 0) // if the signs are different,
536 continue; // the point is inside the gradient
537 if (sDist < 0) {
538 SkScalar smaller = SkTMin(sDist, eDist);
539 if (minPerpDist > smaller) {
540 minPerpDist = smaller;
541 minPerpPtIndex = i;
542 }
543 } else {
544 SkScalar larger = SkTMax(sDist, eDist);
545 if (maxPerpDist < larger) {
546 maxPerpDist = larger;
547 maxPerpPtIndex = i;
548 }
549 }
550 }
551 if (minPerpPtIndex < 0 && maxPerpPtIndex < 0) // nothing's outside
552 return;
553
554 // determine if negative distances are before start or after end
555 SkPoint beforeStart = {pts[0].fX * 2 - pts[1].fX, pts[0].fY * 2 - pts[1].fY};
556 bool beforeNeg = LineSide(startPerp, beforeStart) < 0;
557
558 int noClipStartIndex = maxPerpPtIndex;
559 int noClipEndIndex = minPerpPtIndex;
560 if (beforeNeg)
561 std::swap(noClipStartIndex, noClipEndIndex);
562 if ((!clipStart && noClipStartIndex < 0) ||
563 (!clipEnd && noClipEndIndex < 0)) {
564 return;
565 }
566
567 const SkPoint& startEdgePt = clipStart ? pts[0] : rectPts[noClipStartIndex];
568 const SkPoint& endEdgePt = clipEnd ? pts[1] : rectPts[noClipEndIndex];
569
570 // find the corners that bound the gradient
571 SkScalar minDist = SK_ScalarMax;
572 SkScalar maxDist = SK_ScalarMin;
573 int minBounds = -1;
574 int maxBounds = -1;
575 for (int i = 0; i < 4; ++i) {
576 SkScalar dist = LineSide(pts, rectPts[i]);
577 if (minDist > dist) {
578 minDist = dist;
579 minBounds = i;
580 }
581 if (maxDist < dist) {
582 maxDist = dist;
583 maxBounds = i;
584 }
585 }
586 if (minBounds < 0 || maxBounds < 0)
587 return;
588 if (minBounds == maxBounds)
589 return;
590 // construct a clip parallel to the gradient that goes through
591 // rectPts[minBounds] and rectPts[maxBounds] and perpendicular to the
592 // gradient that goes through startEdgePt, endEdgePt.
593 clip->moveTo(IntersectSides(rectPts[minBounds], slope, startEdgePt));
594 clip->lineTo(IntersectSides(rectPts[minBounds], slope, endEdgePt));
595 clip->lineTo(IntersectSides(rectPts[maxBounds], slope, endEdgePt));
596 clip->lineTo(IntersectSides(rectPts[maxBounds], slope, startEdgePt));
597 }
598
599 #ifdef _SKIA_SUPPORT_
SetBitmapMatrix(const CFX_Matrix & m,int width,int height,SkMatrix * skMatrix)600 void SetBitmapMatrix(const CFX_Matrix& m,
601 int width,
602 int height,
603 SkMatrix* skMatrix) {
604 skMatrix->setAll(m.a / width, -m.c / height, m.c + m.e, m.b / width,
605 -m.d / height, m.d + m.f, 0, 0, 1);
606 }
607
SetBitmapPaint(bool isAlphaMask,uint32_t argb,int bitmap_alpha,BlendMode blend_type,SkPaint * paint)608 void SetBitmapPaint(bool isAlphaMask,
609 uint32_t argb,
610 int bitmap_alpha,
611 BlendMode blend_type,
612 SkPaint* paint) {
613 paint->setAntiAlias(true);
614 if (isAlphaMask)
615 paint->setColorFilter(SkColorFilters::Blend(argb, SkBlendMode::kSrc));
616
617 // paint->setFilterQuality(kHigh_SkFilterQuality);
618 paint->setBlendMode(GetSkiaBlendMode(blend_type));
619 paint->setAlpha(bitmap_alpha);
620 }
621
Upsample(const RetainPtr<CFX_DIBBase> & pSource,std::unique_ptr<uint8_t,FxFreeDeleter> & dst8Storage,std::unique_ptr<uint32_t,FxFreeDeleter> & dst32Storage,SkBitmap * skBitmap,int * widthPtr,int * heightPtr,bool forceAlpha)622 bool Upsample(const RetainPtr<CFX_DIBBase>& pSource,
623 std::unique_ptr<uint8_t, FxFreeDeleter>& dst8Storage,
624 std::unique_ptr<uint32_t, FxFreeDeleter>& dst32Storage,
625 SkBitmap* skBitmap,
626 int* widthPtr,
627 int* heightPtr,
628 bool forceAlpha) {
629 void* buffer = pSource->GetBuffer();
630 if (!buffer)
631 return false;
632 SkColorType colorType = forceAlpha || pSource->IsAlphaMask()
633 ? SkColorType::kAlpha_8_SkColorType
634 : SkColorType::kGray_8_SkColorType;
635 SkAlphaType alphaType =
636 pSource->IsAlphaMask() ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
637 int width = pSource->GetWidth();
638 int height = pSource->GetHeight();
639 int rowBytes = pSource->GetPitch();
640 switch (pSource->GetBPP()) {
641 case 1: {
642 dst8Storage.reset(FX_Alloc2D(uint8_t, width, height));
643 uint8_t* dst8Pixels = dst8Storage.get();
644 for (int y = 0; y < height; ++y) {
645 const uint8_t* srcRow =
646 static_cast<const uint8_t*>(buffer) + y * rowBytes;
647 uint8_t* dstRow = dst8Pixels + y * width;
648 for (int x = 0; x < width; ++x)
649 dstRow[x] = srcRow[x >> 3] & (1 << (~x & 0x07)) ? 0xFF : 0x00;
650 }
651 buffer = dst8Storage.get();
652 rowBytes = width;
653 break;
654 }
655 case 8:
656 // we upscale ctables to 32bit.
657 if (pSource->GetPalette()) {
658 dst32Storage.reset(FX_Alloc2D(uint32_t, width, height));
659 SkPMColor* dst32Pixels = dst32Storage.get();
660 const SkPMColor* ctable = pSource->GetPalette();
661 const unsigned ctableSize = pSource->GetPaletteSize();
662 for (int y = 0; y < height; ++y) {
663 const uint8_t* srcRow =
664 static_cast<const uint8_t*>(buffer) + y * rowBytes;
665 uint32_t* dstRow = dst32Pixels + y * width;
666 for (int x = 0; x < width; ++x) {
667 unsigned index = srcRow[x];
668 if (index >= ctableSize) {
669 index = 0;
670 }
671 dstRow[x] = ctable[index];
672 }
673 }
674 buffer = dst32Storage.get();
675 rowBytes = width * sizeof(uint32_t);
676 colorType = SkColorType::kN32_SkColorType;
677 }
678 break;
679 case 24: {
680 dst32Storage.reset(FX_Alloc2D(uint32_t, width, height));
681 uint32_t* dst32Pixels = dst32Storage.get();
682 for (int y = 0; y < height; ++y) {
683 const uint8_t* srcRow =
684 static_cast<const uint8_t*>(buffer) + y * rowBytes;
685 uint32_t* dstRow = dst32Pixels + y * width;
686 for (int x = 0; x < width; ++x) {
687 dstRow[x] = SkPackARGB32(0xFF, srcRow[x * 3 + 2], srcRow[x * 3 + 1],
688 srcRow[x * 3 + 0]);
689 }
690 }
691 buffer = dst32Storage.get();
692 rowBytes = width * sizeof(uint32_t);
693 colorType = SkColorType::kN32_SkColorType;
694 alphaType = kOpaque_SkAlphaType;
695 break;
696 }
697 case 32:
698 colorType = SkColorType::kN32_SkColorType;
699 alphaType = kPremul_SkAlphaType;
700 pSource->DebugVerifyBitmapIsPreMultiplied(buffer);
701 break;
702 default:
703 NOTREACHED(); // TODO(bug_11) ensure that all cases are covered
704 colorType = SkColorType::kUnknown_SkColorType;
705 }
706 SkImageInfo imageInfo =
707 SkImageInfo::Make(width, height, colorType, alphaType);
708 skBitmap->installPixels(imageInfo, buffer, rowBytes);
709 *widthPtr = width;
710 *heightPtr = height;
711 return true;
712 }
713 #endif // _SKIA_SUPPORT_
714
715 } // namespace
716
717 // Encapsulate the state used for successive text and path draws so that
718 // they can be combined.
719 class SkiaState {
720 public:
721 enum class Clip {
722 kSave,
723 kPath,
724 };
725
726 enum class Accumulator {
727 kNone,
728 kPath,
729 kText,
730 kOther,
731 };
732
733 // mark all cached state as uninitialized
SkiaState(CFX_SkiaDeviceDriver * pDriver)734 explicit SkiaState(CFX_SkiaDeviceDriver* pDriver) : m_pDriver(pDriver) {}
735
DrawPath(const CFX_PathData * pPathData,const CFX_Matrix * pMatrix,const CFX_GraphStateData * pDrawState,uint32_t fill_color,uint32_t stroke_color,int fill_mode,BlendMode blend_type)736 bool DrawPath(const CFX_PathData* pPathData,
737 const CFX_Matrix* pMatrix,
738 const CFX_GraphStateData* pDrawState,
739 uint32_t fill_color,
740 uint32_t stroke_color,
741 int fill_mode,
742 BlendMode blend_type) {
743 if (m_debugDisable)
744 return false;
745 Dump(__func__);
746 int drawIndex = SkTMin(m_drawIndex, m_commands.count());
747 if (Accumulator::kText == m_type || drawIndex != m_commandIndex ||
748 (Accumulator::kPath == m_type &&
749 DrawChanged(pMatrix, pDrawState, fill_color, stroke_color, fill_mode,
750 blend_type, m_pDriver->GetGroupKnockout()))) {
751 Flush();
752 }
753 if (Accumulator::kPath != m_type) {
754 m_skPath.reset();
755 m_fillFullCover = !!(fill_mode & FXFILL_FULLCOVER);
756 m_fillPath = GetAlternateOrWindingFillMode(fill_mode) && fill_color;
757 m_skPath.setFillType(GetAlternateOrWindingFillType(fill_mode));
758 if (pDrawState)
759 m_drawState = *pDrawState;
760 m_fillColor = fill_color;
761 m_strokeColor = stroke_color;
762 m_blendType = blend_type;
763 m_groupKnockout = m_pDriver->GetGroupKnockout();
764 if (pMatrix)
765 m_drawMatrix = *pMatrix;
766 m_drawIndex = m_commandIndex;
767 m_type = Accumulator::kPath;
768 }
769 SkPath skPath = BuildPath(pPathData);
770 SkPoint delta;
771 if (MatrixOffset(pMatrix, &delta))
772 skPath.offset(delta.fX, delta.fY);
773 m_skPath.addPath(skPath);
774 return true;
775 }
776
FlushPath()777 void FlushPath() {
778 Dump(__func__);
779 SkMatrix skMatrix = ToSkMatrix(m_drawMatrix);
780 SkPaint skPaint;
781 skPaint.setAntiAlias(true);
782 if (m_fillFullCover)
783 skPaint.setBlendMode(SkBlendMode::kPlus);
784 int stroke_alpha = FXARGB_A(m_strokeColor);
785 if (stroke_alpha)
786 m_pDriver->PaintStroke(&skPaint, &m_drawState, skMatrix);
787 SkCanvas* skCanvas = m_pDriver->SkiaCanvas();
788 SkAutoCanvasRestore scoped_save_restore(skCanvas, /*doSave=*/true);
789 skCanvas->concat(skMatrix);
790 bool do_stroke = true;
791 if (m_fillPath) {
792 SkPath strokePath;
793 const SkPath* fillPath = &m_skPath;
794 if (stroke_alpha) {
795 if (m_groupKnockout) {
796 skPaint.getFillPath(m_skPath, &strokePath);
797 if (m_strokeColor == m_fillColor &&
798 Op(m_skPath, strokePath, SkPathOp::kUnion_SkPathOp,
799 &strokePath)) {
800 fillPath = &strokePath;
801 do_stroke = false;
802 } else if (Op(m_skPath, strokePath, SkPathOp::kDifference_SkPathOp,
803 &strokePath)) {
804 fillPath = &strokePath;
805 }
806 }
807 }
808 skPaint.setStyle(SkPaint::kFill_Style);
809 skPaint.setColor(m_fillColor);
810 #ifdef _SKIA_SUPPORT_PATHS_
811 m_pDriver->PreMultiply();
812 #endif // _SKIA_SUPPORT_PATHS_
813 DebugShowSkiaDrawPath(m_pDriver.Get(), skCanvas, skPaint, *fillPath);
814 skCanvas->drawPath(*fillPath, skPaint);
815 }
816 if (stroke_alpha && do_stroke) {
817 skPaint.setStyle(SkPaint::kStroke_Style);
818 skPaint.setColor(m_strokeColor);
819 #ifdef _SKIA_SUPPORT_PATHS_
820 m_pDriver->PreMultiply();
821 #endif // _SKIA_SUPPORT_PATHS_
822 DebugShowSkiaDrawPath(m_pDriver.Get(), skCanvas, skPaint, m_skPath);
823 skCanvas->drawPath(m_skPath, skPaint);
824 }
825 m_drawIndex = INT_MAX;
826 m_type = Accumulator::kNone;
827 m_drawMatrix = CFX_Matrix();
828 }
829
HasRSX(int nChars,const TextCharPos * pCharPos,float * scaleXPtr,bool * oneAtATimePtr) const830 bool HasRSX(int nChars,
831 const TextCharPos* pCharPos,
832 float* scaleXPtr,
833 bool* oneAtATimePtr) const {
834 bool useRSXform = false;
835 bool oneAtATime = false;
836 float scaleX = 1;
837 for (int index = 0; index < nChars; ++index) {
838 const TextCharPos& cp = pCharPos[index];
839 if (!cp.m_bGlyphAdjust)
840 continue;
841 bool upright = 0 == cp.m_AdjustMatrix[1] && 0 == cp.m_AdjustMatrix[2];
842 if (cp.m_AdjustMatrix[0] != cp.m_AdjustMatrix[3]) {
843 if (upright && 1 == cp.m_AdjustMatrix[3]) {
844 if (1 == scaleX)
845 scaleX = cp.m_AdjustMatrix[0];
846 else if (scaleX != cp.m_AdjustMatrix[0])
847 oneAtATime = true;
848 } else {
849 oneAtATime = true;
850 }
851 } else if (cp.m_AdjustMatrix[1] != -cp.m_AdjustMatrix[2]) {
852 oneAtATime = true;
853 } else {
854 useRSXform = true;
855 }
856 }
857 *oneAtATimePtr = oneAtATime;
858 *scaleXPtr = oneAtATime ? 1 : scaleX;
859 return oneAtATime ? false : useRSXform;
860 }
861
DrawText(int nChars,const TextCharPos * pCharPos,CFX_Font * pFont,const CFX_Matrix & matrix,float font_size,uint32_t color)862 bool DrawText(int nChars,
863 const TextCharPos* pCharPos,
864 CFX_Font* pFont,
865 const CFX_Matrix& matrix,
866 float font_size,
867 uint32_t color) {
868 if (m_debugDisable)
869 return false;
870 Dump(__func__);
871 float scaleX = 1;
872 bool oneAtATime = false;
873 bool hasRSX = HasRSX(nChars, pCharPos, &scaleX, &oneAtATime);
874 if (oneAtATime) {
875 Flush();
876 return false;
877 }
878 int drawIndex = SkTMin(m_drawIndex, m_commands.count());
879 if (Accumulator::kPath == m_type || drawIndex != m_commandIndex ||
880 (Accumulator::kText == m_type &&
881 (FontChanged(pFont, matrix, font_size, scaleX, color) ||
882 hasRSX == m_rsxform.isEmpty()))) {
883 Flush();
884 }
885 if (Accumulator::kText != m_type) {
886 m_italicAngle = pFont->GetSubstFontItalicAngle();
887 m_charDetails.SetCount(0);
888 m_rsxform.setCount(0);
889 if (pFont->GetFaceRec())
890 m_pTypeFace.reset(SkSafeRef(pFont->GetDeviceCache()));
891 else
892 m_pTypeFace.reset();
893 m_fontSize = font_size;
894 m_scaleX = scaleX;
895 m_fillColor = color;
896 m_drawMatrix = matrix;
897 m_drawIndex = m_commandIndex;
898 m_type = Accumulator::kText;
899 m_pFont = pFont;
900 }
901 if (!hasRSX && !m_rsxform.isEmpty())
902 FlushText();
903
904 int count = m_charDetails.Count();
905 m_charDetails.SetCount(nChars + count);
906 if (hasRSX)
907 m_rsxform.setCount(nChars + count);
908
909 SkScalar flip = m_fontSize < 0 ? -1 : 1;
910 SkScalar vFlip = flip;
911 if (pFont->IsVertical())
912 vFlip *= -1;
913 for (int index = 0; index < nChars; ++index) {
914 const TextCharPos& cp = pCharPos[index];
915 int cur_index = index + count;
916 m_charDetails.SetPositionAt(
917 cur_index, {cp.m_Origin.x * flip, cp.m_Origin.y * vFlip});
918 m_charDetails.SetGlyphAt(cur_index,
919 static_cast<uint16_t>(cp.m_GlyphIndex));
920 m_charDetails.SetFontCharWidthAt(cur_index, cp.m_FontCharWidth);
921 #if defined(OS_MACOSX)
922 if (cp.m_ExtGID) {
923 m_charDetails.SetGlyphAt(cur_index, static_cast<uint16_t>(cp.m_ExtGID));
924 }
925 #endif
926 }
927 SkPoint delta;
928 if (MatrixOffset(&matrix, &delta)) {
929 for (int index = 0; index < nChars; ++index) {
930 m_charDetails.OffsetPositionAt(index + count, delta.fX * flip,
931 -delta.fY * flip);
932 }
933 }
934 if (hasRSX) {
935 const SkTDArray<SkPoint>& positions = m_charDetails.GetPositions();
936 for (int index = 0; index < nChars; ++index) {
937 const TextCharPos& cp = pCharPos[index];
938 SkRSXform* rsxform = &m_rsxform[index + count];
939 if (cp.m_bGlyphAdjust) {
940 rsxform->fSCos = cp.m_AdjustMatrix[0];
941 rsxform->fSSin = cp.m_AdjustMatrix[1];
942 rsxform->fTx = cp.m_AdjustMatrix[0] * positions[index].fX;
943 rsxform->fTy = cp.m_AdjustMatrix[1] * positions[index].fY;
944 } else {
945 rsxform->fSCos = 1;
946 rsxform->fSSin = 0;
947 rsxform->fTx = positions[index].fX;
948 rsxform->fTy = positions[index].fY;
949 }
950 }
951 }
952 return true;
953 }
954
FlushText()955 void FlushText() {
956 Dump(__func__);
957 SkPaint skPaint;
958 skPaint.setAntiAlias(true);
959 skPaint.setColor(m_fillColor);
960
961 SkFont font;
962 if (m_pTypeFace) { // exclude placeholder test fonts
963 font.setTypeface(m_pTypeFace);
964 }
965 font.setHinting(SkFontHinting::kNone);
966 font.setScaleX(m_scaleX);
967 font.setSkewX(tanf(m_italicAngle * FX_PI / 180.0));
968 font.setSize(SkTAbs(m_fontSize));
969 font.setSubpixel(true);
970
971 SkCanvas* skCanvas = m_pDriver->SkiaCanvas();
972 SkAutoCanvasRestore scoped_save_restore(skCanvas, /*doSave=*/true);
973 SkScalar flip = m_fontSize < 0 ? -1 : 1;
974 SkMatrix skMatrix = ToFlippedSkMatrix(m_drawMatrix, flip);
975 skCanvas->concat(skMatrix);
976 const SkTDArray<uint16_t>& glyphs = m_charDetails.GetGlyphs();
977 #ifdef _SKIA_SUPPORT_PATHS_
978 m_pDriver->PreMultiply();
979 #endif // _SKIA_SUPPORT_PATHS_
980 #if SHOW_TEXT_GLYPHS
981 SkTDArray<SkUnichar> text;
982 // TODO(nigi): |m_glyphs| are deprecated and glyphToUnichars() takes 4
983 // parameters now.
984 text.setCount(m_glyphs.count());
985 skPaint.glyphsToUnichars(m_glyphs.begin(), m_glyphs.count(), text.begin());
986 for (int i = 0; i < m_glyphs.count(); ++i)
987 printf("%lc", m_glyphs[i]);
988 printf("\n");
989 #endif
990
991 if (m_rsxform.count()) {
992 sk_sp<SkTextBlob> blob = SkTextBlob::MakeFromRSXform(
993 glyphs.begin(), glyphs.bytes(), m_rsxform.begin(), font,
994 SkTextEncoding::kGlyphID);
995 skCanvas->drawTextBlob(blob, 0, 0, skPaint);
996 } else {
997 const SkTDArray<SkPoint>& positions = m_charDetails.GetPositions();
998 const SkTDArray<uint32_t>& widths = m_charDetails.GetFontCharWidths();
999 for (int i = 0; i < m_charDetails.Count(); ++i) {
1000 uint32_t font_glyph_width =
1001 m_pFont ? m_pFont->GetGlyphWidth(glyphs[i]) : 0;
1002 uint32_t pdf_glyph_width = widths[i];
1003 if (font_glyph_width && pdf_glyph_width &&
1004 font_glyph_width > pdf_glyph_width) {
1005 font.setScaleX(SkIntToScalar(pdf_glyph_width) / font_glyph_width);
1006 } else {
1007 font.setScaleX(SkIntToScalar(1));
1008 }
1009 sk_sp<SkTextBlob> blob = SkTextBlob::MakeFromText(
1010 &glyphs[i], sizeof(glyphs[i]), font, SkTextEncoding::kGlyphID);
1011 skCanvas->drawTextBlob(blob, positions[i].fX, positions[i].fY, skPaint);
1012 }
1013 }
1014
1015 m_drawIndex = INT_MAX;
1016 m_type = Accumulator::kNone;
1017 m_drawMatrix = CFX_Matrix();
1018 m_pFont = nullptr;
1019 m_italicAngle = 0;
1020 }
1021
IsEmpty() const1022 bool IsEmpty() const { return !m_commands.count(); }
1023
SetClipFill(const CFX_PathData * pPathData,const CFX_Matrix * pMatrix,int fill_mode)1024 bool SetClipFill(const CFX_PathData* pPathData,
1025 const CFX_Matrix* pMatrix,
1026 int fill_mode) {
1027 if (m_debugDisable)
1028 return false;
1029 Dump(__func__);
1030 SkPath skClipPath;
1031 if (pPathData->GetPoints().size() == 5 ||
1032 pPathData->GetPoints().size() == 4) {
1033 CFX_FloatRect rectf;
1034 if (pPathData->IsRect(pMatrix, &rectf)) {
1035 rectf.Intersect(CFX_FloatRect(
1036 0, 0,
1037 static_cast<float>(m_pDriver->GetDeviceCaps(FXDC_PIXEL_WIDTH)),
1038 static_cast<float>(m_pDriver->GetDeviceCaps(FXDC_PIXEL_HEIGHT))));
1039 FX_RECT outer = rectf.GetOuterRect();
1040 // note that PDF's y-axis goes up; Skia's y-axis goes down
1041 skClipPath.addRect({(float)outer.left, (float)outer.bottom,
1042 (float)outer.right, (float)outer.top});
1043 }
1044 }
1045 if (skClipPath.isEmpty()) {
1046 skClipPath = BuildPath(pPathData);
1047 skClipPath.setFillType(GetAlternateOrWindingFillType(fill_mode));
1048 SkMatrix skMatrix = ToSkMatrix(*pMatrix);
1049 skClipPath.transform(skMatrix);
1050 }
1051 return SetClip(skClipPath);
1052 }
1053
SetClip(const SkPath & skClipPath)1054 bool SetClip(const SkPath& skClipPath) {
1055 // if a pending draw depends on clip state that is cached, flush it and draw
1056 if (m_commandIndex < m_commands.count()) {
1057 if (m_commands[m_commandIndex] == Clip::kPath &&
1058 m_clips[m_commandIndex] == skClipPath) {
1059 ++m_commandIndex;
1060 return true;
1061 }
1062 Flush();
1063 }
1064 while (m_clipIndex > m_commandIndex) {
1065 do {
1066 --m_clipIndex;
1067 ASSERT(m_clipIndex >= 0);
1068 } while (m_commands[m_clipIndex] != Clip::kSave);
1069 m_pDriver->SkiaCanvas()->restore();
1070 }
1071 if (m_commandIndex < m_commands.count()) {
1072 m_commands[m_commandIndex] = Clip::kPath;
1073 m_clips[m_commandIndex] = skClipPath;
1074 } else {
1075 m_commands.push_back(Clip::kPath);
1076 m_clips.push_back(skClipPath);
1077 }
1078 ++m_commandIndex;
1079 return true;
1080 }
1081
SetClipStroke(const CFX_PathData * pPathData,const CFX_Matrix * pMatrix,const CFX_GraphStateData * pGraphState)1082 bool SetClipStroke(const CFX_PathData* pPathData,
1083 const CFX_Matrix* pMatrix,
1084 const CFX_GraphStateData* pGraphState) {
1085 if (m_debugDisable)
1086 return false;
1087 Dump(__func__);
1088 SkPath skPath = BuildPath(pPathData);
1089 SkMatrix skMatrix = ToSkMatrix(*pMatrix);
1090 SkPaint skPaint;
1091 m_pDriver->PaintStroke(&skPaint, pGraphState, skMatrix);
1092 SkPath dst_path;
1093 skPaint.getFillPath(skPath, &dst_path);
1094 dst_path.transform(skMatrix);
1095 return SetClip(dst_path);
1096 }
1097
MatrixOffset(const CFX_Matrix * pMatrix,SkPoint * delta)1098 bool MatrixOffset(const CFX_Matrix* pMatrix, SkPoint* delta) {
1099 CFX_Matrix identityMatrix;
1100 if (!pMatrix)
1101 pMatrix = &identityMatrix;
1102 delta->set(pMatrix->e - m_drawMatrix.e, pMatrix->f - m_drawMatrix.f);
1103 if (!delta->fX && !delta->fY)
1104 return true;
1105 SkMatrix drawMatrix = ToSkMatrix(m_drawMatrix);
1106 if (!(drawMatrix.getType() & ~SkMatrix::kTranslate_Mask))
1107 return true;
1108 SkMatrix invDrawMatrix;
1109 if (!drawMatrix.invert(&invDrawMatrix))
1110 return false;
1111 SkMatrix invNewMatrix;
1112 SkMatrix newMatrix = ToSkMatrix(*pMatrix);
1113 if (!newMatrix.invert(&invNewMatrix))
1114 return false;
1115 delta->set(invDrawMatrix.getTranslateX() - invNewMatrix.getTranslateX(),
1116 invDrawMatrix.getTranslateY() - invNewMatrix.getTranslateY());
1117 return true;
1118 }
1119
1120 // returns true if caller should apply command to skia canvas
ClipSave()1121 bool ClipSave() {
1122 if (m_debugDisable)
1123 return false;
1124 Dump(__func__);
1125 int count = m_commands.count();
1126 if (m_commandIndex < count) {
1127 if (Clip::kSave == m_commands[m_commandIndex]) {
1128 ++m_commandIndex;
1129 return true;
1130 }
1131 Flush();
1132 AdjustClip(m_commandIndex);
1133 m_commands[m_commandIndex] = Clip::kSave;
1134 m_clips[m_commandIndex] = m_skEmptyPath;
1135 } else {
1136 AdjustClip(m_commandIndex);
1137 m_commands.push_back(Clip::kSave);
1138 m_clips.push_back(m_skEmptyPath);
1139 }
1140 ++m_commandIndex;
1141 return true;
1142 }
1143
ClipRestore()1144 bool ClipRestore() {
1145 if (m_debugDisable)
1146 return false;
1147 Dump(__func__);
1148 while (Clip::kSave != m_commands[--m_commandIndex]) {
1149 ASSERT(m_commandIndex > 0);
1150 }
1151 return true;
1152 }
1153
DrawChanged(const CFX_Matrix * pMatrix,const CFX_GraphStateData * pState,uint32_t fill_color,uint32_t stroke_color,int fill_mode,BlendMode blend_type,bool group_knockout) const1154 bool DrawChanged(const CFX_Matrix* pMatrix,
1155 const CFX_GraphStateData* pState,
1156 uint32_t fill_color,
1157 uint32_t stroke_color,
1158 int fill_mode,
1159 BlendMode blend_type,
1160 bool group_knockout) const {
1161 return MatrixChanged(pMatrix) || StateChanged(pState, m_drawState) ||
1162 fill_color != m_fillColor || stroke_color != m_strokeColor ||
1163 IsEvenOddFillType(m_skPath.getFillType()) ||
1164 IsAlternateFillMode(fill_mode) || blend_type != m_blendType ||
1165 group_knockout != m_groupKnockout;
1166 }
1167
FontChanged(CFX_Font * pFont,const CFX_Matrix & matrix,float font_size,float scaleX,uint32_t color) const1168 bool FontChanged(CFX_Font* pFont,
1169 const CFX_Matrix& matrix,
1170 float font_size,
1171 float scaleX,
1172 uint32_t color) const {
1173 CFX_TypeFace* typeface =
1174 pFont->GetFaceRec() ? pFont->GetDeviceCache() : nullptr;
1175 return typeface != m_pTypeFace.get() || MatrixChanged(&matrix) ||
1176 font_size != m_fontSize || scaleX != m_scaleX ||
1177 color != m_fillColor ||
1178 pFont->GetSubstFontItalicAngle() != m_italicAngle;
1179 }
1180
MatrixChanged(const CFX_Matrix * pMatrix) const1181 bool MatrixChanged(const CFX_Matrix* pMatrix) const {
1182 return pMatrix ? *pMatrix != m_drawMatrix : m_drawMatrix.IsIdentity();
1183 }
1184
StateChanged(const CFX_GraphStateData * pState,const CFX_GraphStateData & refState) const1185 bool StateChanged(const CFX_GraphStateData* pState,
1186 const CFX_GraphStateData& refState) const {
1187 CFX_GraphStateData identityState;
1188 if (!pState)
1189 pState = &identityState;
1190 return pState->m_LineWidth != refState.m_LineWidth ||
1191 pState->m_LineCap != refState.m_LineCap ||
1192 pState->m_LineJoin != refState.m_LineJoin ||
1193 pState->m_MiterLimit != refState.m_MiterLimit ||
1194 DashChanged(pState, refState);
1195 }
1196
DashChanged(const CFX_GraphStateData * pState,const CFX_GraphStateData & refState) const1197 bool DashChanged(const CFX_GraphStateData* pState,
1198 const CFX_GraphStateData& refState) const {
1199 bool dashArray = pState && !pState->m_DashArray.empty();
1200 if (!dashArray && refState.m_DashArray.empty())
1201 return false;
1202 if (!dashArray || refState.m_DashArray.empty())
1203 return true;
1204 return pState->m_DashPhase != refState.m_DashPhase ||
1205 pState->m_DashArray != refState.m_DashArray;
1206 }
1207
AdjustClip(int limit)1208 void AdjustClip(int limit) {
1209 while (m_clipIndex > limit) {
1210 do {
1211 --m_clipIndex;
1212 ASSERT(m_clipIndex >= 0);
1213 } while (m_commands[m_clipIndex] != Clip::kSave);
1214 m_pDriver->SkiaCanvas()->restore();
1215 }
1216 while (m_clipIndex < limit) {
1217 if (Clip::kSave == m_commands[m_clipIndex]) {
1218 m_pDriver->SkiaCanvas()->save();
1219 } else {
1220 ASSERT(Clip::kPath == m_commands[m_clipIndex]);
1221 m_pDriver->SkiaCanvas()->clipPath(m_clips[m_clipIndex],
1222 SkClipOp::kIntersect, true);
1223 }
1224 ++m_clipIndex;
1225 }
1226 }
1227
Flush()1228 void Flush() {
1229 if (m_debugDisable)
1230 return;
1231 Dump(__func__);
1232 if (Accumulator::kPath == m_type || Accumulator::kText == m_type) {
1233 AdjustClip(SkTMin(m_drawIndex, m_commands.count()));
1234 Accumulator::kPath == m_type ? FlushPath() : FlushText();
1235 }
1236 }
1237
FlushForDraw()1238 void FlushForDraw() {
1239 if (m_debugDisable)
1240 return;
1241 Flush(); // draw any pending text or path
1242 AdjustClip(m_commandIndex); // set up clip stack with any pending state
1243 }
1244
1245 #if SHOW_SKIA_PATH
DumpPrefix(int index) const1246 void DumpPrefix(int index) const {
1247 if (index != m_commandIndex && index != m_drawIndex &&
1248 index != m_clipIndex) {
1249 printf(" ");
1250 return;
1251 }
1252 printf("%c%c%c> ", index == m_commandIndex ? 'x' : '-',
1253 index == m_drawIndex ? 'd' : '-', index == m_clipIndex ? 'c' : '-');
1254 }
1255
DumpEndPrefix() const1256 void DumpEndPrefix() const {
1257 int index = m_commands.count();
1258 if (index != m_commandIndex && index > m_drawIndex && index != m_clipIndex)
1259 return;
1260 printf("%c%c%c>\n", index == m_commandIndex ? 'x' : '-',
1261 index <= m_drawIndex ? 'd' : '-', index == m_clipIndex ? 'c' : '-');
1262 }
1263 #endif // SHOW_SKIA_PATH
1264
Dump(const char * where) const1265 void Dump(const char* where) const {
1266 #if SHOW_SKIA_PATH
1267 if (m_debugDisable)
1268 return;
1269 printf(
1270 "\n%s\nSkia Save Count %d Agg Save Stack/Count %d/%d"
1271 " Cache Save Index/Count %d/%d\n",
1272 where, m_pDriver->SkiaCanvas()->getSaveCount(),
1273 (int)m_pDriver->stack().size(), AggSaveCount(m_pDriver), m_commandIndex,
1274 CacheSaveCount(m_commands, m_commandIndex));
1275 printf("Cache:\n");
1276 #if SHOW_SKIA_PATH_SHORTHAND
1277 bool dumpedPath = false;
1278 #endif
1279 for (int index = 0; index < m_commands.count(); ++index) {
1280 #if SHOW_SKIA_PATH_SHORTHAND
1281 if (Clip::kSave == m_commands[index] && dumpedPath) {
1282 printf("\n");
1283 dumpedPath = false;
1284 }
1285 #endif
1286 DumpPrefix(index);
1287 switch (m_commands[index]) {
1288 case Clip::kSave:
1289 printf("Save %d\n", ++m_debugSaveCounter);
1290 break;
1291 case Clip::kPath:
1292 #if SHOW_SKIA_PATH_SHORTHAND
1293 printf("*");
1294 dumpedPath = true;
1295 #else
1296 m_clips[index].dump();
1297 #endif
1298 break;
1299 default:
1300 printf("unknown\n");
1301 }
1302 }
1303 #if SHOW_SKIA_PATH_SHORTHAND
1304 if (dumpedPath)
1305 printf("\n");
1306 #endif
1307 DumpEndPrefix();
1308 int skCanvasSaveCount = m_pDriver->SkiaCanvas()->getSaveCount();
1309 int cacheSaveCount = 1;
1310 ASSERT(m_clipIndex <= m_commands.count());
1311 for (int index = 0; index < m_clipIndex; ++index)
1312 cacheSaveCount += Clip::kSave == m_commands[index];
1313 ASSERT(skCanvasSaveCount == cacheSaveCount);
1314 #endif // SHOW_SKIA_PATH
1315 }
1316
1317 #if SHOW_SKIA_PATH
AggSaveCount(const UnownedPtr<CFX_SkiaDeviceDriver> driver)1318 static int AggSaveCount(const UnownedPtr<CFX_SkiaDeviceDriver> driver) {
1319 FX_RECT last;
1320 int aggSaveCount = 0;
1321 bool foundLast = false;
1322 for (int index = 0; index < (int)driver->stack().size(); ++index) {
1323 if (!driver->stack()[index]) {
1324 continue;
1325 }
1326 if (driver->stack()[index]->GetType() != CFX_ClipRgn::RectI) {
1327 aggSaveCount += 1;
1328 foundLast = false;
1329 continue;
1330 }
1331 if (!foundLast ||
1332 memcmp(&last, &driver->stack()[index]->GetBox(), sizeof(FX_RECT))) {
1333 aggSaveCount += 1;
1334 foundLast = true;
1335 last = driver->stack()[index]->GetBox();
1336 }
1337 }
1338 if (driver->clip_region()) {
1339 CFX_ClipRgn::ClipType clipType = driver->clip_region()->GetType();
1340 if (clipType != CFX_ClipRgn::RectI || !foundLast ||
1341 memcmp(&last, &driver->clip_region()->GetBox(), sizeof(FX_RECT))) {
1342 aggSaveCount += 1;
1343 }
1344 }
1345 return aggSaveCount;
1346 }
1347
CacheSaveCount(const SkTDArray<SkiaState::Clip> & commands,int commandIndex)1348 static int CacheSaveCount(const SkTDArray<SkiaState::Clip>& commands,
1349 int commandIndex) {
1350 int cacheSaveCount = 0;
1351 bool newPath = false;
1352 for (int index = 0; index < commandIndex; ++index) {
1353 if (Clip::kSave == commands[index]) {
1354 newPath = true;
1355 } else if (newPath) {
1356 ++cacheSaveCount;
1357 newPath = false;
1358 }
1359 }
1360 return cacheSaveCount;
1361 }
1362 #endif
1363
DebugCheckClip()1364 void DebugCheckClip() {
1365 #if SHOW_SKIA_PATH
1366 if (m_debugDisable)
1367 return;
1368 int aggSaveCount = AggSaveCount(m_pDriver);
1369 int cacheSaveCount = CacheSaveCount(m_commands, m_commandIndex);
1370 ASSERT(m_clipIndex <= m_commands.count());
1371 if (aggSaveCount != cacheSaveCount) {
1372 // may not signify a bug if counts don't match
1373 printf("aggSaveCount %d != cacheSaveCount %d\n", aggSaveCount,
1374 cacheSaveCount);
1375 DumpClipStacks();
1376 }
1377 for (int aggIndex = 0; aggIndex < (int)m_pDriver->stack().size();
1378 ++aggIndex) {
1379 if (!m_pDriver->stack()[aggIndex])
1380 continue;
1381 if (m_pDriver->stack()[aggIndex]->GetType() != CFX_ClipRgn::RectI)
1382 continue;
1383 const FX_RECT& aggRect = m_pDriver->stack()[aggIndex]->GetBox();
1384 SkRect skRect = SkRect::MakeLTRB(aggRect.left, aggRect.top, aggRect.right,
1385 aggRect.bottom);
1386 bool foundMatch = false;
1387 for (int skIndex = 0; skIndex < m_commandIndex; ++skIndex) {
1388 if (Clip::kPath != m_commands[skIndex])
1389 continue;
1390 const SkPath& clip = m_clips[skIndex];
1391 SkRect bounds;
1392 if (!clip.isRect(&bounds))
1393 continue;
1394 bounds.roundOut(&bounds);
1395 if (skRect == bounds) {
1396 foundMatch = true;
1397 break;
1398 }
1399 }
1400 if (!foundMatch) {
1401 DumpClipStacks();
1402 NOTREACHED();
1403 }
1404 }
1405 #endif // SHOW_SKIA_PATH
1406 }
1407
1408 #if SHOW_SKIA_PATH
DumpClipStacks() const1409 void DumpClipStacks() const {
1410 if (m_debugDisable)
1411 return;
1412 printf("\ncache\n");
1413 for (int index = 0; index < m_commandIndex; ++index) {
1414 DumpPrefix(index);
1415 switch (m_commands[index]) {
1416 case Clip::kSave:
1417 printf("Save\n");
1418 break;
1419 case Clip::kPath:
1420 m_clips[index].dump();
1421 break;
1422 default:
1423 printf("unknown\n");
1424 }
1425 }
1426 printf("\nagg\n");
1427 for (int index = 0; index < (int)m_pDriver->stack().size(); ++index) {
1428 if (!m_pDriver->stack()[index]) {
1429 printf("null\n");
1430 continue;
1431 }
1432 CFX_ClipRgn::ClipType clipType = m_pDriver->stack()[index]->GetType();
1433 const FX_RECT& box = m_pDriver->stack()[index]->GetBox();
1434 printf("stack rect: %d,%d,%d,%d mask=%s\n", box.left, box.top, box.right,
1435 box.bottom,
1436 CFX_ClipRgn::MaskF == clipType
1437 ? "1"
1438 : CFX_ClipRgn::RectI == clipType ? "0" : "?");
1439 }
1440 if (m_pDriver->clip_region()) {
1441 const FX_RECT& box = m_pDriver->clip_region()->GetBox();
1442 CFX_ClipRgn::ClipType clipType = m_pDriver->clip_region()->GetType();
1443 printf("clip rect: %d,%d,%d,%d mask=%s\n", box.left, box.top, box.right,
1444 box.bottom,
1445 CFX_ClipRgn::MaskF == clipType
1446 ? "1"
1447 : CFX_ClipRgn::RectI == clipType ? "0" : "?");
1448 }
1449 }
1450 #endif // SHOW_SKIA_PATH
1451
1452 private:
1453 class CharDetail {
1454 public:
1455 CharDetail() = default;
1456 ~CharDetail() = default;
1457
GetPositions() const1458 const SkTDArray<SkPoint>& GetPositions() const { return m_positions; }
SetPositionAt(int index,const SkPoint & position)1459 void SetPositionAt(int index, const SkPoint& position) {
1460 m_positions[index] = position;
1461 }
OffsetPositionAt(int index,SkScalar dx,SkScalar dy)1462 void OffsetPositionAt(int index, SkScalar dx, SkScalar dy) {
1463 m_positions[index].offset(dx, dy);
1464 }
GetGlyphs() const1465 const SkTDArray<uint16_t>& GetGlyphs() const { return m_glyphs; }
SetGlyphAt(int index,uint16_t glyph)1466 void SetGlyphAt(int index, uint16_t glyph) { m_glyphs[index] = glyph; }
GetFontCharWidths() const1467 const SkTDArray<uint32_t>& GetFontCharWidths() const {
1468 return m_fontCharWidths;
1469 }
SetFontCharWidthAt(int index,uint32_t width)1470 void SetFontCharWidthAt(int index, uint32_t width) {
1471 m_fontCharWidths[index] = width;
1472 }
Count() const1473 int Count() const {
1474 ASSERT(m_positions.count() == m_glyphs.count());
1475 return m_glyphs.count();
1476 }
SetCount(int count)1477 void SetCount(int count) {
1478 ASSERT(count >= 0);
1479 m_positions.setCount(count);
1480 m_glyphs.setCount(count);
1481 m_fontCharWidths.setCount(count);
1482 }
1483
1484 private:
1485 SkTDArray<SkPoint> m_positions; // accumulator for text positions
1486 SkTDArray<uint16_t> m_glyphs; // accumulator for text glyphs
1487 // accumulator for glyphs' width defined in pdf
1488 SkTDArray<uint32_t> m_fontCharWidths;
1489 };
1490
1491 SkTArray<SkPath> m_clips; // stack of clips that may be reused
1492 SkTDArray<Clip> m_commands; // stack of clip-related commands
1493 CharDetail m_charDetails;
1494 SkTDArray<SkRSXform> m_rsxform; // accumulator for txt rotate/scale/translate
1495 SkPath m_skPath; // accumulator for path contours
1496 SkPath m_skEmptyPath; // used as placehold in the clips array
1497 UnownedPtr<CFX_Font> m_pFont;
1498 CFX_Matrix m_drawMatrix;
1499 CFX_GraphStateData m_clipState;
1500 CFX_GraphStateData m_drawState;
1501 CFX_Matrix m_clipMatrix;
1502 UnownedPtr<CFX_SkiaDeviceDriver> const m_pDriver;
1503 sk_sp<CFX_TypeFace> m_pTypeFace;
1504 float m_fontSize = 0;
1505 float m_scaleX = 0;
1506 uint32_t m_fillColor = 0;
1507 uint32_t m_strokeColor = 0;
1508 BlendMode m_blendType = BlendMode::kNormal;
1509 int m_commandIndex = 0; // active position in clip command stack
1510 int m_drawIndex = INT_MAX; // position of the pending path or text draw
1511 int m_clipIndex = 0; // position reflecting depth of canvas clip stacck
1512 int m_italicAngle = 0;
1513 Accumulator m_type = Accumulator::kNone; // type of pending draw
1514 bool m_fillFullCover = false;
1515 bool m_fillPath = false;
1516 bool m_groupKnockout = false;
1517 bool m_debugDisable = false; // turn off cache for debugging
1518 #if SHOW_SKIA_PATH
1519 public:
1520 mutable int m_debugSaveCounter = 0;
1521 static int m_debugInitCounter;
1522 #endif
1523 };
1524
1525 #if SHOW_SKIA_PATH
1526 int SkiaState::m_debugInitCounter;
1527 #endif
1528
1529 // convert a stroking path to scanlines
PaintStroke(SkPaint * spaint,const CFX_GraphStateData * pGraphState,const SkMatrix & matrix)1530 void CFX_SkiaDeviceDriver::PaintStroke(SkPaint* spaint,
1531 const CFX_GraphStateData* pGraphState,
1532 const SkMatrix& matrix) {
1533 SkPaint::Cap cap;
1534 switch (pGraphState->m_LineCap) {
1535 case CFX_GraphStateData::LineCapRound:
1536 cap = SkPaint::kRound_Cap;
1537 break;
1538 case CFX_GraphStateData::LineCapSquare:
1539 cap = SkPaint::kSquare_Cap;
1540 break;
1541 default:
1542 cap = SkPaint::kButt_Cap;
1543 break;
1544 }
1545 SkPaint::Join join;
1546 switch (pGraphState->m_LineJoin) {
1547 case CFX_GraphStateData::LineJoinRound:
1548 join = SkPaint::kRound_Join;
1549 break;
1550 case CFX_GraphStateData::LineJoinBevel:
1551 join = SkPaint::kBevel_Join;
1552 break;
1553 default:
1554 join = SkPaint::kMiter_Join;
1555 break;
1556 }
1557 SkMatrix inverse;
1558 if (!matrix.invert(&inverse))
1559 return; // give up if the matrix is degenerate, and not invertable
1560 inverse.set(SkMatrix::kMTransX, 0);
1561 inverse.set(SkMatrix::kMTransY, 0);
1562 SkVector deviceUnits[2] = {{0, 1}, {1, 0}};
1563 inverse.mapPoints(deviceUnits, SK_ARRAY_COUNT(deviceUnits));
1564 float width =
1565 SkTMax(pGraphState->m_LineWidth,
1566 SkTMin(deviceUnits[0].length(), deviceUnits[1].length()));
1567 if (!pGraphState->m_DashArray.empty()) {
1568 size_t count = (pGraphState->m_DashArray.size() + 1) / 2;
1569 std::unique_ptr<SkScalar, FxFreeDeleter> intervals(
1570 FX_Alloc2D(SkScalar, count, sizeof(SkScalar)));
1571 // Set dash pattern
1572 for (size_t i = 0; i < count; i++) {
1573 float on = pGraphState->m_DashArray[i * 2];
1574 if (on <= 0.000001f)
1575 on = 1.f / 10;
1576 float off = i * 2 + 1 == pGraphState->m_DashArray.size()
1577 ? on
1578 : pGraphState->m_DashArray[i * 2 + 1];
1579 if (off < 0)
1580 off = 0;
1581 intervals.get()[i * 2] = on;
1582 intervals.get()[i * 2 + 1] = off;
1583 }
1584 spaint->setPathEffect(SkDashPathEffect::Make(intervals.get(), count * 2,
1585 pGraphState->m_DashPhase));
1586 }
1587 spaint->setStyle(SkPaint::kStroke_Style);
1588 spaint->setAntiAlias(true);
1589 spaint->setStrokeWidth(width);
1590 spaint->setStrokeMiter(pGraphState->m_MiterLimit);
1591 spaint->setStrokeCap(cap);
1592 spaint->setStrokeJoin(join);
1593 }
1594
CFX_SkiaDeviceDriver(const RetainPtr<CFX_DIBitmap> & pBitmap,bool bRgbByteOrder,const RetainPtr<CFX_DIBitmap> & pBackdropBitmap,bool bGroupKnockout)1595 CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(
1596 const RetainPtr<CFX_DIBitmap>& pBitmap,
1597 bool bRgbByteOrder,
1598 const RetainPtr<CFX_DIBitmap>& pBackdropBitmap,
1599 bool bGroupKnockout)
1600 : m_pBitmap(pBitmap),
1601 m_pBackdropBitmap(pBackdropBitmap),
1602 m_pRecorder(nullptr),
1603 m_pCache(new SkiaState(this)),
1604 #ifdef _SKIA_SUPPORT_PATHS_
1605 m_pClipRgn(nullptr),
1606 m_FillFlags(0),
1607 m_bRgbByteOrder(bRgbByteOrder),
1608 #endif // _SKIA_SUPPORT_PATHS_
1609 m_bGroupKnockout(bGroupKnockout) {
1610 SkBitmap skBitmap;
1611 ASSERT(pBitmap->GetBPP() == 8 || pBitmap->GetBPP() == 32);
1612 SkImageInfo imageInfo = SkImageInfo::Make(
1613 pBitmap->GetWidth(), pBitmap->GetHeight(),
1614 pBitmap->GetBPP() == 8 ? kAlpha_8_SkColorType : kN32_SkColorType,
1615 kOpaque_SkAlphaType);
1616 skBitmap.installPixels(imageInfo, pBitmap->GetBuffer(), pBitmap->GetPitch());
1617 m_pCanvas = new SkCanvas(skBitmap);
1618 }
1619
1620 #ifdef _SKIA_SUPPORT_
CFX_SkiaDeviceDriver(int size_x,int size_y)1621 CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(int size_x, int size_y)
1622 : m_pBitmap(nullptr),
1623 m_pBackdropBitmap(nullptr),
1624 m_pRecorder(new SkPictureRecorder),
1625 m_pCache(new SkiaState(this)),
1626 m_bGroupKnockout(false) {
1627 m_pRecorder->beginRecording(SkIntToScalar(size_x), SkIntToScalar(size_y));
1628 m_pCanvas = m_pRecorder->getRecordingCanvas();
1629 }
1630
CFX_SkiaDeviceDriver(SkPictureRecorder * recorder)1631 CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(SkPictureRecorder* recorder)
1632 : m_pBitmap(nullptr),
1633 m_pBackdropBitmap(nullptr),
1634 m_pRecorder(recorder),
1635 m_pCache(new SkiaState(this)),
1636 m_bGroupKnockout(false) {
1637 m_pCanvas = m_pRecorder->getRecordingCanvas();
1638 }
1639 #endif // _SKIA_SUPPORT_
1640
~CFX_SkiaDeviceDriver()1641 CFX_SkiaDeviceDriver::~CFX_SkiaDeviceDriver() {
1642 Flush();
1643 if (!m_pRecorder)
1644 delete m_pCanvas;
1645 }
1646
Flush()1647 void CFX_SkiaDeviceDriver::Flush() {
1648 m_pCache->Flush();
1649 }
1650
PreMultiply()1651 void CFX_SkiaDeviceDriver::PreMultiply() {
1652 m_pBitmap->PreMultiply();
1653 }
1654
DrawDeviceText(int nChars,const TextCharPos * pCharPos,CFX_Font * pFont,const CFX_Matrix & mtObject2Device,float font_size,uint32_t color)1655 bool CFX_SkiaDeviceDriver::DrawDeviceText(int nChars,
1656 const TextCharPos* pCharPos,
1657 CFX_Font* pFont,
1658 const CFX_Matrix& mtObject2Device,
1659 float font_size,
1660 uint32_t color) {
1661 if (m_pCache->DrawText(nChars, pCharPos, pFont, mtObject2Device, font_size,
1662 color)) {
1663 return true;
1664 }
1665 sk_sp<SkTypeface> typeface(SkSafeRef(pFont->GetDeviceCache()));
1666 SkPaint paint;
1667 paint.setAntiAlias(true);
1668 paint.setColor(color);
1669
1670 SkFont font;
1671 font.setTypeface(typeface);
1672 font.setHinting(SkFontHinting::kNone);
1673 font.setSize(SkTAbs(font_size));
1674 font.setSubpixel(true);
1675 font.setSkewX(tanf(pFont->GetSubstFontItalicAngle() * FX_PI / 180.0));
1676
1677 SkAutoCanvasRestore scoped_save_restore(m_pCanvas, /*doSave=*/true);
1678 SkScalar flip = font_size < 0 ? -1 : 1;
1679 SkScalar vFlip = flip;
1680 if (pFont->IsVertical())
1681 vFlip *= -1;
1682 SkMatrix skMatrix = ToFlippedSkMatrix(mtObject2Device, flip);
1683 m_pCanvas->concat(skMatrix);
1684 SkTDArray<SkPoint> positions;
1685 positions.setCount(nChars);
1686 SkTDArray<uint16_t> glyphs;
1687 glyphs.setCount(nChars);
1688 bool useRSXform = false;
1689 bool oneAtATime = false;
1690 for (int index = 0; index < nChars; ++index) {
1691 const TextCharPos& cp = pCharPos[index];
1692 positions[index] = {cp.m_Origin.x * flip, cp.m_Origin.y * vFlip};
1693 if (cp.m_bGlyphAdjust) {
1694 useRSXform = true;
1695 if (cp.m_AdjustMatrix[0] != cp.m_AdjustMatrix[3] ||
1696 cp.m_AdjustMatrix[1] != -cp.m_AdjustMatrix[2]) {
1697 oneAtATime = true;
1698 }
1699 }
1700 glyphs[index] = static_cast<uint16_t>(cp.m_GlyphIndex);
1701 #if defined(OS_MACOSX)
1702 if (cp.m_ExtGID)
1703 glyphs[index] = static_cast<uint16_t>(cp.m_ExtGID);
1704 #endif
1705 }
1706 if (oneAtATime)
1707 useRSXform = false;
1708 #if SHOW_TEXT_GLYPHS
1709 SkTDArray<SkUnichar> text;
1710 text.setCount(glyphs.count());
1711 paint.glyphsToUnichars(glyphs.begin(), glyphs.count(), text.begin());
1712 for (int i = 0; i < glyphs.count(); ++i)
1713 printf("%lc", text[i]);
1714 printf("\n");
1715 #endif
1716 #ifdef _SKIA_SUPPORT_PATHS_
1717 m_pBitmap->PreMultiply();
1718 #endif // _SKIA_SUPPORT_PATHS_
1719 if (useRSXform) {
1720 SkTDArray<SkRSXform> xforms;
1721 xforms.setCount(nChars);
1722 for (int index = 0; index < nChars; ++index) {
1723 const TextCharPos& cp = pCharPos[index];
1724 SkRSXform* rsxform = &xforms[index];
1725 if (cp.m_bGlyphAdjust) {
1726 rsxform->fSCos = cp.m_AdjustMatrix[0];
1727 rsxform->fSSin = cp.m_AdjustMatrix[1];
1728 rsxform->fTx = cp.m_AdjustMatrix[0] * positions[index].fX;
1729 rsxform->fTy = cp.m_AdjustMatrix[1] * positions[index].fY;
1730 } else {
1731 rsxform->fSCos = 1;
1732 rsxform->fSSin = 0;
1733 rsxform->fTx = positions[index].fX;
1734 rsxform->fTy = positions[index].fY;
1735 }
1736 }
1737 m_pCanvas->drawTextBlob(
1738 SkTextBlob::MakeFromRSXform(glyphs.begin(), nChars * 2, xforms.begin(),
1739 font, SkTextEncoding::kGlyphID),
1740 0, 0, paint);
1741 } else if (oneAtATime) {
1742 for (int index = 0; index < nChars; ++index) {
1743 const TextCharPos& cp = pCharPos[index];
1744 if (cp.m_bGlyphAdjust) {
1745 if (0 == cp.m_AdjustMatrix[1] && 0 == cp.m_AdjustMatrix[2] &&
1746 1 == cp.m_AdjustMatrix[3]) {
1747 font.setScaleX(cp.m_AdjustMatrix[0]);
1748 auto blob =
1749 SkTextBlob::MakeFromText(&glyphs[index], sizeof(glyphs[index]),
1750 font, SkTextEncoding::kGlyphID);
1751 m_pCanvas->drawTextBlob(blob, positions[index].fX,
1752 positions[index].fY, paint);
1753 font.setScaleX(SkIntToScalar(1));
1754 } else {
1755 SkAutoCanvasRestore scoped_save_restore2(m_pCanvas, /*doSave=*/true);
1756 SkMatrix adjust;
1757 adjust.reset();
1758 adjust.setScaleX(cp.m_AdjustMatrix[0]);
1759 adjust.setSkewX(cp.m_AdjustMatrix[1]);
1760 adjust.setSkewY(cp.m_AdjustMatrix[2]);
1761 adjust.setScaleY(cp.m_AdjustMatrix[3]);
1762 adjust.preTranslate(positions[index].fX, positions[index].fY);
1763 m_pCanvas->concat(adjust);
1764 auto blob =
1765 SkTextBlob::MakeFromText(&glyphs[index], sizeof(glyphs[index]),
1766 font, SkTextEncoding::kGlyphID);
1767 m_pCanvas->drawTextBlob(blob, 0, 0, paint);
1768 }
1769 } else {
1770 auto blob =
1771 SkTextBlob::MakeFromText(&glyphs[index], sizeof(glyphs[index]),
1772 font, SkTextEncoding::kGlyphID);
1773 m_pCanvas->drawTextBlob(blob, positions[index].fX, positions[index].fY,
1774 paint);
1775 }
1776 }
1777 } else {
1778 for (int index = 0; index < nChars; ++index) {
1779 const TextCharPos& cp = pCharPos[index];
1780 uint32_t font_glyph_width =
1781 pFont ? pFont->GetGlyphWidth(cp.m_GlyphIndex) : 0;
1782 uint32_t pdf_glyph_width = cp.m_FontCharWidth;
1783 if (font_glyph_width && pdf_glyph_width &&
1784 font_glyph_width > pdf_glyph_width) {
1785 font.setScaleX(SkIntToScalar(pdf_glyph_width) / font_glyph_width);
1786 } else {
1787 font.setScaleX(SkIntToScalar(1));
1788 }
1789 auto blob =
1790 SkTextBlob::MakeFromText(&glyphs[index], sizeof(glyphs[index]), font,
1791 SkTextEncoding::kGlyphID);
1792 m_pCanvas->drawTextBlob(blob, positions[index].fX, positions[index].fY,
1793 paint);
1794 }
1795 }
1796
1797 return true;
1798 }
1799
GetDriverType() const1800 int CFX_SkiaDeviceDriver::GetDriverType() const {
1801 return 1;
1802 }
1803
GetDeviceType() const1804 DeviceType CFX_SkiaDeviceDriver::GetDeviceType() const {
1805 return DeviceType::kDisplay;
1806 }
1807
GetDeviceCaps(int caps_id) const1808 int CFX_SkiaDeviceDriver::GetDeviceCaps(int caps_id) const {
1809 switch (caps_id) {
1810 #ifdef _SKIA_SUPPORT_
1811 case FXDC_PIXEL_WIDTH:
1812 return m_pCanvas->imageInfo().width();
1813 case FXDC_PIXEL_HEIGHT:
1814 return m_pCanvas->imageInfo().height();
1815 case FXDC_BITS_PIXEL:
1816 return 32;
1817 case FXDC_HORZ_SIZE:
1818 case FXDC_VERT_SIZE:
1819 return 0;
1820 case FXDC_RENDER_CAPS:
1821 return FXRC_GET_BITS | FXRC_ALPHA_PATH | FXRC_ALPHA_IMAGE |
1822 FXRC_BLEND_MODE | FXRC_SOFT_CLIP | FXRC_ALPHA_OUTPUT |
1823 FXRC_FILLSTROKE_PATH | FXRC_SHADING;
1824 #endif // _SKIA_SUPPORT_
1825
1826 #ifdef _SKIA_SUPPORT_PATHS_
1827 case FXDC_PIXEL_WIDTH:
1828 return m_pBitmap->GetWidth();
1829 case FXDC_PIXEL_HEIGHT:
1830 return m_pBitmap->GetHeight();
1831 case FXDC_BITS_PIXEL:
1832 return m_pBitmap->GetBPP();
1833 case FXDC_HORZ_SIZE:
1834 case FXDC_VERT_SIZE:
1835 return 0;
1836 case FXDC_RENDER_CAPS: {
1837 int flags = FXRC_GET_BITS | FXRC_ALPHA_PATH | FXRC_ALPHA_IMAGE |
1838 FXRC_BLEND_MODE | FXRC_SOFT_CLIP | FXRC_SHADING;
1839 if (m_pBitmap->HasAlpha()) {
1840 flags |= FXRC_ALPHA_OUTPUT;
1841 } else if (m_pBitmap->IsAlphaMask()) {
1842 if (m_pBitmap->GetBPP() == 1) {
1843 flags |= FXRC_BITMASK_OUTPUT;
1844 } else {
1845 flags |= FXRC_BYTEMASK_OUTPUT;
1846 }
1847 }
1848 if (m_pBitmap->IsCmykImage()) {
1849 flags |= FXRC_CMYK_OUTPUT;
1850 }
1851 return flags;
1852 }
1853 #endif // _SKIA_SUPPORT_PATHS_
1854
1855 default:
1856 NOTREACHED();
1857 return 0;
1858 }
1859 }
1860
SaveState()1861 void CFX_SkiaDeviceDriver::SaveState() {
1862 m_pCache->DebugCheckClip();
1863 if (!m_pCache->ClipSave())
1864 m_pCanvas->save();
1865
1866 #ifdef _SKIA_SUPPORT_PATHS_
1867 #if SHOW_SKIA_PATH
1868 printf("SaveState %zd\n", stack().size());
1869 #endif
1870 std::unique_ptr<CFX_ClipRgn> pClip;
1871 if (m_pClipRgn)
1872 pClip = pdfium::MakeUnique<CFX_ClipRgn>(*m_pClipRgn);
1873 m_StateStack.push_back(std::move(pClip));
1874 #endif // _SKIA_SUPPORT_PATHS_
1875 }
1876
RestoreState(bool bKeepSaved)1877 void CFX_SkiaDeviceDriver::RestoreState(bool bKeepSaved) {
1878 #ifdef _SKIA_SUPPORT_PATHS_
1879 m_pClipRgn.reset();
1880
1881 if (m_StateStack.empty())
1882 return;
1883 #else
1884 if (m_pCache->IsEmpty())
1885 return;
1886 #endif
1887 if (!m_pCache->ClipRestore())
1888 m_pCanvas->restore();
1889 if (bKeepSaved && !m_pCache->ClipSave())
1890 m_pCanvas->save();
1891 #ifdef _SKIA_SUPPORT_PATHS_
1892 #if SHOW_SKIA_PATH
1893 printf("RestoreState %zd %s\n", m_StateStack.size(),
1894 bKeepSaved ? "bKeepSaved" : "");
1895 #endif
1896 if (bKeepSaved) {
1897 if (m_StateStack.back())
1898 m_pClipRgn = pdfium::MakeUnique<CFX_ClipRgn>(*m_StateStack.back());
1899 } else {
1900 m_pClipRgn = std::move(m_StateStack.back());
1901 m_StateStack.pop_back();
1902 }
1903 m_pCache->DebugCheckClip();
1904 #endif // _SKIA_SUPPORT_PATHS_
1905 }
1906
1907 #ifdef _SKIA_SUPPORT_PATHS_
SetClipMask(const FX_RECT & clipBox,const SkPath & path)1908 void CFX_SkiaDeviceDriver::SetClipMask(const FX_RECT& clipBox,
1909 const SkPath& path) {
1910 FX_RECT path_rect(clipBox.left, clipBox.top, clipBox.right + 1,
1911 clipBox.bottom + 1);
1912 path_rect.Intersect(m_pClipRgn->GetBox());
1913 auto pThisLayer = pdfium::MakeRetain<CFX_DIBitmap>();
1914 pThisLayer->Create(path_rect.Width(), path_rect.Height(), FXDIB_8bppMask);
1915 pThisLayer->Clear(0);
1916
1917 SkImageInfo imageInfo =
1918 SkImageInfo::Make(pThisLayer->GetWidth(), pThisLayer->GetHeight(),
1919 SkColorType::kAlpha_8_SkColorType, kOpaque_SkAlphaType);
1920 SkBitmap bitmap;
1921 bitmap.installPixels(imageInfo, pThisLayer->GetBuffer(),
1922 pThisLayer->GetPitch());
1923 auto canvas = pdfium::MakeUnique<SkCanvas>(bitmap);
1924 canvas->translate(
1925 -path_rect.left,
1926 -path_rect.top); // FIXME(caryclark) wrong sign(s)? upside down?
1927 SkPaint paint;
1928 paint.setAntiAlias((m_FillFlags & FXFILL_NOPATHSMOOTH) == 0);
1929 canvas->drawPath(path, paint);
1930 m_pClipRgn->IntersectMaskF(path_rect.left, path_rect.top, pThisLayer);
1931 }
1932 #endif // _SKIA_SUPPORT_PATHS_
1933
SetClip_PathFill(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,int fill_mode)1934 bool CFX_SkiaDeviceDriver::SetClip_PathFill(
1935 const CFX_PathData* pPathData, // path info
1936 const CFX_Matrix* pObject2Device, // flips object's y-axis
1937 int fill_mode // fill mode, WINDING or ALTERNATE
1938 ) {
1939 CFX_Matrix identity;
1940 const CFX_Matrix* deviceMatrix = pObject2Device ? pObject2Device : &identity;
1941 bool cached = m_pCache->SetClipFill(pPathData, deviceMatrix, fill_mode);
1942
1943 #ifdef _SKIA_SUPPORT_PATHS_
1944 m_FillFlags = fill_mode;
1945 if (!m_pClipRgn) {
1946 m_pClipRgn = pdfium::MakeUnique<CFX_ClipRgn>(
1947 GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT));
1948 }
1949 #endif // _SKIA_SUPPORT_PATHS_
1950 if (pPathData->GetPoints().size() == 5 ||
1951 pPathData->GetPoints().size() == 4) {
1952 CFX_FloatRect rectf;
1953 if (pPathData->IsRect(deviceMatrix, &rectf)) {
1954 rectf.Intersect(CFX_FloatRect(0, 0,
1955 (float)GetDeviceCaps(FXDC_PIXEL_WIDTH),
1956 (float)GetDeviceCaps(FXDC_PIXEL_HEIGHT)));
1957 // note that PDF's y-axis goes up; Skia's y-axis goes down
1958 if (!cached) {
1959 SkRect skClipRect =
1960 SkRect::MakeLTRB(rectf.left, rectf.bottom, rectf.right, rectf.top);
1961 DebugDrawSkiaClipRect(m_pCanvas, skClipRect);
1962 m_pCanvas->clipRect(skClipRect, SkClipOp::kIntersect, true);
1963 }
1964
1965 #ifdef _SKIA_SUPPORT_PATHS_
1966 FX_RECT rect = rectf.GetOuterRect();
1967 m_pClipRgn->IntersectRect(rect);
1968 #endif // _SKIA_SUPPORT_PATHS_
1969 DebugShowCanvasClip(this, m_pCanvas);
1970 return true;
1971 }
1972 }
1973 SkPath skClipPath = BuildPath(pPathData);
1974 skClipPath.setFillType(GetAlternateOrWindingFillType(fill_mode));
1975 SkMatrix skMatrix = ToSkMatrix(*deviceMatrix);
1976 skClipPath.transform(skMatrix);
1977 DebugShowSkiaPath(skClipPath);
1978 if (!cached) {
1979 DebugDrawSkiaClipPath(m_pCanvas, skClipPath);
1980 m_pCanvas->clipPath(skClipPath, SkClipOp::kIntersect, true);
1981 }
1982 #ifdef _SKIA_SUPPORT_PATHS_
1983 FX_RECT clipBox(0, 0, GetDeviceCaps(FXDC_PIXEL_WIDTH),
1984 GetDeviceCaps(FXDC_PIXEL_HEIGHT));
1985 SetClipMask(clipBox, skClipPath);
1986 #endif // _SKIA_SUPPORT_PATHS_
1987 DebugShowCanvasClip(this, m_pCanvas);
1988 return true;
1989 }
1990
SetClip_PathStroke(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState)1991 bool CFX_SkiaDeviceDriver::SetClip_PathStroke(
1992 const CFX_PathData* pPathData, // path info
1993 const CFX_Matrix* pObject2Device, // required transformation
1994 const CFX_GraphStateData* pGraphState // graphic state, for pen attributes
1995 ) {
1996 bool cached = m_pCache->SetClipStroke(pPathData, pObject2Device, pGraphState);
1997
1998 #ifdef _SKIA_SUPPORT_PATHS_
1999 if (!m_pClipRgn) {
2000 m_pClipRgn = pdfium::MakeUnique<CFX_ClipRgn>(
2001 GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT));
2002 }
2003 #endif // _SKIA_SUPPORT_PATHS_
2004 // build path data
2005 SkPath skPath = BuildPath(pPathData);
2006 SkMatrix skMatrix = ToSkMatrix(*pObject2Device);
2007 SkPaint skPaint;
2008 PaintStroke(&skPaint, pGraphState, skMatrix);
2009 SkPath dst_path;
2010 skPaint.getFillPath(skPath, &dst_path);
2011 dst_path.transform(skMatrix);
2012 if (!cached) {
2013 DebugDrawSkiaClipPath(m_pCanvas, dst_path);
2014 m_pCanvas->clipPath(dst_path, SkClipOp::kIntersect, true);
2015 }
2016 #ifdef _SKIA_SUPPORT_PATHS_
2017 FX_RECT clipBox(0, 0, GetDeviceCaps(FXDC_PIXEL_WIDTH),
2018 GetDeviceCaps(FXDC_PIXEL_HEIGHT));
2019 SetClipMask(clipBox, dst_path);
2020 #endif // _SKIA_SUPPORT_PATHS_
2021 DebugShowCanvasClip(this, m_pCanvas);
2022 return true;
2023 }
2024
DrawPath(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState,uint32_t fill_color,uint32_t stroke_color,int fill_mode,BlendMode blend_type)2025 bool CFX_SkiaDeviceDriver::DrawPath(
2026 const CFX_PathData* pPathData, // path info
2027 const CFX_Matrix* pObject2Device, // optional transformation
2028 const CFX_GraphStateData* pGraphState, // graphic state, for pen attributes
2029 uint32_t fill_color, // fill color
2030 uint32_t stroke_color, // stroke color
2031 int fill_mode, // fill mode, WINDING or ALTERNATE. 0 for not filled
2032 BlendMode blend_type) {
2033 ASSERT(GetAlternateOrWindingFillMode(fill_mode) !=
2034 kAlternateOrWindingFillModeMask);
2035 if (m_pCache->DrawPath(pPathData, pObject2Device, pGraphState, fill_color,
2036 stroke_color, fill_mode, blend_type)) {
2037 return true;
2038 }
2039 SkMatrix skMatrix;
2040 if (pObject2Device)
2041 skMatrix = ToSkMatrix(*pObject2Device);
2042 else
2043 skMatrix.setIdentity();
2044 SkPaint skPaint;
2045 skPaint.setAntiAlias(true);
2046 if (fill_mode & FXFILL_FULLCOVER)
2047 skPaint.setBlendMode(SkBlendMode::kPlus);
2048 int stroke_alpha = FXARGB_A(stroke_color);
2049 bool is_paint_stroke = pGraphState && stroke_alpha;
2050 if (is_paint_stroke)
2051 PaintStroke(&skPaint, pGraphState, skMatrix);
2052 SkPath skPath = BuildPath(pPathData);
2053 SkAutoCanvasRestore scoped_save_restore(m_pCanvas, /*doSave=*/true);
2054 m_pCanvas->concat(skMatrix);
2055 bool do_stroke = true;
2056 if (GetAlternateOrWindingFillMode(fill_mode) && fill_color) {
2057 skPath.setFillType(GetAlternateOrWindingFillType(fill_mode));
2058 SkPath strokePath;
2059 const SkPath* fillPath = &skPath;
2060 if (is_paint_stroke) {
2061 if (m_bGroupKnockout) {
2062 skPaint.getFillPath(skPath, &strokePath);
2063 if (stroke_color == fill_color &&
2064 Op(skPath, strokePath, SkPathOp::kUnion_SkPathOp, &strokePath)) {
2065 fillPath = &strokePath;
2066 do_stroke = false;
2067 } else if (Op(skPath, strokePath, SkPathOp::kDifference_SkPathOp,
2068 &strokePath)) {
2069 fillPath = &strokePath;
2070 }
2071 }
2072 }
2073 skPaint.setStyle(SkPaint::kFill_Style);
2074 skPaint.setColor(fill_color);
2075 #ifdef _SKIA_SUPPORT_PATHS_
2076 m_pBitmap->PreMultiply();
2077 #endif // _SKIA_SUPPORT_PATHS_
2078 DebugShowSkiaDrawPath(this, m_pCanvas, skPaint, *fillPath);
2079 m_pCanvas->drawPath(*fillPath, skPaint);
2080 }
2081 if (is_paint_stroke && do_stroke) {
2082 skPaint.setStyle(SkPaint::kStroke_Style);
2083 skPaint.setColor(stroke_color);
2084 #ifdef _SKIA_SUPPORT_PATHS_
2085 m_pBitmap->PreMultiply();
2086 #endif // _SKIA_SUPPORT_PATHS_
2087 DebugShowSkiaDrawPath(this, m_pCanvas, skPaint, skPath);
2088 m_pCanvas->drawPath(skPath, skPaint);
2089 }
2090 return true;
2091 }
2092
DrawCosmeticLine(const CFX_PointF & ptMoveTo,const CFX_PointF & ptLineTo,uint32_t color,BlendMode blend_type)2093 bool CFX_SkiaDeviceDriver::DrawCosmeticLine(const CFX_PointF& ptMoveTo,
2094 const CFX_PointF& ptLineTo,
2095 uint32_t color,
2096 BlendMode blend_type) {
2097 return false;
2098 }
2099
FillRectWithBlend(const FX_RECT & rect,uint32_t fill_color,BlendMode blend_type)2100 bool CFX_SkiaDeviceDriver::FillRectWithBlend(const FX_RECT& rect,
2101 uint32_t fill_color,
2102 BlendMode blend_type) {
2103 m_pCache->FlushForDraw();
2104 SkPaint spaint;
2105 spaint.setAntiAlias(true);
2106 spaint.setColor(fill_color);
2107 spaint.setBlendMode(GetSkiaBlendMode(blend_type));
2108 SkRect srect = SkRect::MakeLTRB(rect.left, SkTMin(rect.top, rect.bottom),
2109 rect.right, SkTMax(rect.bottom, rect.top));
2110 DebugShowSkiaDrawRect(this, m_pCanvas, spaint, srect);
2111 m_pCanvas->drawRect(srect, spaint);
2112 return true;
2113 }
2114
DrawShading(const CPDF_ShadingPattern * pPattern,const CFX_Matrix * pMatrix,const FX_RECT & clip_rect,int alpha,bool bAlphaMode)2115 bool CFX_SkiaDeviceDriver::DrawShading(const CPDF_ShadingPattern* pPattern,
2116 const CFX_Matrix* pMatrix,
2117 const FX_RECT& clip_rect,
2118 int alpha,
2119 bool bAlphaMode) {
2120 m_pCache->FlushForDraw();
2121 ShadingType shadingType = pPattern->GetShadingType();
2122 if (kAxialShading != shadingType && kRadialShading != shadingType &&
2123 kCoonsPatchMeshShading != shadingType) {
2124 // TODO(caryclark) more types
2125 return false;
2126 }
2127 int csFamily = pPattern->GetCS()->GetFamily();
2128 if (PDFCS_DEVICERGB != csFamily && PDFCS_DEVICEGRAY != csFamily)
2129 return false;
2130 const std::vector<std::unique_ptr<CPDF_Function>>& pFuncs =
2131 pPattern->GetFuncs();
2132 int nFuncs = pFuncs.size();
2133 if (nFuncs > 1) // TODO(caryclark) remove this restriction
2134 return false;
2135 const CPDF_Dictionary* pDict = pPattern->GetShadingObject()->GetDict();
2136 const CPDF_Array* pCoords = pDict->GetArrayFor("Coords");
2137 if (!pCoords && kCoonsPatchMeshShading != shadingType)
2138 return false;
2139 // TODO(caryclark) Respect Domain[0], Domain[1]. (Don't know what they do
2140 // yet.)
2141 SkTDArray<SkColor> skColors;
2142 SkTDArray<SkScalar> skPos;
2143 for (int j = 0; j < nFuncs; j++) {
2144 if (!pFuncs[j])
2145 continue;
2146
2147 if (const CPDF_SampledFunc* pSampledFunc = pFuncs[j]->ToSampledFunc()) {
2148 /* TODO(caryclark)
2149 Type 0 Sampled Functions in PostScript can also have an Order integer
2150 in the dictionary. PDFium doesn't appear to check for this anywhere.
2151 */
2152 if (!AddSamples(pSampledFunc, &skColors, &skPos))
2153 return false;
2154 } else if (const CPDF_ExpIntFunc* pExpIntFuc = pFuncs[j]->ToExpIntFunc()) {
2155 if (!AddColors(pExpIntFuc, &skColors, /*is_encode_reversed=*/false))
2156 return false;
2157 skPos.push_back(0);
2158 skPos.push_back(1);
2159 } else if (const CPDF_StitchFunc* pStitchFunc = pFuncs[j]->ToStitchFunc()) {
2160 if (!AddStitching(pStitchFunc, &skColors, &skPos))
2161 return false;
2162 } else {
2163 return false;
2164 }
2165 }
2166 const CPDF_Array* pArray = pDict->GetArrayFor("Extend");
2167 bool clipStart = !pArray || !pArray->GetIntegerAt(0);
2168 bool clipEnd = !pArray || !pArray->GetIntegerAt(1);
2169 SkPaint paint;
2170 paint.setAntiAlias(true);
2171 paint.setAlpha(alpha);
2172 SkMatrix skMatrix = ToSkMatrix(*pMatrix);
2173 SkRect skRect = SkRect::MakeLTRB(clip_rect.left, clip_rect.top,
2174 clip_rect.right, clip_rect.bottom);
2175 SkPath skClip;
2176 SkPath skPath;
2177 if (kAxialShading == shadingType) {
2178 float start_x = pCoords->GetNumberAt(0);
2179 float start_y = pCoords->GetNumberAt(1);
2180 float end_x = pCoords->GetNumberAt(2);
2181 float end_y = pCoords->GetNumberAt(3);
2182 SkPoint pts[] = {{start_x, start_y}, {end_x, end_y}};
2183 skMatrix.mapPoints(pts, SK_ARRAY_COUNT(pts));
2184 paint.setShader(
2185 SkGradientShader::MakeLinear(pts, skColors.begin(), skPos.begin(),
2186 skColors.count(), SkTileMode::kClamp));
2187 if (clipStart || clipEnd) {
2188 // if the gradient is horizontal or vertical, modify the draw rectangle
2189 if (pts[0].fX == pts[1].fX) { // vertical
2190 if (pts[0].fY > pts[1].fY) {
2191 std::swap(pts[0].fY, pts[1].fY);
2192 std::swap(clipStart, clipEnd);
2193 }
2194 if (clipStart)
2195 skRect.fTop = SkTMax(skRect.fTop, pts[0].fY);
2196 if (clipEnd)
2197 skRect.fBottom = SkTMin(skRect.fBottom, pts[1].fY);
2198 } else if (pts[0].fY == pts[1].fY) { // horizontal
2199 if (pts[0].fX > pts[1].fX) {
2200 std::swap(pts[0].fX, pts[1].fX);
2201 std::swap(clipStart, clipEnd);
2202 }
2203 if (clipStart)
2204 skRect.fLeft = SkTMax(skRect.fLeft, pts[0].fX);
2205 if (clipEnd)
2206 skRect.fRight = SkTMin(skRect.fRight, pts[1].fX);
2207 } else { // if the gradient is angled and contained by the rect, clip
2208 SkPoint rectPts[4] = {{skRect.fLeft, skRect.fTop},
2209 {skRect.fRight, skRect.fTop},
2210 {skRect.fRight, skRect.fBottom},
2211 {skRect.fLeft, skRect.fBottom}};
2212 ClipAngledGradient(pts, rectPts, clipStart, clipEnd, &skClip);
2213 }
2214 }
2215 skPath.addRect(skRect);
2216 skMatrix.setIdentity();
2217 } else if (kRadialShading == shadingType) {
2218 float start_x = pCoords->GetNumberAt(0);
2219 float start_y = pCoords->GetNumberAt(1);
2220 float start_r = pCoords->GetNumberAt(2);
2221 float end_x = pCoords->GetNumberAt(3);
2222 float end_y = pCoords->GetNumberAt(4);
2223 float end_r = pCoords->GetNumberAt(5);
2224 SkPoint pts[] = {{start_x, start_y}, {end_x, end_y}};
2225
2226 paint.setShader(SkGradientShader::MakeTwoPointConical(
2227 pts[0], start_r, pts[1], end_r, skColors.begin(), skPos.begin(),
2228 skColors.count(), SkTileMode::kClamp));
2229 if (clipStart || clipEnd) {
2230 if (clipStart && start_r)
2231 skClip.addCircle(pts[0].fX, pts[0].fY, start_r);
2232 if (clipEnd)
2233 skClip.addCircle(pts[1].fX, pts[1].fY, end_r, SkPathDirection::kCCW);
2234 else
2235 skClip.setFillType(SkPathFillType::kInverseWinding);
2236 skClip.transform(skMatrix);
2237 }
2238 SkMatrix inverse;
2239 if (!skMatrix.invert(&inverse))
2240 return false;
2241 skPath.addRect(skRect);
2242 skPath.transform(inverse);
2243 } else {
2244 ASSERT(kCoonsPatchMeshShading == shadingType);
2245 const CPDF_Stream* pStream = ToStream(pPattern->GetShadingObject());
2246 if (!pStream)
2247 return false;
2248 CPDF_MeshStream stream(shadingType, pPattern->GetFuncs(), pStream,
2249 pPattern->GetCS());
2250 if (!stream.Load())
2251 return false;
2252 SkPoint cubics[12];
2253 SkColor colors[4];
2254 SkAutoCanvasRestore scoped_save_restore(m_pCanvas, /*doSave=*/true);
2255 if (!skClip.isEmpty())
2256 m_pCanvas->clipPath(skClip, SkClipOp::kIntersect, true);
2257 m_pCanvas->concat(skMatrix);
2258 while (!stream.BitStream()->IsEOF()) {
2259 uint32_t flag = stream.ReadFlag();
2260 int iStartPoint = flag ? 4 : 0;
2261 int iStartColor = flag ? 2 : 0;
2262 if (flag) {
2263 SkPoint tempCubics[4];
2264 for (int i = 0; i < (int)SK_ARRAY_COUNT(tempCubics); i++)
2265 tempCubics[i] = cubics[(flag * 3 + i) % 12];
2266 memcpy(cubics, tempCubics, sizeof(tempCubics));
2267 SkColor tempColors[2];
2268 tempColors[0] = colors[flag];
2269 tempColors[1] = colors[(flag + 1) % 4];
2270 memcpy(colors, tempColors, sizeof(tempColors));
2271 }
2272 for (int i = iStartPoint; i < (int)SK_ARRAY_COUNT(cubics); i++) {
2273 CFX_PointF point = stream.ReadCoords();
2274 cubics[i].fX = point.x;
2275 cubics[i].fY = point.y;
2276 }
2277 for (int i = iStartColor; i < (int)SK_ARRAY_COUNT(colors); i++) {
2278 float r;
2279 float g;
2280 float b;
2281 std::tie(r, g, b) = stream.ReadColor();
2282 colors[i] = SkColorSetARGB(0xFF, (U8CPU)(r * 255), (U8CPU)(g * 255),
2283 (U8CPU)(b * 255));
2284 }
2285 m_pCanvas->drawPatch(cubics, colors, nullptr, paint);
2286 }
2287 return true;
2288 }
2289 SkAutoCanvasRestore scoped_save_restore(m_pCanvas, /*doSave=*/true);
2290 if (!skClip.isEmpty())
2291 m_pCanvas->clipPath(skClip, SkClipOp::kIntersect, true);
2292 m_pCanvas->concat(skMatrix);
2293 m_pCanvas->drawPath(skPath, paint);
2294 return true;
2295 }
2296
GetBuffer() const2297 uint8_t* CFX_SkiaDeviceDriver::GetBuffer() const {
2298 return m_pBitmap->GetBuffer();
2299 }
2300
GetClipBox(FX_RECT * pRect)2301 bool CFX_SkiaDeviceDriver::GetClipBox(FX_RECT* pRect) {
2302 #ifdef _SKIA_SUPPORT_PATHS_
2303 if (!m_pClipRgn) {
2304 pRect->left = pRect->top = 0;
2305 pRect->right = GetDeviceCaps(FXDC_PIXEL_WIDTH);
2306 pRect->bottom = GetDeviceCaps(FXDC_PIXEL_HEIGHT);
2307 return true;
2308 }
2309 *pRect = m_pClipRgn->GetBox();
2310 #else
2311 // TODO(caryclark) call m_canvas->getClipDeviceBounds() instead
2312 pRect->left = 0;
2313 pRect->top = 0;
2314 const SkImageInfo& canvasSize = m_pCanvas->imageInfo();
2315 pRect->right = canvasSize.width();
2316 pRect->bottom = canvasSize.height();
2317 #endif
2318 return true;
2319 }
2320
GetDIBits(const RetainPtr<CFX_DIBitmap> & pBitmap,int left,int top)2321 bool CFX_SkiaDeviceDriver::GetDIBits(const RetainPtr<CFX_DIBitmap>& pBitmap,
2322 int left,
2323 int top) {
2324 if (!m_pBitmap)
2325 return true;
2326 uint8_t* srcBuffer = m_pBitmap->GetBuffer();
2327 if (!srcBuffer)
2328 return true;
2329 #ifdef _SKIA_SUPPORT_
2330 m_pCache->FlushForDraw();
2331 int srcWidth = m_pBitmap->GetWidth();
2332 int srcHeight = m_pBitmap->GetHeight();
2333 int srcRowBytes = srcWidth * sizeof(uint32_t);
2334 SkImageInfo srcImageInfo = SkImageInfo::Make(
2335 srcWidth, srcHeight, SkColorType::kN32_SkColorType, kPremul_SkAlphaType);
2336 SkBitmap skSrcBitmap;
2337 skSrcBitmap.installPixels(srcImageInfo, srcBuffer, srcRowBytes);
2338 uint8_t* dstBuffer = pBitmap->GetBuffer();
2339 ASSERT(dstBuffer);
2340 int dstWidth = pBitmap->GetWidth();
2341 int dstHeight = pBitmap->GetHeight();
2342 int dstRowBytes = dstWidth * sizeof(uint32_t);
2343 SkImageInfo dstImageInfo = SkImageInfo::Make(
2344 dstWidth, dstHeight, SkColorType::kN32_SkColorType, kPremul_SkAlphaType);
2345 SkBitmap skDstBitmap;
2346 skDstBitmap.installPixels(dstImageInfo, dstBuffer, dstRowBytes);
2347 SkCanvas canvas(skDstBitmap);
2348 canvas.drawBitmap(skSrcBitmap, left, top, nullptr);
2349 return true;
2350 #endif // _SKIA_SUPPORT_
2351
2352 #ifdef _SKIA_SUPPORT_PATHS_
2353 Flush();
2354 m_pBitmap->UnPreMultiply();
2355 FX_RECT rect(left, top, left + pBitmap->GetWidth(),
2356 top + pBitmap->GetHeight());
2357 RetainPtr<CFX_DIBitmap> pBack;
2358 if (m_pBackdropBitmap) {
2359 pBack = m_pBackdropBitmap->Clone(&rect);
2360 if (!pBack)
2361 return true;
2362
2363 pBack->CompositeBitmap(0, 0, pBack->GetWidth(), pBack->GetHeight(),
2364 m_pBitmap, 0, 0, BlendMode::kNormal, nullptr, false);
2365 } else {
2366 pBack = m_pBitmap->Clone(&rect);
2367 if (!pBack)
2368 return true;
2369 }
2370
2371 bool bRet = true;
2372 left = std::min(left, 0);
2373 top = std::min(top, 0);
2374 if (m_bRgbByteOrder) {
2375 RgbByteOrderTransferBitmap(pBitmap, 0, 0, rect.Width(), rect.Height(),
2376 pBack, left, top);
2377 } else {
2378 bRet = pBitmap->TransferBitmap(0, 0, rect.Width(), rect.Height(), pBack,
2379 left, top);
2380 }
2381 return bRet;
2382 #endif // _SKIA_SUPPORT_PATHS_
2383 }
2384
GetBackDrop()2385 RetainPtr<CFX_DIBitmap> CFX_SkiaDeviceDriver::GetBackDrop() {
2386 return m_pBackdropBitmap;
2387 }
2388
SetDIBits(const RetainPtr<CFX_DIBBase> & pBitmap,uint32_t argb,const FX_RECT & src_rect,int left,int top,BlendMode blend_type)2389 bool CFX_SkiaDeviceDriver::SetDIBits(const RetainPtr<CFX_DIBBase>& pBitmap,
2390 uint32_t argb,
2391 const FX_RECT& src_rect,
2392 int left,
2393 int top,
2394 BlendMode blend_type) {
2395 if (!m_pBitmap || !m_pBitmap->GetBuffer())
2396 return true;
2397
2398 #ifdef _SKIA_SUPPORT_
2399 CFX_Matrix m = CFX_RenderDevice::GetFlipMatrix(
2400 pBitmap->GetWidth(), pBitmap->GetHeight(), left, top);
2401 std::unique_ptr<CFX_ImageRenderer> dummy;
2402 return StartDIBits(pBitmap, 0xFF, argb, m, FXDIB_ResampleOptions(), &dummy,
2403 blend_type);
2404 #endif // _SKIA_SUPPORT_
2405
2406 #ifdef _SKIA_SUPPORT_PATHS_
2407 Flush();
2408 if (pBitmap->IsAlphaMask()) {
2409 return m_pBitmap->CompositeMask(left, top, src_rect.Width(),
2410 src_rect.Height(), pBitmap, argb,
2411 src_rect.left, src_rect.top, blend_type,
2412 m_pClipRgn.get(), m_bRgbByteOrder);
2413 }
2414 return m_pBitmap->CompositeBitmap(
2415 left, top, src_rect.Width(), src_rect.Height(), pBitmap, src_rect.left,
2416 src_rect.top, blend_type, m_pClipRgn.get(), m_bRgbByteOrder);
2417 #endif // _SKIA_SUPPORT_PATHS_
2418 }
2419
StretchDIBits(const RetainPtr<CFX_DIBBase> & pSource,uint32_t argb,int dest_left,int dest_top,int dest_width,int dest_height,const FX_RECT * pClipRect,const FXDIB_ResampleOptions & options,BlendMode blend_type)2420 bool CFX_SkiaDeviceDriver::StretchDIBits(const RetainPtr<CFX_DIBBase>& pSource,
2421 uint32_t argb,
2422 int dest_left,
2423 int dest_top,
2424 int dest_width,
2425 int dest_height,
2426 const FX_RECT* pClipRect,
2427 const FXDIB_ResampleOptions& options,
2428 BlendMode blend_type) {
2429 #ifdef _SKIA_SUPPORT_
2430 m_pCache->FlushForDraw();
2431 if (!m_pBitmap->GetBuffer())
2432 return true;
2433
2434 CFX_Matrix m = CFX_RenderDevice::GetFlipMatrix(dest_width, dest_height,
2435 dest_left, dest_top);
2436 SkAutoCanvasRestore scoped_save_restore(m_pCanvas, /*doSave=*/true);
2437 SkRect skClipRect = SkRect::MakeLTRB(pClipRect->left, pClipRect->bottom,
2438 pClipRect->right, pClipRect->top);
2439 m_pCanvas->clipRect(skClipRect, SkClipOp::kIntersect, true);
2440 std::unique_ptr<CFX_ImageRenderer> dummy;
2441 return StartDIBits(pSource, 0xFF, argb, m, FXDIB_ResampleOptions(), &dummy,
2442 blend_type);
2443 #endif // _SKIA_SUPPORT_
2444
2445 #ifdef _SKIA_SUPPORT_PATHS_
2446 if (dest_width == pSource->GetWidth() &&
2447 dest_height == pSource->GetHeight()) {
2448 FX_RECT rect(0, 0, dest_width, dest_height);
2449 return SetDIBits(pSource, argb, rect, dest_left, dest_top, blend_type);
2450 }
2451 Flush();
2452 FX_RECT dest_rect(dest_left, dest_top, dest_left + dest_width,
2453 dest_top + dest_height);
2454 dest_rect.Normalize();
2455 FX_RECT dest_clip = dest_rect;
2456 dest_clip.Intersect(*pClipRect);
2457 CFX_BitmapComposer composer;
2458 composer.Compose(m_pBitmap, m_pClipRgn.get(), 255, argb, dest_clip, false,
2459 false, false, m_bRgbByteOrder, blend_type);
2460 dest_clip.Offset(-dest_rect.left, -dest_rect.top);
2461 CFX_ImageStretcher stretcher(&composer, pSource, dest_width, dest_height,
2462 dest_clip, options);
2463 if (stretcher.Start())
2464 stretcher.Continue(nullptr);
2465 return true;
2466 #endif // _SKIA_SUPPORT_PATHS_
2467 }
2468
StartDIBits(const RetainPtr<CFX_DIBBase> & pSource,int bitmap_alpha,uint32_t argb,const CFX_Matrix & matrix,const FXDIB_ResampleOptions & options,std::unique_ptr<CFX_ImageRenderer> * handle,BlendMode blend_type)2469 bool CFX_SkiaDeviceDriver::StartDIBits(
2470 const RetainPtr<CFX_DIBBase>& pSource,
2471 int bitmap_alpha,
2472 uint32_t argb,
2473 const CFX_Matrix& matrix,
2474 const FXDIB_ResampleOptions& options,
2475 std::unique_ptr<CFX_ImageRenderer>* handle,
2476 BlendMode blend_type) {
2477 #ifdef _SKIA_SUPPORT_
2478 m_pCache->FlushForDraw();
2479 DebugValidate(m_pBitmap, m_pBackdropBitmap);
2480 std::unique_ptr<uint8_t, FxFreeDeleter> dst8Storage;
2481 std::unique_ptr<uint32_t, FxFreeDeleter> dst32Storage;
2482 SkBitmap skBitmap;
2483 int width, height;
2484 if (!Upsample(pSource, dst8Storage, dst32Storage, &skBitmap, &width, &height,
2485 false)) {
2486 return false;
2487 }
2488 {
2489 SkAutoCanvasRestore scoped_save_restore(m_pCanvas, /*doSave=*/true);
2490 SkMatrix skMatrix;
2491 SetBitmapMatrix(matrix, width, height, &skMatrix);
2492 m_pCanvas->concat(skMatrix);
2493 SkPaint paint;
2494 SetBitmapPaint(pSource->IsAlphaMask(), argb, bitmap_alpha, blend_type,
2495 &paint);
2496 // TODO(caryclark) Once Skia supports 8 bit src to 8 bit dst remove this
2497 if (m_pBitmap && m_pBitmap->GetBPP() == 8 && pSource->GetBPP() == 8) {
2498 SkMatrix inv;
2499 SkAssertResult(skMatrix.invert(&inv));
2500 for (int y = 0; y < m_pBitmap->GetHeight(); ++y) {
2501 for (int x = 0; x < m_pBitmap->GetWidth(); ++x) {
2502 SkPoint src = {x + 0.5f, y + 0.5f};
2503 inv.mapPoints(&src, 1);
2504 // TODO(caryclark) Why does the matrix map require clamping?
2505 src.fX = SkTMax(0.5f, SkTMin(src.fX, width - 0.5f));
2506 src.fY = SkTMax(0.5f, SkTMin(src.fY, height - 0.5f));
2507 m_pBitmap->SetPixel(x, y, skBitmap.getColor(src.fX, src.fY));
2508 }
2509 }
2510 } else {
2511 m_pCanvas->drawBitmap(skBitmap, 0, 0, &paint);
2512 }
2513 }
2514 DebugValidate(m_pBitmap, m_pBackdropBitmap);
2515 #endif // _SKIA_SUPPORT_
2516
2517 #ifdef _SKIA_SUPPORT_PATHS_
2518 Flush();
2519 if (!m_pBitmap->GetBuffer())
2520 return true;
2521 m_pBitmap->UnPreMultiply();
2522 *handle = pdfium::MakeUnique<CFX_ImageRenderer>(
2523 m_pBitmap, m_pClipRgn.get(), pSource, bitmap_alpha, argb, matrix, options,
2524 m_bRgbByteOrder);
2525 #endif // _SKIA_SUPPORT_PATHS_
2526 return true;
2527 }
2528
ContinueDIBits(CFX_ImageRenderer * handle,PauseIndicatorIface * pPause)2529 bool CFX_SkiaDeviceDriver::ContinueDIBits(CFX_ImageRenderer* handle,
2530 PauseIndicatorIface* pPause) {
2531 #ifdef _SKIA_SUPPORT_
2532 m_pCache->FlushForDraw();
2533 return false;
2534 #endif // _SKIA_SUPPORT_
2535
2536 #ifdef _SKIA_SUPPORT_PATHS_
2537 Flush();
2538 if (!m_pBitmap->GetBuffer()) {
2539 return true;
2540 }
2541 return handle->Continue(pPause);
2542 #endif // _SKIA_SUPPORT_PATHS_
2543 }
2544
2545 #if defined _SKIA_SUPPORT_
PreMultiply(const RetainPtr<CFX_DIBitmap> & pDIBitmap)2546 void CFX_SkiaDeviceDriver::PreMultiply(
2547 const RetainPtr<CFX_DIBitmap>& pDIBitmap) {
2548 pDIBitmap->PreMultiply();
2549 }
2550 #endif // _SKIA_SUPPORT_
2551
PreMultiply()2552 void CFX_DIBitmap::PreMultiply() {
2553 if (this->GetBPP() != 32)
2554 return;
2555 void* buffer = this->GetBuffer();
2556 if (!buffer)
2557 return;
2558 #if defined _SKIA_SUPPORT_PATHS_
2559 Format priorFormat = m_nFormat;
2560 m_nFormat = Format::kPreMultiplied;
2561 if (priorFormat != Format::kUnPreMultiplied)
2562 return;
2563 #endif
2564 int height = this->GetHeight();
2565 int width = this->GetWidth();
2566 int rowBytes = this->GetPitch();
2567 SkImageInfo unpremultipliedInfo =
2568 SkImageInfo::Make(width, height, kN32_SkColorType, kUnpremul_SkAlphaType);
2569 SkPixmap unpremultiplied(unpremultipliedInfo, buffer, rowBytes);
2570 SkImageInfo premultipliedInfo =
2571 SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
2572 SkPixmap premultiplied(premultipliedInfo, buffer, rowBytes);
2573 unpremultiplied.readPixels(premultiplied);
2574 this->DebugVerifyBitmapIsPreMultiplied(nullptr);
2575 }
2576
2577 #ifdef _SKIA_SUPPORT_PATHS_
UnPreMultiply()2578 void CFX_DIBitmap::UnPreMultiply() {
2579 if (this->GetBPP() != 32)
2580 return;
2581 void* buffer = this->GetBuffer();
2582 if (!buffer)
2583 return;
2584 Format priorFormat = m_nFormat;
2585 m_nFormat = Format::kUnPreMultiplied;
2586 if (priorFormat != Format::kPreMultiplied)
2587 return;
2588 this->DebugVerifyBitmapIsPreMultiplied(nullptr);
2589 int height = this->GetHeight();
2590 int width = this->GetWidth();
2591 int rowBytes = this->GetPitch();
2592 SkImageInfo premultipliedInfo =
2593 SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
2594 SkPixmap premultiplied(premultipliedInfo, buffer, rowBytes);
2595 SkImageInfo unpremultipliedInfo =
2596 SkImageInfo::Make(width, height, kN32_SkColorType, kUnpremul_SkAlphaType);
2597 SkPixmap unpremultiplied(unpremultipliedInfo, buffer, rowBytes);
2598 premultiplied.readPixels(unpremultiplied);
2599 }
2600 #endif // _SKIA_SUPPORT_PATHS_
2601
2602 #ifdef _SKIA_SUPPORT_
DrawBitsWithMask(const RetainPtr<CFX_DIBBase> & pSource,const RetainPtr<CFX_DIBBase> & pMask,int bitmap_alpha,const CFX_Matrix & matrix,BlendMode blend_type)2603 bool CFX_SkiaDeviceDriver::DrawBitsWithMask(
2604 const RetainPtr<CFX_DIBBase>& pSource,
2605 const RetainPtr<CFX_DIBBase>& pMask,
2606 int bitmap_alpha,
2607 const CFX_Matrix& matrix,
2608 BlendMode blend_type) {
2609 DebugValidate(m_pBitmap, m_pBackdropBitmap);
2610 std::unique_ptr<uint8_t, FxFreeDeleter> src8Storage, mask8Storage;
2611 std::unique_ptr<uint32_t, FxFreeDeleter> src32Storage, mask32Storage;
2612 SkBitmap skBitmap, skMask;
2613 int srcWidth, srcHeight, maskWidth, maskHeight;
2614 if (!Upsample(pSource, src8Storage, src32Storage, &skBitmap, &srcWidth,
2615 &srcHeight, false)) {
2616 return false;
2617 }
2618 if (!Upsample(pMask, mask8Storage, mask32Storage, &skMask, &maskWidth,
2619 &maskHeight, true)) {
2620 return false;
2621 }
2622 {
2623 SkAutoCanvasRestore scoped_save_restore(m_pCanvas, /*doSave=*/true);
2624 SkMatrix skMatrix;
2625 SetBitmapMatrix(matrix, srcWidth, srcHeight, &skMatrix);
2626 m_pCanvas->concat(skMatrix);
2627 SkPaint paint;
2628 SetBitmapPaint(pSource->IsAlphaMask(), 0xFFFFFFFF, bitmap_alpha, blend_type,
2629 &paint);
2630 sk_sp<SkImage> skSrc = SkImage::MakeFromBitmap(skBitmap);
2631 sk_sp<SkShader> skSrcShader =
2632 skSrc->makeShader(SkTileMode::kClamp, SkTileMode::kClamp);
2633 sk_sp<SkImage> skMaskImage = SkImage::MakeFromBitmap(skMask);
2634 sk_sp<SkShader> skMaskShader =
2635 skMaskImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp);
2636 paint.setShader(
2637 SkShaders::Blend(SkBlendMode::kSrcIn, skMaskShader, skSrcShader));
2638 SkRect r = {0, 0, SkIntToScalar(srcWidth), SkIntToScalar(srcHeight)};
2639 m_pCanvas->drawRect(r, paint);
2640 }
2641 DebugValidate(m_pBitmap, m_pBackdropBitmap);
2642 return true;
2643 }
2644
SetBitsWithMask(const RetainPtr<CFX_DIBBase> & pBitmap,const RetainPtr<CFX_DIBBase> & pMask,int dest_left,int dest_top,int bitmap_alpha,BlendMode blend_type)2645 bool CFX_SkiaDeviceDriver::SetBitsWithMask(
2646 const RetainPtr<CFX_DIBBase>& pBitmap,
2647 const RetainPtr<CFX_DIBBase>& pMask,
2648 int dest_left,
2649 int dest_top,
2650 int bitmap_alpha,
2651 BlendMode blend_type) {
2652 if (!m_pBitmap || !m_pBitmap->GetBuffer())
2653 return true;
2654
2655 CFX_Matrix m = CFX_RenderDevice::GetFlipMatrix(
2656 pBitmap->GetWidth(), pBitmap->GetHeight(), dest_left, dest_top);
2657 return DrawBitsWithMask(pBitmap, pMask, bitmap_alpha, m, blend_type);
2658 }
2659
Clear(uint32_t color)2660 void CFX_SkiaDeviceDriver::Clear(uint32_t color) {
2661 m_pCanvas->clear(color);
2662 }
2663 #endif // _SKIA_SUPPORT_
2664
Dump() const2665 void CFX_SkiaDeviceDriver::Dump() const {
2666 #if SHOW_SKIA_PATH && defined _SKIA_SUPPORT_
2667 if (m_pCache)
2668 m_pCache->Dump(this);
2669 #endif // SHOW_SKIA_PATH && defined _SKIA_SUPPORT_
2670 }
2671
2672 #ifdef _SKIA_SUPPORT_
DebugVerifyBitmapIsPreMultiplied() const2673 void CFX_SkiaDeviceDriver::DebugVerifyBitmapIsPreMultiplied() const {
2674 if (m_pBackdropBitmap)
2675 m_pBackdropBitmap->DebugVerifyBitmapIsPreMultiplied(nullptr);
2676 }
2677 #endif // _SKIA_SUPPORT_
2678
CFX_DefaultRenderDevice()2679 CFX_DefaultRenderDevice::CFX_DefaultRenderDevice() {}
2680
2681 #ifdef _SKIA_SUPPORT_
Clear(uint32_t color)2682 void CFX_DefaultRenderDevice::Clear(uint32_t color) {
2683 CFX_SkiaDeviceDriver* skDriver =
2684 static_cast<CFX_SkiaDeviceDriver*>(GetDeviceDriver());
2685 skDriver->Clear(color);
2686 }
2687
CreateRecorder(int size_x,int size_y)2688 SkPictureRecorder* CFX_DefaultRenderDevice::CreateRecorder(int size_x,
2689 int size_y) {
2690 CFX_SkiaDeviceDriver* skDriver = new CFX_SkiaDeviceDriver(size_x, size_y);
2691 SetDeviceDriver(pdfium::WrapUnique(skDriver));
2692 return skDriver->GetRecorder();
2693 }
2694 #endif // _SKIA_SUPPORT_
2695
Attach(const RetainPtr<CFX_DIBitmap> & pBitmap,bool bRgbByteOrder,const RetainPtr<CFX_DIBitmap> & pBackdropBitmap,bool bGroupKnockout)2696 bool CFX_DefaultRenderDevice::Attach(
2697 const RetainPtr<CFX_DIBitmap>& pBitmap,
2698 bool bRgbByteOrder,
2699 const RetainPtr<CFX_DIBitmap>& pBackdropBitmap,
2700 bool bGroupKnockout) {
2701 if (!pBitmap)
2702 return false;
2703 SetBitmap(pBitmap);
2704 SetDeviceDriver(pdfium::MakeUnique<CFX_SkiaDeviceDriver>(
2705 pBitmap, bRgbByteOrder, pBackdropBitmap, bGroupKnockout));
2706 return true;
2707 }
2708
2709 #ifdef _SKIA_SUPPORT_
AttachRecorder(SkPictureRecorder * recorder)2710 bool CFX_DefaultRenderDevice::AttachRecorder(SkPictureRecorder* recorder) {
2711 if (!recorder)
2712 return false;
2713 SetDeviceDriver(pdfium::MakeUnique<CFX_SkiaDeviceDriver>(recorder));
2714 return true;
2715 }
2716 #endif // _SKIA_SUPPORT_
2717
Create(int width,int height,FXDIB_Format format,const RetainPtr<CFX_DIBitmap> & pBackdropBitmap)2718 bool CFX_DefaultRenderDevice::Create(
2719 int width,
2720 int height,
2721 FXDIB_Format format,
2722 const RetainPtr<CFX_DIBitmap>& pBackdropBitmap) {
2723 auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
2724 if (!pBitmap->Create(width, height, format)) {
2725 return false;
2726 }
2727 SetBitmap(pBitmap);
2728 SetDeviceDriver(pdfium::MakeUnique<CFX_SkiaDeviceDriver>(
2729 pBitmap, false, pBackdropBitmap, false));
2730 return true;
2731 }
2732
~CFX_DefaultRenderDevice()2733 CFX_DefaultRenderDevice::~CFX_DefaultRenderDevice() {
2734 Flush(true);
2735 }
2736
2737 #ifdef _SKIA_SUPPORT_
DebugVerifyBitmapIsPreMultiplied() const2738 void CFX_DefaultRenderDevice::DebugVerifyBitmapIsPreMultiplied() const {
2739 #ifdef SK_DEBUG
2740 CFX_SkiaDeviceDriver* skDriver =
2741 static_cast<CFX_SkiaDeviceDriver*>(GetDeviceDriver());
2742 if (skDriver)
2743 skDriver->DebugVerifyBitmapIsPreMultiplied();
2744 #endif // SK_DEBUG
2745 }
2746
SetBitsWithMask(const RetainPtr<CFX_DIBBase> & pBitmap,const RetainPtr<CFX_DIBBase> & pMask,int left,int top,int bitmap_alpha,BlendMode blend_type)2747 bool CFX_DefaultRenderDevice::SetBitsWithMask(
2748 const RetainPtr<CFX_DIBBase>& pBitmap,
2749 const RetainPtr<CFX_DIBBase>& pMask,
2750 int left,
2751 int top,
2752 int bitmap_alpha,
2753 BlendMode blend_type) {
2754 CFX_SkiaDeviceDriver* skDriver =
2755 static_cast<CFX_SkiaDeviceDriver*>(GetDeviceDriver());
2756 if (skDriver)
2757 return skDriver->SetBitsWithMask(pBitmap, pMask, left, top, bitmap_alpha,
2758 blend_type);
2759 return false;
2760 }
2761 #endif // _SKIA_SUPPORT_
2762
DebugVerifyBitmapIsPreMultiplied(void * opt) const2763 void CFX_DIBBase::DebugVerifyBitmapIsPreMultiplied(void* opt) const {
2764 #ifdef SK_DEBUG
2765 ASSERT(GetBPP() == 32);
2766 const uint32_t* buffer = (const uint32_t*)(opt ? opt : GetBuffer());
2767 int width = GetWidth();
2768 int height = GetHeight();
2769 // verify that input is really premultiplied
2770 for (int y = 0; y < height; ++y) {
2771 const uint32_t* srcRow = buffer + y * width;
2772 for (int x = 0; x < width; ++x) {
2773 uint8_t a = SkGetPackedA32(srcRow[x]);
2774 uint8_t r = SkGetPackedR32(srcRow[x]);
2775 uint8_t g = SkGetPackedG32(srcRow[x]);
2776 uint8_t b = SkGetPackedB32(srcRow[x]);
2777 SkA32Assert(a);
2778 ASSERT(r <= a);
2779 ASSERT(g <= a);
2780 ASSERT(b <= a);
2781 }
2782 }
2783 #endif // SK_DEBUG
2784 }
2785