xref: /aosp_15_r20/external/pdfium/core/fxge/skia/fx_skia_device.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2014 The PDFium Authors
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 <math.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <algorithm>
12 #include <limits>
13 #include <memory>
14 #include <utility>
15 #include <vector>
16 
17 #include "build/build_config.h"
18 #include "core/fpdfapi/page/cpdf_expintfunc.h"
19 #include "core/fpdfapi/page/cpdf_function.h"
20 #include "core/fpdfapi/page/cpdf_meshstream.h"
21 #include "core/fpdfapi/page/cpdf_sampledfunc.h"
22 #include "core/fpdfapi/page/cpdf_shadingpattern.h"
23 #include "core/fpdfapi/page/cpdf_stitchfunc.h"
24 #include "core/fpdfapi/parser/cpdf_array.h"
25 #include "core/fpdfapi/parser/cpdf_dictionary.h"
26 #include "core/fpdfapi/parser/cpdf_stream.h"
27 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
28 #include "core/fxcrt/cfx_bitstream.h"
29 #include "core/fxcrt/data_vector.h"
30 #include "core/fxcrt/fx_2d_size.h"
31 #include "core/fxcrt/fx_coordinates.h"
32 #include "core/fxcrt/fx_memory.h"
33 #include "core/fxcrt/fx_system.h"
34 #include "core/fxcrt/stl_util.h"
35 #include "core/fxge/cfx_defaultrenderdevice.h"
36 #include "core/fxge/cfx_fillrenderoptions.h"
37 #include "core/fxge/cfx_font.h"
38 #include "core/fxge/cfx_graphstatedata.h"
39 #include "core/fxge/cfx_path.h"
40 #include "core/fxge/cfx_renderdevice.h"
41 #include "core/fxge/cfx_substfont.h"
42 #include "core/fxge/cfx_textrenderoptions.h"
43 #include "core/fxge/dib/cfx_dibitmap.h"
44 #include "core/fxge/dib/cfx_imagerenderer.h"
45 #include "core/fxge/dib/cstretchengine.h"
46 #include "core/fxge/dib/fx_dib.h"
47 #include "core/fxge/text_char_pos.h"
48 #include "third_party/base/check.h"
49 #include "third_party/base/check_op.h"
50 #include "third_party/base/containers/span.h"
51 #include "third_party/base/memory/ptr_util.h"
52 #include "third_party/base/notreached.h"
53 #include "third_party/base/numerics/safe_conversions.h"
54 #include "third_party/skia/include/core/SkBlendMode.h"
55 #include "third_party/skia/include/core/SkCanvas.h"
56 #include "third_party/skia/include/core/SkClipOp.h"
57 #include "third_party/skia/include/core/SkColorFilter.h"
58 #include "third_party/skia/include/core/SkColorPriv.h"
59 #include "third_party/skia/include/core/SkColorType.h"
60 #include "third_party/skia/include/core/SkImage.h"
61 #include "third_party/skia/include/core/SkImageInfo.h"
62 #include "third_party/skia/include/core/SkMaskFilter.h"
63 #include "third_party/skia/include/core/SkPaint.h"
64 #include "third_party/skia/include/core/SkPath.h"
65 #include "third_party/skia/include/core/SkPathEffect.h"
66 #include "third_party/skia/include/core/SkPathUtils.h"
67 #include "third_party/skia/include/core/SkPixmap.h"
68 #include "third_party/skia/include/core/SkRSXform.h"
69 #include "third_party/skia/include/core/SkRect.h"
70 #include "third_party/skia/include/core/SkRefCnt.h"
71 #include "third_party/skia/include/core/SkSamplingOptions.h"
72 #include "third_party/skia/include/core/SkShader.h"
73 #include "third_party/skia/include/core/SkStream.h"
74 #include "third_party/skia/include/core/SkSurface.h"
75 #include "third_party/skia/include/core/SkTextBlob.h"
76 #include "third_party/skia/include/core/SkTileMode.h"
77 #include "third_party/skia/include/core/SkTypeface.h"
78 #include "third_party/skia/include/effects/SkDashPathEffect.h"
79 #include "third_party/skia/include/effects/SkGradientShader.h"
80 #include "third_party/skia/include/pathops/SkPathOps.h"
81 
82 namespace {
83 
84 #define SHOW_SKIA_PATH 0  // set to 1 to print the path contents
85 #if SHOW_SKIA_PATH
86 #define SHOW_SKIA_PATH_SHORTHAND 0  // set to 1 for abbreviated path contents
87 #endif
88 
89 #if SHOW_SKIA_PATH
DebugShowSkiaPaint(const SkPaint & paint)90 void DebugShowSkiaPaint(const SkPaint& paint) {
91   if (SkPaint::kFill_Style == paint.getStyle()) {
92     printf("fill 0x%08x\n", paint.getColor());
93   } else {
94     printf("stroke 0x%08x width %g\n", paint.getColor(),
95            paint.getStrokeWidth());
96   }
97 }
98 #endif  // SHOW_SKIA_PATH
99 
DebugShowSkiaPath(const SkPath & path)100 void DebugShowSkiaPath(const SkPath& path) {
101 #if SHOW_SKIA_PATH
102 #if SHOW_SKIA_PATH_SHORTHAND
103   printf(" **\n");
104 #else
105   SkDynamicMemoryWStream stream;
106   path.dump(&stream, false);
107   DataVector<char> storage(stream.bytesWritten());
108   stream.copyTo(storage.data());
109   printf("%.*s", static_cast<int>(storage.size()), storage.data());
110 #endif  // SHOW_SKIA_PATH_SHORTHAND
111 #endif  // SHOW_SKIA_PATH
112 }
113 
DebugShowCanvasClip(CFX_SkiaDeviceDriver * driver,const SkCanvas * canvas)114 void DebugShowCanvasClip(CFX_SkiaDeviceDriver* driver, const SkCanvas* canvas) {
115 #if SHOW_SKIA_PATH
116   SkMatrix matrix = canvas->getTotalMatrix();
117   SkScalar m[9];
118   matrix.get9(m);
119   printf("matrix (%g,%g,%g) (%g,%g,%g) (%g,%g,%g)\n", m[0], m[1], m[2], m[3],
120          m[4], m[5], m[6], m[7], m[8]);
121   SkRect local = canvas->getLocalClipBounds();
122   SkIRect device = canvas->getDeviceClipBounds();
123 
124   printf("local bounds %g %g %g %g\n", local.fLeft, local.fTop, local.fRight,
125          local.fBottom);
126   printf("device bounds %d %d %d %d\n", device.fLeft, device.fTop,
127          device.fRight, device.fBottom);
128   FX_RECT clipBox;
129   driver->GetClipBox(&clipBox);
130   printf("reported bounds %d %d %d %d\n", clipBox.left, clipBox.top,
131          clipBox.right, clipBox.bottom);
132 #endif  // SHOW_SKIA_PATH
133 }
134 
DebugShowSkiaDrawPath(CFX_SkiaDeviceDriver * driver,const SkCanvas * canvas,const SkPaint & paint,const SkPath & path)135 void DebugShowSkiaDrawPath(CFX_SkiaDeviceDriver* driver,
136                            const SkCanvas* canvas,
137                            const SkPaint& paint,
138                            const SkPath& path) {
139 #if SHOW_SKIA_PATH
140   DebugShowSkiaPaint(paint);
141   DebugShowCanvasClip(driver, canvas);
142   DebugShowSkiaPath(path);
143   printf("\n");
144 #endif  // SHOW_SKIA_PATH
145 }
146 
DebugShowSkiaDrawRect(CFX_SkiaDeviceDriver * driver,const SkCanvas * canvas,const SkPaint & paint,const SkRect & rect)147 void DebugShowSkiaDrawRect(CFX_SkiaDeviceDriver* driver,
148                            const SkCanvas* canvas,
149                            const SkPaint& paint,
150                            const SkRect& rect) {
151 #if SHOW_SKIA_PATH
152   DebugShowSkiaPaint(paint);
153   DebugShowCanvasClip(driver, canvas);
154   printf("rect %g %g %g %g\n", rect.fLeft, rect.fTop, rect.fRight,
155          rect.fBottom);
156 #endif  // SHOW_SKIA_PATH
157 }
158 
DebugValidate(const RetainPtr<CFX_DIBitmap> & bitmap,const RetainPtr<CFX_DIBitmap> & device)159 static void DebugValidate(const RetainPtr<CFX_DIBitmap>& bitmap,
160                           const RetainPtr<CFX_DIBitmap>& device) {
161   if (bitmap) {
162     DCHECK(bitmap->GetBPP() == 8 || bitmap->GetBPP() == 32);
163   }
164   if (device) {
165     DCHECK(device->GetBPP() == 8 || device->GetBPP() == 32);
166   }
167 }
168 
Get32BitSkColorType(bool is_rgb_byte_order)169 SkColorType Get32BitSkColorType(bool is_rgb_byte_order) {
170   return is_rgb_byte_order ? kRGBA_8888_SkColorType : kBGRA_8888_SkColorType;
171 }
172 
GetAlternateOrWindingFillType(const CFX_FillRenderOptions & fill_options)173 SkPathFillType GetAlternateOrWindingFillType(
174     const CFX_FillRenderOptions& fill_options) {
175   // TODO(thestig): This function should be able to assert
176   // fill_options.fill_type != CFX_FillRenderOptions::FillType::kNoFill.
177   return fill_options.fill_type == CFX_FillRenderOptions::FillType::kEvenOdd
178              ? SkPathFillType::kEvenOdd
179              : SkPathFillType::kWinding;
180 }
181 
GetFontEdgingType(const CFX_TextRenderOptions & text_options)182 SkFont::Edging GetFontEdgingType(const CFX_TextRenderOptions& text_options) {
183   if (text_options.aliasing_type == CFX_TextRenderOptions::kAliasing)
184     return SkFont::Edging::kAlias;
185 
186   if (text_options.aliasing_type == CFX_TextRenderOptions::kAntiAliasing)
187     return SkFont::Edging::kAntiAlias;
188 
189   DCHECK_EQ(text_options.aliasing_type, CFX_TextRenderOptions::kLcd);
190   return SkFont::Edging::kSubpixelAntiAlias;
191 }
192 
IsPathAPoint(const SkPath & path)193 bool IsPathAPoint(const SkPath& path) {
194   if (path.isEmpty())
195     return false;
196 
197   if (path.countPoints() == 1)
198     return true;
199 
200   for (int i = 0; i < path.countPoints() - 1; ++i) {
201     if (path.getPoint(i) != path.getPoint(i + 1))
202       return false;
203   }
204   return true;
205 }
206 
BuildPath(const CFX_Path & path)207 SkPath BuildPath(const CFX_Path& path) {
208   SkPath sk_path;
209   pdfium::span<const CFX_Path::Point> points = path.GetPoints();
210   for (size_t i = 0; i < points.size(); ++i) {
211     const CFX_PointF& point = points[i].m_Point;
212     CFX_Path::Point::Type point_type = points[i].m_Type;
213     if (point_type == CFX_Path::Point::Type::kMove) {
214       sk_path.moveTo(point.x, point.y);
215     } else if (point_type == CFX_Path::Point::Type::kLine) {
216       sk_path.lineTo(point.x, point.y);
217     } else if (point_type == CFX_Path::Point::Type::kBezier) {
218       const CFX_PointF& point2 = points[i + 1].m_Point;
219       const CFX_PointF& point3 = points[i + 2].m_Point;
220       sk_path.cubicTo(point.x, point.y, point2.x, point2.y, point3.x, point3.y);
221       i += 2;
222     }
223     if (points[i].m_CloseFigure)
224       sk_path.close();
225   }
226   return sk_path;
227 }
228 
ToSkMatrix(const CFX_Matrix & m)229 SkMatrix ToSkMatrix(const CFX_Matrix& m) {
230   SkMatrix skMatrix;
231   skMatrix.setAll(m.a, m.c, m.e, m.b, m.d, m.f, 0, 0, 1);
232   return skMatrix;
233 }
234 
235 // use when pdf's y-axis points up instead of down
ToFlippedSkMatrix(const CFX_Matrix & m,SkScalar flip)236 SkMatrix ToFlippedSkMatrix(const CFX_Matrix& m, SkScalar flip) {
237   SkMatrix skMatrix;
238   skMatrix.setAll(m.a * flip, -m.c * flip, m.e, m.b * flip, -m.d * flip, m.f, 0,
239                   0, 1);
240   return skMatrix;
241 }
242 
GetSkiaBlendMode(BlendMode blend_type)243 SkBlendMode GetSkiaBlendMode(BlendMode blend_type) {
244   switch (blend_type) {
245     case BlendMode::kMultiply:
246       return SkBlendMode::kMultiply;
247     case BlendMode::kScreen:
248       return SkBlendMode::kScreen;
249     case BlendMode::kOverlay:
250       return SkBlendMode::kOverlay;
251     case BlendMode::kDarken:
252       return SkBlendMode::kDarken;
253     case BlendMode::kLighten:
254       return SkBlendMode::kLighten;
255     case BlendMode::kColorDodge:
256       return SkBlendMode::kColorDodge;
257     case BlendMode::kColorBurn:
258       return SkBlendMode::kColorBurn;
259     case BlendMode::kHardLight:
260       return SkBlendMode::kHardLight;
261     case BlendMode::kSoftLight:
262       return SkBlendMode::kSoftLight;
263     case BlendMode::kDifference:
264       return SkBlendMode::kDifference;
265     case BlendMode::kExclusion:
266       return SkBlendMode::kExclusion;
267     case BlendMode::kHue:
268       return SkBlendMode::kHue;
269     case BlendMode::kSaturation:
270       return SkBlendMode::kSaturation;
271     case BlendMode::kColor:
272       return SkBlendMode::kColor;
273     case BlendMode::kLuminosity:
274       return SkBlendMode::kLuminosity;
275     case BlendMode::kNormal:
276       return SkBlendMode::kSrcOver;
277   }
278 }
279 
280 // Add begin & end colors into `colors` array for each gradient transition.
281 //
282 // `is_encode_reversed` must be set to true when the parent function of `func`
283 // has an Encode array, and the matching pair of encode values for `func` are
284 // in decreasing order.
AddColors(const CPDF_ExpIntFunc * func,DataVector<SkColor> & colors,bool is_encode_reversed)285 bool AddColors(const CPDF_ExpIntFunc* func,
286                DataVector<SkColor>& colors,
287                bool is_encode_reversed) {
288   if (func->CountInputs() != 1) {
289     return false;
290   }
291   if (func->GetExponent() != 1) {
292     return false;
293   }
294   if (func->GetOrigOutputs() != 3) {
295     return false;
296   }
297 
298   pdfium::span<const float> begin_values = func->GetBeginValues();
299   pdfium::span<const float> end_values = func->GetEndValues();
300   if (is_encode_reversed)
301     std::swap(begin_values, end_values);
302 
303   colors.push_back(SkColorSetARGB(0xFF,
304                                   SkUnitScalarClampToByte(begin_values[0]),
305                                   SkUnitScalarClampToByte(begin_values[1]),
306                                   SkUnitScalarClampToByte(begin_values[2])));
307   colors.push_back(SkColorSetARGB(0xFF, SkUnitScalarClampToByte(end_values[0]),
308                                   SkUnitScalarClampToByte(end_values[1]),
309                                   SkUnitScalarClampToByte(end_values[2])));
310   return true;
311 }
312 
FloatToByte(float f)313 uint8_t FloatToByte(float f) {
314   DCHECK(f >= 0);
315   DCHECK(f <= 1);
316   return (uint8_t)(f * 255.99f);
317 }
318 
AddSamples(const CPDF_SampledFunc * func,DataVector<SkColor> & colors,DataVector<SkScalar> & pos)319 bool AddSamples(const CPDF_SampledFunc* func,
320                 DataVector<SkColor>& colors,
321                 DataVector<SkScalar>& pos) {
322   if (func->CountInputs() != 1) {
323     return false;
324   }
325   if (func->CountOutputs() != 3) {  // expect rgb
326     return false;
327   }
328   if (func->GetEncodeInfo().empty()) {
329     return false;
330   }
331   const CPDF_SampledFunc::SampleEncodeInfo& encode_info =
332       func->GetEncodeInfo()[0];
333   if (encode_info.encode_min != 0) {
334     return false;
335   }
336   if (encode_info.encode_max != encode_info.sizes - 1) {
337     return false;
338   }
339   uint32_t sample_size = func->GetBitsPerSample();
340   uint32_t sample_count = encode_info.sizes;
341   if (sample_count != 1U << sample_size) {
342     return false;
343   }
344   if (func->GetSampleStream()->GetSize() < sample_count * 3 * sample_size / 8) {
345     return false;
346   }
347 
348   float colors_min[3];
349   float colors_max[3];
350   for (int i = 0; i < 3; ++i) {
351     colors_min[i] = func->GetRange(i * 2);
352     colors_max[i] = func->GetRange(i * 2 + 1);
353   }
354   pdfium::span<const uint8_t> sample_data = func->GetSampleStream()->GetSpan();
355   CFX_BitStream bitstream(sample_data);
356   for (uint32_t i = 0; i < sample_count; ++i) {
357     float float_colors[3];
358     for (uint32_t j = 0; j < 3; ++j) {
359       float sample = static_cast<float>(bitstream.GetBits(sample_size));
360       float interp = sample / (sample_count - 1);
361       float_colors[j] =
362           colors_min[j] + (colors_max[j] - colors_min[j]) * interp;
363     }
364     colors.push_back(SkPackARGB32NoCheck(0xFF, FloatToByte(float_colors[0]),
365                                          FloatToByte(float_colors[1]),
366                                          FloatToByte(float_colors[2])));
367     pos.push_back(static_cast<float>(i) / (sample_count - 1));
368   }
369   return true;
370 }
371 
AddStitching(const CPDF_StitchFunc * func,DataVector<SkColor> & colors,DataVector<SkScalar> & pos)372 bool AddStitching(const CPDF_StitchFunc* func,
373                   DataVector<SkColor>& colors,
374                   DataVector<SkScalar>& pos) {
375   float bounds_start = func->GetDomain(0);
376 
377   const auto& sub_functions = func->GetSubFunctions();
378   const size_t sub_function_count = sub_functions.size();
379   for (size_t i = 0; i < sub_function_count; ++i) {
380     const CPDF_ExpIntFunc* sub_func = sub_functions[i]->ToExpIntFunc();
381     if (!sub_func)
382       return false;
383     // Check if the matching encode values are reversed
384     bool is_encode_reversed =
385         func->GetEncode(2 * i) > func->GetEncode(2 * i + 1);
386     if (!AddColors(sub_func, colors, is_encode_reversed)) {
387       return false;
388     }
389     float bounds_end =
390         i < sub_function_count - 1 ? func->GetBound(i + 1) : func->GetDomain(1);
391     pos.push_back(bounds_start);
392     pos.push_back(bounds_end);
393     bounds_start = bounds_end;
394   }
395   return true;
396 }
397 
398 // see https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
LineSide(const SkPoint line[2],const SkPoint & pt)399 SkScalar LineSide(const SkPoint line[2], const SkPoint& pt) {
400   return (line[1].fY - line[0].fY) * pt.fX - (line[1].fX - line[0].fX) * pt.fY +
401          line[1].fX * line[0].fY - line[1].fY * line[0].fX;
402 }
403 
IntersectSides(const SkPoint & parallelPt,const SkVector & paraRay,const SkPoint & perpendicularPt)404 SkPoint IntersectSides(const SkPoint& parallelPt,
405                        const SkVector& paraRay,
406                        const SkPoint& perpendicularPt) {
407   SkVector perpRay = {paraRay.fY, -paraRay.fX};
408   SkScalar denom = perpRay.fY * paraRay.fX - paraRay.fY * perpRay.fX;
409   if (!denom) {
410     SkPoint zeroPt = {0, 0};
411     return zeroPt;
412   }
413   SkVector ab0 = parallelPt - perpendicularPt;
414   SkScalar numerA = ab0.fY * perpRay.fX - perpRay.fY * ab0.fX;
415   numerA /= denom;
416   SkPoint result = {parallelPt.fX + paraRay.fX * numerA,
417                     parallelPt.fY + paraRay.fY * numerA};
418   return result;
419 }
420 
ClipAngledGradient(const SkPoint pts[2],SkPoint rectPts[4],bool clipStart,bool clipEnd,SkPath * clip)421 void ClipAngledGradient(const SkPoint pts[2],
422                         SkPoint rectPts[4],
423                         bool clipStart,
424                         bool clipEnd,
425                         SkPath* clip) {
426   // find the corners furthest from the gradient perpendiculars
427   SkScalar minPerpDist = SK_ScalarMax;
428   SkScalar maxPerpDist = SK_ScalarMin;
429   int minPerpPtIndex = -1;
430   int maxPerpPtIndex = -1;
431   SkVector slope = pts[1] - pts[0];
432   SkPoint startPerp[2] = {pts[0], {pts[0].fX + slope.fY, pts[0].fY - slope.fX}};
433   SkPoint endPerp[2] = {pts[1], {pts[1].fX + slope.fY, pts[1].fY - slope.fX}};
434   for (int i = 0; i < 4; ++i) {
435     SkScalar sDist = LineSide(startPerp, rectPts[i]);
436     SkScalar eDist = LineSide(endPerp, rectPts[i]);
437     if (sDist * eDist <= 0)  // if the signs are different,
438       continue;              // the point is inside the gradient
439     if (sDist < 0) {
440       SkScalar smaller = std::min(sDist, eDist);
441       if (minPerpDist > smaller) {
442         minPerpDist = smaller;
443         minPerpPtIndex = i;
444       }
445     } else {
446       SkScalar larger = std::max(sDist, eDist);
447       if (maxPerpDist < larger) {
448         maxPerpDist = larger;
449         maxPerpPtIndex = i;
450       }
451     }
452   }
453   if (minPerpPtIndex < 0 && maxPerpPtIndex < 0)  // nothing's outside
454     return;
455 
456   // determine if negative distances are before start or after end
457   SkPoint beforeStart = {pts[0].fX * 2 - pts[1].fX, pts[0].fY * 2 - pts[1].fY};
458   bool beforeNeg = LineSide(startPerp, beforeStart) < 0;
459 
460   int noClipStartIndex = maxPerpPtIndex;
461   int noClipEndIndex = minPerpPtIndex;
462   if (beforeNeg)
463     std::swap(noClipStartIndex, noClipEndIndex);
464   if ((!clipStart && noClipStartIndex < 0) ||
465       (!clipEnd && noClipEndIndex < 0)) {
466     return;
467   }
468 
469   const SkPoint& startEdgePt = clipStart ? pts[0] : rectPts[noClipStartIndex];
470   const SkPoint& endEdgePt = clipEnd ? pts[1] : rectPts[noClipEndIndex];
471 
472   // find the corners that bound the gradient
473   SkScalar minDist = SK_ScalarMax;
474   SkScalar maxDist = SK_ScalarMin;
475   int minBounds = -1;
476   int maxBounds = -1;
477   for (int i = 0; i < 4; ++i) {
478     SkScalar dist = LineSide(pts, rectPts[i]);
479     if (minDist > dist) {
480       minDist = dist;
481       minBounds = i;
482     }
483     if (maxDist < dist) {
484       maxDist = dist;
485       maxBounds = i;
486     }
487   }
488   if (minBounds < 0 || maxBounds < 0)
489     return;
490   if (minBounds == maxBounds)
491     return;
492   // construct a clip parallel to the gradient that goes through
493   // rectPts[minBounds] and rectPts[maxBounds] and perpendicular to the
494   // gradient that goes through startEdgePt, endEdgePt.
495   clip->moveTo(IntersectSides(rectPts[minBounds], slope, startEdgePt));
496   clip->lineTo(IntersectSides(rectPts[minBounds], slope, endEdgePt));
497   clip->lineTo(IntersectSides(rectPts[maxBounds], slope, endEdgePt));
498   clip->lineTo(IntersectSides(rectPts[maxBounds], slope, startEdgePt));
499 }
500 
501 // Converts a stroking path to scanlines
PaintStroke(SkPaint * spaint,const CFX_GraphStateData * graph_state,const SkMatrix & matrix,const CFX_FillRenderOptions & fill_options)502 void PaintStroke(SkPaint* spaint,
503                  const CFX_GraphStateData* graph_state,
504                  const SkMatrix& matrix,
505                  const CFX_FillRenderOptions& fill_options) {
506   SkPaint::Cap cap;
507   switch (graph_state->m_LineCap) {
508     case CFX_GraphStateData::LineCap::kRound:
509       cap = SkPaint::kRound_Cap;
510       break;
511     case CFX_GraphStateData::LineCap::kSquare:
512       cap = SkPaint::kSquare_Cap;
513       break;
514     default:
515       cap = SkPaint::kButt_Cap;
516       break;
517   }
518   SkPaint::Join join;
519   switch (graph_state->m_LineJoin) {
520     case CFX_GraphStateData::LineJoin::kRound:
521       join = SkPaint::kRound_Join;
522       break;
523     case CFX_GraphStateData::LineJoin::kBevel:
524       join = SkPaint::kBevel_Join;
525       break;
526     default:
527       join = SkPaint::kMiter_Join;
528       break;
529   }
530   SkMatrix inverse;
531   if (!matrix.invert(&inverse)) {
532     return;  // give up if the matrix is degenerate, and not invertable
533   }
534   inverse.set(SkMatrix::kMTransX, 0);
535   inverse.set(SkMatrix::kMTransY, 0);
536   SkVector deviceUnits[2] = {{0, 1}, {1, 0}};
537   inverse.mapPoints(deviceUnits, std::size(deviceUnits));
538 
539   float width = fill_options.zero_area
540                     ? 0.0f
541                     : std::max(graph_state->m_LineWidth,
542                                std::min(deviceUnits[0].length(),
543                                         deviceUnits[1].length()));
544   if (!graph_state->m_DashArray.empty()) {
545     size_t count = (graph_state->m_DashArray.size() + 1) / 2;
546     DataVector<SkScalar> intervals(count * 2);
547     // Set dash pattern
548     for (size_t i = 0; i < count; i++) {
549       float on = graph_state->m_DashArray[i * 2];
550       if (on <= 0.000001f) {
551         on = 0.1f;
552       }
553       float off = i * 2 + 1 == graph_state->m_DashArray.size()
554                       ? on
555                       : graph_state->m_DashArray[i * 2 + 1];
556       off = std::max(off, 0.0f);
557       intervals[i * 2] = on;
558       intervals[i * 2 + 1] = off;
559     }
560     spaint->setPathEffect(SkDashPathEffect::Make(
561         intervals.data(), pdfium::base::checked_cast<int>(intervals.size()),
562         graph_state->m_DashPhase));
563   }
564   spaint->setStyle(SkPaint::kStroke_Style);
565   spaint->setAntiAlias(!fill_options.aliased_path);
566   spaint->setStrokeWidth(width);
567   spaint->setStrokeMiter(graph_state->m_MiterLimit);
568   spaint->setStrokeCap(cap);
569   spaint->setStrokeJoin(join);
570 }
571 
SetBitmapMatrix(const CFX_Matrix & m,int width,int height,SkMatrix * skMatrix)572 void SetBitmapMatrix(const CFX_Matrix& m,
573                      int width,
574                      int height,
575                      SkMatrix* skMatrix) {
576   skMatrix->setAll(m.a / width, -m.c / height, m.c + m.e, m.b / width,
577                    -m.d / height, m.d + m.f, 0, 0, 1);
578 }
579 
SetBitmapPaint(bool is_mask,bool anti_alias,int bitmap_alpha,uint32_t argb,BlendMode blend_type,SkPaint * paint)580 void SetBitmapPaint(bool is_mask,
581                     bool anti_alias,
582                     int bitmap_alpha,
583                     uint32_t argb,
584                     BlendMode blend_type,
585                     SkPaint* paint) {
586   DCHECK_GE(bitmap_alpha, 0);
587   DCHECK_LE(bitmap_alpha, 255);
588 
589   if (is_mask)
590     paint->setColor(argb);
591   else if (bitmap_alpha != 255)
592     paint->setAlpha(bitmap_alpha);
593 
594   paint->setAntiAlias(anti_alias);
595   paint->setBlendMode(GetSkiaBlendMode(blend_type));
596 }
597 
SetBitmapPaintForMerge(bool is_mask,bool anti_alias,uint32_t argb,int bitmap_alpha,BlendMode blend_type,SkPaint * paint)598 void SetBitmapPaintForMerge(bool is_mask,
599                             bool anti_alias,
600                             uint32_t argb,
601                             int bitmap_alpha,
602                             BlendMode blend_type,
603                             SkPaint* paint) {
604   if (is_mask)
605     paint->setColorFilter(SkColorFilters::Blend(argb, SkBlendMode::kSrc));
606 
607   paint->setAlpha(bitmap_alpha);
608   paint->setAntiAlias(anti_alias);
609   paint->setBlendMode(GetSkiaBlendMode(blend_type));
610 }
611 
612 // Makes a bitmap filled with a solid color for debugging with `SkPicture`.
MakeDebugBitmap(int width,int height,uint32_t color)613 RetainPtr<CFX_DIBitmap> MakeDebugBitmap(int width, int height, uint32_t color) {
614   auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
615   if (!bitmap->Create(width, height, FXDIB_Format::kArgb))
616     return nullptr;
617 
618   bitmap->Clear(color);
619   return bitmap;
620 }
621 
HasRSX(pdfium::span<const TextCharPos> char_pos,float * scaleXPtr,bool * oneAtATimePtr)622 bool HasRSX(pdfium::span<const TextCharPos> char_pos,
623             float* scaleXPtr,
624             bool* oneAtATimePtr) {
625   bool useRSXform = false;
626   bool oneAtATime = false;
627   float scaleX = 1;
628   for (const TextCharPos& cp : char_pos) {
629     if (!cp.m_bGlyphAdjust) {
630       continue;
631     }
632     bool upright = 0 == cp.m_AdjustMatrix[1] && 0 == cp.m_AdjustMatrix[2];
633     if (cp.m_AdjustMatrix[0] != cp.m_AdjustMatrix[3]) {
634       if (upright && 1 == cp.m_AdjustMatrix[3]) {
635         if (1 == scaleX) {
636           scaleX = cp.m_AdjustMatrix[0];
637         } else if (scaleX != cp.m_AdjustMatrix[0]) {
638           oneAtATime = true;
639         }
640       } else {
641         oneAtATime = true;
642       }
643     } else if (cp.m_AdjustMatrix[1] != -cp.m_AdjustMatrix[2]) {
644       oneAtATime = true;
645     } else {
646       useRSXform = true;
647     }
648   }
649   *oneAtATimePtr = oneAtATime;
650   *scaleXPtr = oneAtATime ? 1 : scaleX;
651   return oneAtATime ? false : useRSXform;
652 }
653 
654 }  // namespace
655 
656 // static
Create(RetainPtr<CFX_DIBitmap> pBitmap,bool bRgbByteOrder,RetainPtr<CFX_DIBitmap> pBackdropBitmap,bool bGroupKnockout)657 std::unique_ptr<CFX_SkiaDeviceDriver> CFX_SkiaDeviceDriver::Create(
658     RetainPtr<CFX_DIBitmap> pBitmap,
659     bool bRgbByteOrder,
660     RetainPtr<CFX_DIBitmap> pBackdropBitmap,
661     bool bGroupKnockout) {
662   auto driver = pdfium::WrapUnique(
663       new CFX_SkiaDeviceDriver(std::move(pBitmap), bRgbByteOrder,
664                                std::move(pBackdropBitmap), bGroupKnockout));
665   if (!driver->m_pCanvas) {
666     return nullptr;
667   }
668 
669   return driver;
670 }
671 
CFX_SkiaDeviceDriver(RetainPtr<CFX_DIBitmap> pBitmap,bool bRgbByteOrder,RetainPtr<CFX_DIBitmap> pBackdropBitmap,bool bGroupKnockout)672 CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(
673     RetainPtr<CFX_DIBitmap> pBitmap,
674     bool bRgbByteOrder,
675     RetainPtr<CFX_DIBitmap> pBackdropBitmap,
676     bool bGroupKnockout)
677     : m_pBitmap(std::move(pBitmap)),
678       m_pBackdropBitmap(pBackdropBitmap),
679       m_bRgbByteOrder(bRgbByteOrder),
680       m_bGroupKnockout(bGroupKnockout) {
681   SkColorType color_type;
682   const int bpp = m_pBitmap->GetBPP();
683   if (bpp == 8) {
684     color_type = m_pBitmap->IsAlphaFormat() || m_pBitmap->IsMaskFormat()
685                      ? kAlpha_8_SkColorType
686                      : kGray_8_SkColorType;
687   } else if (bpp == 24) {
688     DCHECK_EQ(m_pBitmap->GetFormat(), FXDIB_Format::kRgb);
689 
690     // Save the input bitmap as `m_pOriginalBitmap` and save its 32 bpp
691     // equivalent at `m_pBitmap` for Skia's internal process.
692     m_pOriginalBitmap = std::move(m_pBitmap);
693     m_pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
694     if (!m_pBitmap->Copy(m_pOriginalBitmap) ||
695         !m_pBitmap->ConvertFormat(FXDIB_Format::kArgb)) {
696       // Skip creating SkCanvas if we fail to create the 32 bpp bitmap to back
697       // it.
698       return;
699     }
700 
701     color_type = Get32BitSkColorType(bRgbByteOrder);
702   } else {
703     DCHECK_EQ(bpp, 32);
704     color_type = Get32BitSkColorType(bRgbByteOrder);
705   }
706 
707   SkImageInfo imageInfo =
708       SkImageInfo::Make(m_pBitmap->GetWidth(), m_pBitmap->GetHeight(),
709                         color_type, kPremul_SkAlphaType);
710   surface_ = SkSurfaces::WrapPixels(
711       imageInfo, m_pBitmap->GetWritableBuffer().data(), m_pBitmap->GetPitch());
712   m_pCanvas = surface_->getCanvas();
713 }
714 
CFX_SkiaDeviceDriver(SkCanvas * canvas)715 CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(SkCanvas* canvas)
716     : m_pCanvas(canvas), m_bGroupKnockout(false) {
717   int width = m_pCanvas->imageInfo().width();
718   int height = m_pCanvas->imageInfo().height();
719   DCHECK_EQ(kUnknown_SkColorType, m_pCanvas->imageInfo().colorType());
720 
721   constexpr uint32_t kMagenta = 0xffff00ff;
722   constexpr uint32_t kGreen = 0xff00ff00;
723   m_pBitmap = MakeDebugBitmap(width, height, kMagenta);
724   m_pBackdropBitmap = MakeDebugBitmap(width, height, kGreen);
725 }
726 
~CFX_SkiaDeviceDriver()727 CFX_SkiaDeviceDriver::~CFX_SkiaDeviceDriver() {
728   // Convert and transfer the internal processed result to the original 24 bpp
729   // bitmap provided by the render device.
730   if (m_pOriginalBitmap && m_pBitmap->ConvertFormat(FXDIB_Format::kRgb)) {
731     int width = m_pOriginalBitmap->GetWidth();
732     int height = m_pOriginalBitmap->GetHeight();
733     DCHECK_EQ(width, m_pBitmap->GetWidth());
734     DCHECK_EQ(height, m_pBitmap->GetHeight());
735     DCHECK_EQ(FXDIB_Format::kRgb, m_pOriginalBitmap->GetFormat());
736     m_pOriginalBitmap->TransferBitmap(/*dest_left=*/0, /*dest_top=*/0, width,
737                                       height, m_pBitmap, /*src_left=*/0,
738                                       /*src_top=*/0);
739   }
740 }
741 
DrawDeviceText(pdfium::span<const TextCharPos> pCharPos,CFX_Font * pFont,const CFX_Matrix & mtObject2Device,float font_size,uint32_t color,const CFX_TextRenderOptions & options)742 bool CFX_SkiaDeviceDriver::DrawDeviceText(
743     pdfium::span<const TextCharPos> pCharPos,
744     CFX_Font* pFont,
745     const CFX_Matrix& mtObject2Device,
746     float font_size,
747     uint32_t color,
748     const CFX_TextRenderOptions& options) {
749   // `SkTextBlob` is built from `pFont`'s font data. If `pFont` doesn't contain
750   // any font data, each text blob will have zero area to be drawn and the
751   // drawing command will be rejected. In this case, we fall back to drawing
752   // characters by their glyph bitmaps.
753   if (pFont->GetFontSpan().empty())
754     return false;
755 
756   if (TryDrawText(pCharPos, pFont, mtObject2Device, font_size, color,
757                   options)) {
758     return true;
759   }
760   sk_sp<SkTypeface> typeface(SkSafeRef(pFont->GetDeviceCache()));
761   SkPaint paint;
762   paint.setAntiAlias(true);
763   paint.setColor(color);
764 
765   SkFont font;
766   font.setTypeface(typeface);
767   font.setEmbolden(pFont->IsSubstFontBold());
768   font.setHinting(SkFontHinting::kNone);
769   font.setSize(SkTAbs(font_size));
770   font.setSubpixel(true);
771   font.setSkewX(tanf(pFont->GetSubstFontItalicAngle() * FXSYS_PI / 180.0));
772   font.setEdging(GetFontEdgingType(options));
773 
774   SkAutoCanvasRestore scoped_save_restore(m_pCanvas, /*doSave=*/true);
775   const SkScalar flip = font_size < 0 ? -1 : 1;
776   const SkScalar vFlip = pFont->IsVertical() ? -1 : 1;
777   SkMatrix skMatrix = ToFlippedSkMatrix(mtObject2Device, flip);
778   m_pCanvas->concat(skMatrix);
779   DataVector<SkPoint> positions(pCharPos.size());
780   DataVector<uint16_t> glyphs(pCharPos.size());
781 
782   for (size_t index = 0; index < pCharPos.size(); ++index) {
783     const TextCharPos& cp = pCharPos[index];
784     positions[index] = {cp.m_Origin.x * flip, cp.m_Origin.y * vFlip};
785     glyphs[index] = static_cast<uint16_t>(cp.m_GlyphIndex);
786 #if BUILDFLAG(IS_APPLE)
787     if (cp.m_ExtGID)
788       glyphs[index] = static_cast<uint16_t>(cp.m_ExtGID);
789 #endif
790   }
791 
792   for (size_t index = 0; index < pCharPos.size(); ++index) {
793     const TextCharPos& cp = pCharPos[index];
794     if (cp.m_bGlyphAdjust) {
795       if (0 == cp.m_AdjustMatrix[1] && 0 == cp.m_AdjustMatrix[2] &&
796           1 == cp.m_AdjustMatrix[3]) {
797         font.setScaleX(cp.m_AdjustMatrix[0]);
798         auto blob =
799             SkTextBlob::MakeFromText(&glyphs[index], sizeof(glyphs[index]),
800                                      font, SkTextEncoding::kGlyphID);
801         m_pCanvas->drawTextBlob(blob, positions[index].fX, positions[index].fY,
802                                 paint);
803         font.setScaleX(SkIntToScalar(1));
804       } else {
805         SkAutoCanvasRestore scoped_save_restore2(m_pCanvas, /*doSave=*/true);
806         SkMatrix adjust;
807         adjust.preTranslate(positions[index].fX, -positions[index].fY);
808         adjust.setScaleX(cp.m_AdjustMatrix[0]);
809         adjust.setSkewX(cp.m_AdjustMatrix[1]);
810         adjust.setSkewY(cp.m_AdjustMatrix[2]);
811         adjust.setScaleY(cp.m_AdjustMatrix[3]);
812         m_pCanvas->concat(adjust);
813         auto blob =
814             SkTextBlob::MakeFromText(&glyphs[index], sizeof(glyphs[index]),
815                                      font, SkTextEncoding::kGlyphID);
816         m_pCanvas->drawTextBlob(blob, 0, 0, paint);
817       }
818     } else {
819       auto blob =
820           SkTextBlob::MakeFromText(&glyphs[index], sizeof(glyphs[index]), font,
821                                    SkTextEncoding::kGlyphID);
822       m_pCanvas->drawTextBlob(blob, positions[index].fX, positions[index].fY,
823                               paint);
824     }
825   }
826   return true;
827 }
828 
829 // TODO(crbug.com/pdfium/1999): Merge with `DrawDeviceText()` and refactor
830 // common logic.
831 // TODO(crbug.com/pdfium/1774): Sometimes the thickness of the glyphs is not
832 // ideal. Improve text rendering results regarding different font weight.
TryDrawText(pdfium::span<const TextCharPos> char_pos,const CFX_Font * pFont,const CFX_Matrix & matrix,float font_size,uint32_t color,const CFX_TextRenderOptions & options)833 bool CFX_SkiaDeviceDriver::TryDrawText(pdfium::span<const TextCharPos> char_pos,
834                                        const CFX_Font* pFont,
835                                        const CFX_Matrix& matrix,
836                                        float font_size,
837                                        uint32_t color,
838                                        const CFX_TextRenderOptions& options) {
839   float scaleX = 1;
840   bool oneAtATime = false;
841   bool hasRSX = HasRSX(char_pos, &scaleX, &oneAtATime);
842   if (oneAtATime) {
843     return false;
844   }
845 
846   m_charDetails.SetCount(0);
847   m_rsxform.resize(0);
848 
849   const size_t original_count = m_charDetails.Count();
850   FX_SAFE_SIZE_T safe_count = original_count;
851   safe_count += char_pos.size();
852   const size_t total_count = safe_count.ValueOrDie();
853   m_charDetails.SetCount(total_count);
854   if (hasRSX) {
855     m_rsxform.resize(total_count);
856   }
857 
858   const SkScalar flip = font_size < 0 ? -1 : 1;
859   const SkScalar vFlip = pFont->IsVertical() ? -1 : 1;
860   for (size_t index = 0; index < char_pos.size(); ++index) {
861     const TextCharPos& cp = char_pos[index];
862     size_t cur_index = index + original_count;
863     m_charDetails.SetPositionAt(cur_index,
864                                 {cp.m_Origin.x * flip, cp.m_Origin.y * vFlip});
865     m_charDetails.SetGlyphAt(cur_index, static_cast<uint16_t>(cp.m_GlyphIndex));
866     m_charDetails.SetFontCharWidthAt(cur_index, cp.m_FontCharWidth);
867 #if BUILDFLAG(IS_APPLE)
868     if (cp.m_ExtGID) {
869       m_charDetails.SetGlyphAt(cur_index, static_cast<uint16_t>(cp.m_ExtGID));
870     }
871 #endif
872   }
873   if (hasRSX) {
874     const DataVector<SkPoint>& positions = m_charDetails.GetPositions();
875     for (size_t index = 0; index < char_pos.size(); ++index) {
876       const TextCharPos& cp = char_pos[index];
877       SkRSXform& rsxform = m_rsxform[index + original_count];
878       if (cp.m_bGlyphAdjust) {
879         rsxform.fSCos = cp.m_AdjustMatrix[0];
880         rsxform.fSSin = cp.m_AdjustMatrix[1];
881         rsxform.fTx = cp.m_AdjustMatrix[0] * positions[index].fX;
882         rsxform.fTy = -cp.m_AdjustMatrix[3] * positions[index].fY;
883       } else {
884         rsxform.fSCos = 1;
885         rsxform.fSSin = 0;
886         rsxform.fTx = positions[index].fX;
887         rsxform.fTy = positions[index].fY;
888       }
889     }
890   }
891 
892   SkPaint skPaint;
893   skPaint.setAntiAlias(true);
894   skPaint.setColor(color);
895 
896   SkFont font;
897   if (pFont->GetFaceRec()) {  // exclude placeholder test fonts
898     font.setTypeface(sk_ref_sp(pFont->GetDeviceCache()));
899   }
900   font.setEmbolden(pFont->IsSubstFontBold());
901   font.setHinting(SkFontHinting::kNone);
902   font.setScaleX(scaleX);
903   font.setSkewX(tanf(pFont->GetSubstFontItalicAngle() * FXSYS_PI / 180.0));
904   font.setSize(SkTAbs(font_size));
905   font.setSubpixel(true);
906   font.setEdging(GetFontEdgingType(options));
907 
908   SkAutoCanvasRestore scoped_save_restore(m_pCanvas, /*doSave=*/true);
909   m_pCanvas->concat(ToFlippedSkMatrix(matrix, flip));
910 
911   const DataVector<uint16_t>& glyphs = m_charDetails.GetGlyphs();
912   if (m_rsxform.size()) {
913     sk_sp<SkTextBlob> blob = SkTextBlob::MakeFromRSXform(
914         glyphs.data(), glyphs.size() * sizeof(uint16_t), m_rsxform.data(), font,
915         SkTextEncoding::kGlyphID);
916     m_pCanvas->drawTextBlob(blob, 0, 0, skPaint);
917     return true;
918   }
919   const DataVector<SkPoint>& positions = m_charDetails.GetPositions();
920   const DataVector<uint32_t>& widths = m_charDetails.GetFontCharWidths();
921   for (size_t i = 0; i < m_charDetails.Count(); ++i) {
922     const uint32_t font_glyph_width =
923         pFont ? pFont->GetGlyphWidth(glyphs[i]) : 0;
924     const uint32_t pdf_glyph_width = widths[i];
925     if (pdf_glyph_width > 0 && font_glyph_width > 0) {
926       // Scale the glyph from its default width `pdf_glyph_width` to the
927       // targeted width `pdf_glyph_width`.
928       font.setScaleX(scaleX * SkIntToScalar(pdf_glyph_width) /
929                      font_glyph_width);
930     } else {
931       font.setScaleX(scaleX);
932     }
933     auto blob =
934         SkTextBlob::MakeFromPosText(&glyphs[i], sizeof(uint16_t), &positions[i],
935                                     font, SkTextEncoding::kGlyphID);
936     m_pCanvas->drawTextBlob(blob, 0, 0, skPaint);
937   }
938   return true;
939 }
940 
GetDriverType() const941 int CFX_SkiaDeviceDriver::GetDriverType() const {
942   return 1;
943 }
944 
MultiplyAlpha(float alpha)945 bool CFX_SkiaDeviceDriver::MultiplyAlpha(float alpha) {
946   SkPaint paint;
947   paint.setAlphaf(alpha);
948   paint.setBlendMode(SkBlendMode::kDstIn);
949   m_pCanvas->drawPaint(paint);
950   return true;
951 }
952 
MultiplyAlpha(const RetainPtr<CFX_DIBBase> & mask)953 bool CFX_SkiaDeviceDriver::MultiplyAlpha(const RetainPtr<CFX_DIBBase>& mask) {
954   CHECK(mask->IsMaskFormat());
955 
956   sk_sp<SkImage> skia_mask = mask->RealizeSkImage();
957   if (!skia_mask) {
958     return false;
959   }
960   DCHECK_EQ(skia_mask->colorType(), kAlpha_8_SkColorType);
961 
962   SkPaint paint;
963   paint.setBlendMode(SkBlendMode::kDstIn);
964   m_pCanvas->drawImageRect(skia_mask,
965                            SkRect::Make(m_pCanvas->imageInfo().bounds()),
966                            SkSamplingOptions(), &paint);
967   return true;
968 }
969 
GetDeviceType() const970 DeviceType CFX_SkiaDeviceDriver::GetDeviceType() const {
971   return DeviceType::kDisplay;
972 }
973 
GetDeviceCaps(int caps_id) const974 int CFX_SkiaDeviceDriver::GetDeviceCaps(int caps_id) const {
975   switch (caps_id) {
976     case FXDC_PIXEL_WIDTH:
977       return m_pCanvas->imageInfo().width();
978     case FXDC_PIXEL_HEIGHT:
979       return m_pCanvas->imageInfo().height();
980     case FXDC_BITS_PIXEL:
981       return 32;
982     case FXDC_HORZ_SIZE:
983     case FXDC_VERT_SIZE:
984       return 0;
985     case FXDC_RENDER_CAPS:
986       return FXRC_GET_BITS | FXRC_ALPHA_PATH | FXRC_ALPHA_IMAGE |
987              FXRC_BLEND_MODE | FXRC_SOFT_CLIP | FXRC_ALPHA_OUTPUT |
988              FXRC_FILLSTROKE_PATH | FXRC_SHADING;
989     default:
990       NOTREACHED_NORETURN();
991   }
992 }
993 
SaveState()994 void CFX_SkiaDeviceDriver::SaveState() {
995   m_pCanvas->save();
996 }
997 
RestoreState(bool bKeepSaved)998 void CFX_SkiaDeviceDriver::RestoreState(bool bKeepSaved) {
999   m_pCanvas->restore();
1000   if (bKeepSaved) {
1001     m_pCanvas->save();
1002   }
1003 }
1004 
SetClip_PathFill(const CFX_Path & path,const CFX_Matrix * pObject2Device,const CFX_FillRenderOptions & fill_options)1005 bool CFX_SkiaDeviceDriver::SetClip_PathFill(
1006     const CFX_Path& path,              // path info
1007     const CFX_Matrix* pObject2Device,  // flips object's y-axis
1008     const CFX_FillRenderOptions& fill_options) {
1009   m_FillOptions = fill_options;
1010   const CFX_Matrix& deviceMatrix =
1011       pObject2Device ? *pObject2Device : CFX_Matrix();
1012 
1013   SkPath skClipPath;
1014   if (path.GetPoints().size() == 5 || path.GetPoints().size() == 4) {
1015     absl::optional<CFX_FloatRect> maybe_rectf = path.GetRect(&deviceMatrix);
1016     if (maybe_rectf.has_value()) {
1017       CFX_FloatRect& rectf = maybe_rectf.value();
1018       rectf.Intersect(CFX_FloatRect(0, 0,
1019                                     (float)GetDeviceCaps(FXDC_PIXEL_WIDTH),
1020                                     (float)GetDeviceCaps(FXDC_PIXEL_HEIGHT)));
1021       FX_RECT outer = rectf.GetOuterRect();
1022       // note that PDF's y-axis goes up; Skia's y-axis goes down
1023       skClipPath.addRect({(float)outer.left, (float)outer.bottom,
1024                           (float)outer.right, (float)outer.top});
1025     }
1026   }
1027   if (skClipPath.isEmpty()) {
1028     skClipPath = BuildPath(path);
1029     skClipPath.setFillType(GetAlternateOrWindingFillType(fill_options));
1030     skClipPath.transform(ToSkMatrix(deviceMatrix));
1031     DebugShowSkiaPath(skClipPath);
1032   }
1033   m_pCanvas->clipPath(skClipPath, SkClipOp::kIntersect, true);
1034   DebugShowCanvasClip(this, m_pCanvas);
1035   return true;
1036 }
1037 
SetClip_PathStroke(const CFX_Path & path,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState)1038 bool CFX_SkiaDeviceDriver::SetClip_PathStroke(
1039     const CFX_Path& path,                  // path info
1040     const CFX_Matrix* pObject2Device,      // required transformation
1041     const CFX_GraphStateData* pGraphState  // graphic state, for pen attributes
1042 ) {
1043   SkPath skPath = BuildPath(path);
1044   SkMatrix skMatrix = ToSkMatrix(*pObject2Device);
1045   SkPaint skPaint;
1046   PaintStroke(&skPaint, pGraphState, skMatrix, CFX_FillRenderOptions());
1047   SkPath dst_path;
1048   skpathutils::FillPathWithPaint(skPath, skPaint, &dst_path);
1049   dst_path.transform(skMatrix);
1050   m_pCanvas->clipPath(dst_path, SkClipOp::kIntersect, true);
1051   DebugShowCanvasClip(this, m_pCanvas);
1052   return true;
1053 }
1054 
1055 // TODO(crbug.com/pdfium/1963): `blend_type` isn't used?
DrawPath(const CFX_Path & path,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState,uint32_t fill_color,uint32_t stroke_color,const CFX_FillRenderOptions & fill_options,BlendMode blend_type)1056 bool CFX_SkiaDeviceDriver::DrawPath(
1057     const CFX_Path& path,                   // path info
1058     const CFX_Matrix* pObject2Device,       // optional transformation
1059     const CFX_GraphStateData* pGraphState,  // graphic state, for pen attributes
1060     uint32_t fill_color,                    // fill color
1061     uint32_t stroke_color,                  // stroke color
1062     const CFX_FillRenderOptions& fill_options,
1063     BlendMode blend_type) {
1064   m_FillOptions = fill_options;
1065 
1066   SkPath skia_path = BuildPath(path);
1067   skia_path.setFillType(GetAlternateOrWindingFillType(fill_options));
1068 
1069   SkMatrix skMatrix = pObject2Device ? ToSkMatrix(*pObject2Device) : SkMatrix();
1070   SkPaint skPaint;
1071   skPaint.setAntiAlias(!fill_options.aliased_path);
1072   if (fill_options.full_cover) {
1073     skPaint.setBlendMode(SkBlendMode::kPlus);
1074   }
1075   int stroke_alpha = FXARGB_A(stroke_color);
1076   if (stroke_alpha) {
1077     const CFX_GraphStateData& graph_state =
1078         pGraphState ? *pGraphState : CFX_GraphStateData();
1079     PaintStroke(&skPaint, &graph_state, skMatrix, fill_options);
1080   }
1081 
1082   SkAutoCanvasRestore scoped_save_restore(m_pCanvas, /*doSave=*/true);
1083   m_pCanvas->concat(skMatrix);
1084   bool do_stroke = true;
1085   if (fill_options.fill_type != CFX_FillRenderOptions::FillType::kNoFill &&
1086       fill_color) {
1087     SkPath strokePath;
1088     const SkPath* fillPath = &skia_path;
1089     if (stroke_alpha) {
1090       if (m_bGroupKnockout) {
1091         skpathutils::FillPathWithPaint(skia_path, skPaint, &strokePath);
1092         if (stroke_color == fill_color &&
1093             Op(skia_path, strokePath, SkPathOp::kUnion_SkPathOp, &strokePath)) {
1094           fillPath = &strokePath;
1095           do_stroke = false;
1096         } else if (Op(skia_path, strokePath, SkPathOp::kDifference_SkPathOp,
1097                       &strokePath)) {
1098           fillPath = &strokePath;
1099         }
1100       }
1101     }
1102     skPaint.setStyle(SkPaint::kFill_Style);
1103     skPaint.setColor(fill_color);
1104     DebugShowSkiaDrawPath(this, m_pCanvas, skPaint, *fillPath);
1105     m_pCanvas->drawPath(*fillPath, skPaint);
1106   }
1107   if (stroke_alpha && do_stroke) {
1108     skPaint.setStyle(SkPaint::kStroke_Style);
1109     skPaint.setColor(stroke_color);
1110     if (!skia_path.isLastContourClosed() && IsPathAPoint(skia_path)) {
1111       DCHECK_GE(skia_path.countPoints(), 1);
1112       m_pCanvas->drawPoint(skia_path.getPoint(0), skPaint);
1113     } else if (IsPathAPoint(skia_path) &&
1114                skPaint.getStrokeCap() != SkPaint::kRound_Cap) {
1115       // Do nothing. A closed 0-length closed path can be rendered only if
1116       // its line cap type is round.
1117     } else {
1118       DebugShowSkiaDrawPath(this, m_pCanvas, skPaint, skia_path);
1119       m_pCanvas->drawPath(skia_path, skPaint);
1120     }
1121   }
1122   return true;
1123 }
1124 
DrawCosmeticLine(const CFX_PointF & ptMoveTo,const CFX_PointF & ptLineTo,uint32_t color,BlendMode blend_type)1125 bool CFX_SkiaDeviceDriver::DrawCosmeticLine(const CFX_PointF& ptMoveTo,
1126                                             const CFX_PointF& ptLineTo,
1127                                             uint32_t color,
1128                                             BlendMode blend_type) {
1129   return false;
1130 }
1131 
FillRectWithBlend(const FX_RECT & rect,uint32_t fill_color,BlendMode blend_type)1132 bool CFX_SkiaDeviceDriver::FillRectWithBlend(const FX_RECT& rect,
1133                                              uint32_t fill_color,
1134                                              BlendMode blend_type) {
1135   SkPaint spaint;
1136   spaint.setAntiAlias(true);
1137   spaint.setColor(fill_color);
1138   spaint.setBlendMode(GetSkiaBlendMode(blend_type));
1139   SkRect srect = SkRect::MakeLTRB(rect.left, std::min(rect.top, rect.bottom),
1140                                   rect.right, std::max(rect.bottom, rect.top));
1141   DebugShowSkiaDrawRect(this, m_pCanvas, spaint, srect);
1142   m_pCanvas->drawRect(srect, spaint);
1143   return true;
1144 }
1145 
DrawShading(const CPDF_ShadingPattern * pPattern,const CFX_Matrix * pMatrix,const FX_RECT & clip_rect,int alpha,bool bAlphaMode)1146 bool CFX_SkiaDeviceDriver::DrawShading(const CPDF_ShadingPattern* pPattern,
1147                                        const CFX_Matrix* pMatrix,
1148                                        const FX_RECT& clip_rect,
1149                                        int alpha,
1150                                        bool bAlphaMode) {
1151   ShadingType shadingType = pPattern->GetShadingType();
1152   if (kAxialShading != shadingType && kRadialShading != shadingType &&
1153       kCoonsPatchMeshShading != shadingType) {
1154     // TODO(caryclark) more types
1155     return false;
1156   }
1157   CPDF_ColorSpace::Family csFamily = pPattern->GetCS()->GetFamily();
1158   if (CPDF_ColorSpace::Family::kDeviceRGB != csFamily &&
1159       CPDF_ColorSpace::Family::kDeviceGray != csFamily) {
1160     return false;
1161   }
1162   const std::vector<std::unique_ptr<CPDF_Function>>& pFuncs =
1163       pPattern->GetFuncs();
1164   size_t nFuncs = pFuncs.size();
1165   if (nFuncs > 1)  // TODO(caryclark) remove this restriction
1166     return false;
1167   RetainPtr<const CPDF_Dictionary> pDict =
1168       pPattern->GetShadingObject()->GetDict();
1169   RetainPtr<const CPDF_Array> pCoords = pDict->GetArrayFor("Coords");
1170   if (!pCoords && kCoonsPatchMeshShading != shadingType)
1171     return false;
1172   // TODO(caryclark) Respect Domain[0], Domain[1]. (Don't know what they do
1173   // yet.)
1174   DataVector<SkColor> sk_colors;
1175   DataVector<SkScalar> sk_pos;
1176   for (size_t j = 0; j < nFuncs; j++) {
1177     if (!pFuncs[j])
1178       continue;
1179 
1180     if (const CPDF_SampledFunc* pSampledFunc = pFuncs[j]->ToSampledFunc()) {
1181       /* TODO(caryclark)
1182          Type 0 Sampled Functions in PostScript can also have an Order integer
1183          in the dictionary. PDFium doesn't appear to check for this anywhere.
1184        */
1185       if (!AddSamples(pSampledFunc, sk_colors, sk_pos)) {
1186         return false;
1187       }
1188     } else if (const CPDF_ExpIntFunc* pExpIntFuc = pFuncs[j]->ToExpIntFunc()) {
1189       if (!AddColors(pExpIntFuc, sk_colors, /*is_encode_reversed=*/false)) {
1190         return false;
1191       }
1192       sk_pos.push_back(0);
1193       sk_pos.push_back(1);
1194     } else if (const CPDF_StitchFunc* pStitchFunc = pFuncs[j]->ToStitchFunc()) {
1195       if (!AddStitching(pStitchFunc, sk_colors, sk_pos)) {
1196         return false;
1197       }
1198     } else {
1199       return false;
1200     }
1201   }
1202   RetainPtr<const CPDF_Array> pArray = pDict->GetArrayFor("Extend");
1203   bool clipStart = !pArray || !pArray->GetIntegerAt(0);
1204   bool clipEnd = !pArray || !pArray->GetIntegerAt(1);
1205   SkPaint paint;
1206   paint.setAntiAlias(true);
1207   paint.setAlpha(alpha);
1208   SkMatrix skMatrix = ToSkMatrix(*pMatrix);
1209   SkRect skRect = SkRect::MakeLTRB(clip_rect.left, clip_rect.top,
1210                                    clip_rect.right, clip_rect.bottom);
1211   SkPath skClip;
1212   SkPath skPath;
1213   if (kAxialShading == shadingType) {
1214     float start_x = pCoords->GetFloatAt(0);
1215     float start_y = pCoords->GetFloatAt(1);
1216     float end_x = pCoords->GetFloatAt(2);
1217     float end_y = pCoords->GetFloatAt(3);
1218     SkPoint pts[] = {{start_x, start_y}, {end_x, end_y}};
1219     skMatrix.mapPoints(pts, std::size(pts));
1220     paint.setShader(SkGradientShader::MakeLinear(
1221         pts, sk_colors.data(), sk_pos.data(),
1222         fxcrt::CollectionSize<int>(sk_colors), SkTileMode::kClamp));
1223     if (clipStart || clipEnd) {
1224       // if the gradient is horizontal or vertical, modify the draw rectangle
1225       if (pts[0].fX == pts[1].fX) {  // vertical
1226         if (pts[0].fY > pts[1].fY) {
1227           std::swap(pts[0].fY, pts[1].fY);
1228           std::swap(clipStart, clipEnd);
1229         }
1230         if (clipStart)
1231           skRect.fTop = std::max(skRect.fTop, pts[0].fY);
1232         if (clipEnd)
1233           skRect.fBottom = std::min(skRect.fBottom, pts[1].fY);
1234       } else if (pts[0].fY == pts[1].fY) {  // horizontal
1235         if (pts[0].fX > pts[1].fX) {
1236           std::swap(pts[0].fX, pts[1].fX);
1237           std::swap(clipStart, clipEnd);
1238         }
1239         if (clipStart)
1240           skRect.fLeft = std::max(skRect.fLeft, pts[0].fX);
1241         if (clipEnd)
1242           skRect.fRight = std::min(skRect.fRight, pts[1].fX);
1243       } else {  // if the gradient is angled and contained by the rect, clip
1244         SkPoint rectPts[4] = {{skRect.fLeft, skRect.fTop},
1245                               {skRect.fRight, skRect.fTop},
1246                               {skRect.fRight, skRect.fBottom},
1247                               {skRect.fLeft, skRect.fBottom}};
1248         ClipAngledGradient(pts, rectPts, clipStart, clipEnd, &skClip);
1249       }
1250     }
1251     skPath.addRect(skRect);
1252     skMatrix.setIdentity();
1253   } else if (kRadialShading == shadingType) {
1254     float start_x = pCoords->GetFloatAt(0);
1255     float start_y = pCoords->GetFloatAt(1);
1256     float start_r = pCoords->GetFloatAt(2);
1257     float end_x = pCoords->GetFloatAt(3);
1258     float end_y = pCoords->GetFloatAt(4);
1259     float end_r = pCoords->GetFloatAt(5);
1260     SkPoint pts[] = {{start_x, start_y}, {end_x, end_y}};
1261 
1262     paint.setShader(SkGradientShader::MakeTwoPointConical(
1263         pts[0], start_r, pts[1], end_r, sk_colors.data(), sk_pos.data(),
1264         fxcrt::CollectionSize<int>(sk_colors), SkTileMode::kClamp));
1265     if (clipStart || clipEnd) {
1266       if (clipStart && start_r)
1267         skClip.addCircle(pts[0].fX, pts[0].fY, start_r);
1268       if (clipEnd)
1269         skClip.addCircle(pts[1].fX, pts[1].fY, end_r, SkPathDirection::kCCW);
1270       else
1271         skClip.setFillType(SkPathFillType::kInverseWinding);
1272       skClip.transform(skMatrix);
1273     }
1274     SkMatrix inverse;
1275     if (!skMatrix.invert(&inverse))
1276       return false;
1277     skPath.addRect(skRect);
1278     skPath.transform(inverse);
1279   } else {
1280     DCHECK_EQ(kCoonsPatchMeshShading, shadingType);
1281     RetainPtr<const CPDF_Stream> pStream =
1282         ToStream(pPattern->GetShadingObject());
1283     if (!pStream)
1284       return false;
1285     CPDF_MeshStream stream(shadingType, pPattern->GetFuncs(),
1286                            std::move(pStream), pPattern->GetCS());
1287     if (!stream.Load())
1288       return false;
1289     SkPoint cubics[12];
1290     SkColor colors[4];
1291     SkAutoCanvasRestore scoped_save_restore(m_pCanvas, /*doSave=*/true);
1292     if (!skClip.isEmpty())
1293       m_pCanvas->clipPath(skClip, SkClipOp::kIntersect, true);
1294     m_pCanvas->concat(skMatrix);
1295     while (!stream.IsEOF()) {
1296       uint32_t flag = stream.ReadFlag();
1297       size_t start_point = flag ? 4 : 0;
1298       size_t start_color = flag ? 2 : 0;
1299       if (flag) {
1300         SkPoint temp_cubics[4];
1301         for (size_t i = 0; i < std::size(temp_cubics); ++i) {
1302           temp_cubics[i] = cubics[(flag * 3 + i) % 12];
1303         }
1304         std::copy(std::begin(temp_cubics), std::end(temp_cubics),
1305                   std::begin(cubics));
1306         SkColor temp_colors[2] = {colors[flag % 4], colors[(flag + 1) % 4]};
1307         std::copy(std::begin(temp_colors), std::end(temp_colors),
1308                   std::begin(colors));
1309       }
1310       for (size_t i = start_point; i < std::size(cubics); ++i) {
1311         CFX_PointF point = stream.ReadCoords();
1312         cubics[i].fX = point.x;
1313         cubics[i].fY = point.y;
1314       }
1315       for (size_t i = start_color; i < std::size(colors); ++i) {
1316         float r;
1317         float g;
1318         float b;
1319         std::tie(r, g, b) = stream.ReadColor();
1320         colors[i] = SkColorSetARGB(0xFF, (U8CPU)(r * 255), (U8CPU)(g * 255),
1321                                    (U8CPU)(b * 255));
1322       }
1323       m_pCanvas->drawPatch(cubics, colors, /*textCoords=*/nullptr,
1324                            SkBlendMode::kDst, paint);
1325     }
1326     return true;
1327   }
1328   SkAutoCanvasRestore scoped_save_restore(m_pCanvas, /*doSave=*/true);
1329   if (!skClip.isEmpty())
1330     m_pCanvas->clipPath(skClip, SkClipOp::kIntersect, true);
1331   m_pCanvas->concat(skMatrix);
1332   m_pCanvas->drawPath(skPath, paint);
1333   return true;
1334 }
1335 
GetClipBox(FX_RECT * pRect)1336 bool CFX_SkiaDeviceDriver::GetClipBox(FX_RECT* pRect) {
1337   SkIRect clip = m_pCanvas->getDeviceClipBounds();
1338   pRect->left = clip.fLeft;
1339   pRect->top = clip.fTop;
1340   pRect->right = clip.fRight;
1341   pRect->bottom = clip.fBottom;
1342   return true;
1343 }
1344 
GetDIBits(const RetainPtr<CFX_DIBitmap> & pBitmap,int left,int top)1345 bool CFX_SkiaDeviceDriver::GetDIBits(const RetainPtr<CFX_DIBitmap>& pBitmap,
1346                                      int left,
1347                                      int top) {
1348   if (!m_pBitmap)
1349     return true;
1350 
1351   const uint8_t* input_buffer = m_pBitmap->GetBuffer().data();
1352   if (!input_buffer) {
1353     return true;
1354   }
1355 
1356   uint8_t* output_buffer = pBitmap->GetWritableBuffer().data();
1357   DCHECK(output_buffer);
1358 
1359   SkImageInfo input_info =
1360       SkImageInfo::Make(m_pBitmap->GetWidth(), m_pBitmap->GetHeight(),
1361                         SkColorType::kN32_SkColorType, kPremul_SkAlphaType);
1362   sk_sp<SkImage> input = SkImages::RasterFromPixmap(
1363       SkPixmap(input_info, input_buffer, m_pBitmap->GetPitch()),
1364       /*rasterReleaseProc=*/nullptr, /*releaseContext=*/nullptr);
1365 
1366   SkImageInfo output_info = SkImageInfo::Make(
1367       pBitmap->GetWidth(), pBitmap->GetHeight(),
1368       Get32BitSkColorType(m_bRgbByteOrder), kPremul_SkAlphaType);
1369   sk_sp<SkSurface> output =
1370       SkSurfaces::WrapPixels(output_info, output_buffer, pBitmap->GetPitch());
1371 
1372   output->getCanvas()->drawImage(input, left, top, SkSamplingOptions());
1373   return true;
1374 }
1375 
GetBackDrop()1376 RetainPtr<CFX_DIBitmap> CFX_SkiaDeviceDriver::GetBackDrop() {
1377   return m_pBackdropBitmap;
1378 }
1379 
SetDIBits(const RetainPtr<CFX_DIBBase> & pBitmap,uint32_t argb,const FX_RECT & src_rect,int left,int top,BlendMode blend_type)1380 bool CFX_SkiaDeviceDriver::SetDIBits(const RetainPtr<CFX_DIBBase>& pBitmap,
1381                                      uint32_t argb,
1382                                      const FX_RECT& src_rect,
1383                                      int left,
1384                                      int top,
1385                                      BlendMode blend_type) {
1386   if (!m_pBitmap || m_pBitmap->GetBuffer().empty())
1387     return true;
1388 
1389   CFX_Matrix m = CFX_RenderDevice::GetFlipMatrix(
1390       pBitmap->GetWidth(), pBitmap->GetHeight(), left, top);
1391 
1392   // `bNoSmoothing` prevents linear sampling when rendering bitmaps.
1393   FXDIB_ResampleOptions sampling_options;
1394   sampling_options.bNoSmoothing = true;
1395 
1396   return StartDIBitsSkia(pBitmap, src_rect, 0xFF, argb, m, sampling_options,
1397                          blend_type);
1398 }
1399 
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)1400 bool CFX_SkiaDeviceDriver::StretchDIBits(const RetainPtr<CFX_DIBBase>& pSource,
1401                                          uint32_t argb,
1402                                          int dest_left,
1403                                          int dest_top,
1404                                          int dest_width,
1405                                          int dest_height,
1406                                          const FX_RECT* pClipRect,
1407                                          const FXDIB_ResampleOptions& options,
1408                                          BlendMode blend_type) {
1409   if (m_pBitmap->GetBuffer().empty())
1410     return true;
1411 
1412   CFX_Matrix m = CFX_RenderDevice::GetFlipMatrix(dest_width, dest_height,
1413                                                  dest_left, dest_top);
1414   SkAutoCanvasRestore scoped_save_restore(m_pCanvas, /*doSave=*/true);
1415   SkRect skClipRect = SkRect::MakeLTRB(pClipRect->left, pClipRect->bottom,
1416                                        pClipRect->right, pClipRect->top);
1417   m_pCanvas->clipRect(skClipRect, SkClipOp::kIntersect, true);
1418 
1419   // `bNoSmoothing` prevents linear sampling when rendering bitmaps.
1420   FXDIB_ResampleOptions sampling_options;
1421   sampling_options.bNoSmoothing = true;
1422 
1423   return StartDIBitsSkia(
1424       pSource, FX_RECT(0, 0, pSource->GetWidth(), pSource->GetHeight()), 0xFF,
1425       argb, m, sampling_options, blend_type);
1426 }
1427 
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)1428 bool CFX_SkiaDeviceDriver::StartDIBits(
1429     const RetainPtr<CFX_DIBBase>& pSource,
1430     int bitmap_alpha,
1431     uint32_t argb,
1432     const CFX_Matrix& matrix,
1433     const FXDIB_ResampleOptions& options,
1434     std::unique_ptr<CFX_ImageRenderer>* handle,
1435     BlendMode blend_type) {
1436   return StartDIBitsSkia(
1437       pSource, FX_RECT(0, 0, pSource->GetWidth(), pSource->GetHeight()),
1438       bitmap_alpha, argb, matrix, options, blend_type);
1439 }
1440 
ContinueDIBits(CFX_ImageRenderer * handle,PauseIndicatorIface * pPause)1441 bool CFX_SkiaDeviceDriver::ContinueDIBits(CFX_ImageRenderer* handle,
1442                                           PauseIndicatorIface* pPause) {
1443   return false;
1444 }
1445 
UnPreMultiply()1446 void CFX_DIBitmap::UnPreMultiply() {
1447   if (GetBPP() != 32)
1448     return;
1449 
1450   void* buffer = GetWritableBuffer().data();
1451   if (!buffer)
1452     return;
1453 
1454   Format prior_format = m_nFormat;
1455   m_nFormat = Format::kUnPreMultiplied;
1456   if (prior_format == Format::kUnPreMultiplied)
1457     return;
1458 
1459   int height = GetHeight();
1460   int width = GetWidth();
1461   int row_bytes = GetPitch();
1462   SkImageInfo premultiplied_info =
1463       SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
1464   SkPixmap premultiplied(premultiplied_info, buffer, row_bytes);
1465   SkImageInfo unpremultiplied_info =
1466       SkImageInfo::Make(width, height, kN32_SkColorType, kUnpremul_SkAlphaType);
1467   SkPixmap unpremultiplied(unpremultiplied_info, buffer, row_bytes);
1468   premultiplied.readPixels(unpremultiplied);
1469 }
1470 
ForcePreMultiply()1471 void CFX_DIBitmap::ForcePreMultiply() {
1472   m_nFormat = Format::kPreMultiplied;
1473 }
1474 
IsPremultiplied() const1475 bool CFX_DIBitmap::IsPremultiplied() const {
1476   return m_nFormat == Format::kPreMultiplied;
1477 }
1478 
DrawBitsWithMask(const RetainPtr<CFX_DIBBase> & pSource,const RetainPtr<CFX_DIBBase> & pMask,int bitmap_alpha,const CFX_Matrix & matrix,BlendMode blend_type)1479 bool CFX_SkiaDeviceDriver::DrawBitsWithMask(
1480     const RetainPtr<CFX_DIBBase>& pSource,
1481     const RetainPtr<CFX_DIBBase>& pMask,
1482     int bitmap_alpha,
1483     const CFX_Matrix& matrix,
1484     BlendMode blend_type) {
1485   DebugValidate(m_pBitmap, m_pBackdropBitmap);
1486 
1487   sk_sp<SkImage> skia_source = pSource->RealizeSkImage();
1488   if (!skia_source) {
1489     return false;
1490   }
1491 
1492   DCHECK(pMask->IsMaskFormat());
1493   sk_sp<SkImage> skia_mask = pMask->RealizeSkImage();
1494   if (!skia_mask) {
1495     return false;
1496   }
1497   DCHECK_EQ(skia_mask->colorType(), kAlpha_8_SkColorType);
1498 
1499   {
1500     SkAutoCanvasRestore scoped_save_restore(m_pCanvas, /*doSave=*/true);
1501 
1502     const int src_width = pSource->GetWidth();
1503     const int src_height = pSource->GetHeight();
1504     SkMatrix skMatrix;
1505     SetBitmapMatrix(matrix, src_width, src_height, &skMatrix);
1506     m_pCanvas->concat(skMatrix);
1507     SkPaint paint;
1508     SetBitmapPaintForMerge(pSource->IsMaskFormat(), !m_FillOptions.aliased_path,
1509                            0xFFFFFFFF, bitmap_alpha, blend_type, &paint);
1510     sk_sp<SkShader> source_shader = skia_source->makeShader(
1511         SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions());
1512     sk_sp<SkShader> mask_shader = skia_mask->makeShader(
1513         SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions());
1514     paint.setShader(SkShaders::Blend(
1515         SkBlendMode::kSrcIn, std::move(mask_shader), std::move(source_shader)));
1516     m_pCanvas->drawRect(
1517         SkRect::MakeWH(SkIntToScalar(src_width), SkIntToScalar(src_height)),
1518         paint);
1519   }
1520 
1521   DebugValidate(m_pBitmap, m_pBackdropBitmap);
1522   return true;
1523 }
1524 
SetBitsWithMask(const RetainPtr<CFX_DIBBase> & pBitmap,const RetainPtr<CFX_DIBBase> & pMask,int dest_left,int dest_top,int bitmap_alpha,BlendMode blend_type)1525 bool CFX_SkiaDeviceDriver::SetBitsWithMask(
1526     const RetainPtr<CFX_DIBBase>& pBitmap,
1527     const RetainPtr<CFX_DIBBase>& pMask,
1528     int dest_left,
1529     int dest_top,
1530     int bitmap_alpha,
1531     BlendMode blend_type) {
1532   if (!m_pBitmap || m_pBitmap->GetBuffer().empty())
1533     return true;
1534 
1535   CFX_Matrix m = CFX_RenderDevice::GetFlipMatrix(
1536       pBitmap->GetWidth(), pBitmap->GetHeight(), dest_left, dest_top);
1537   return DrawBitsWithMask(pBitmap, pMask, bitmap_alpha, m, blend_type);
1538 }
1539 
SetGroupKnockout(bool group_knockout)1540 void CFX_SkiaDeviceDriver::SetGroupKnockout(bool group_knockout) {
1541   m_bGroupKnockout = group_knockout;
1542 }
1543 
Clear(uint32_t color)1544 void CFX_SkiaDeviceDriver::Clear(uint32_t color) {
1545   m_pCanvas->clear(color);
1546 }
1547 
StartDIBitsSkia(const RetainPtr<CFX_DIBBase> & pSource,const FX_RECT & src_rect,int bitmap_alpha,uint32_t argb,const CFX_Matrix & matrix,const FXDIB_ResampleOptions & options,BlendMode blend_type)1548 bool CFX_SkiaDeviceDriver::StartDIBitsSkia(
1549     const RetainPtr<CFX_DIBBase>& pSource,
1550     const FX_RECT& src_rect,
1551     int bitmap_alpha,
1552     uint32_t argb,
1553     const CFX_Matrix& matrix,
1554     const FXDIB_ResampleOptions& options,
1555     BlendMode blend_type) {
1556   DebugValidate(m_pBitmap, m_pBackdropBitmap);
1557 
1558   sk_sp<SkImage> skia_source = pSource->RealizeSkImage();
1559   if (!skia_source) {
1560     return false;
1561   }
1562 
1563   {
1564     SkAutoCanvasRestore scoped_save_restore(m_pCanvas, /*doSave=*/true);
1565 
1566     const int width = pSource->GetWidth();
1567     const int height = pSource->GetHeight();
1568     SkMatrix skMatrix;
1569     SetBitmapMatrix(matrix, width, height, &skMatrix);
1570     m_pCanvas->concat(skMatrix);
1571     SkPaint paint;
1572     SetBitmapPaint(pSource->IsMaskFormat(), !m_FillOptions.aliased_path,
1573                    bitmap_alpha, argb, blend_type, &paint);
1574 
1575     bool use_interpolate_bilinear = options.bInterpolateBilinear;
1576     if (!use_interpolate_bilinear) {
1577       float dest_width = ceilf(matrix.GetXUnit());
1578       float dest_height = ceilf(matrix.GetYUnit());
1579       if (pdfium::base::IsValueInRangeForNumericType<int>(dest_width) &&
1580           pdfium::base::IsValueInRangeForNumericType<int>(dest_height)) {
1581         use_interpolate_bilinear = CStretchEngine::UseInterpolateBilinear(
1582             options, static_cast<int>(dest_width),
1583             static_cast<int>(dest_height), width, height);
1584       }
1585     }
1586     SkSamplingOptions sampling_options;
1587     if (use_interpolate_bilinear) {
1588       sampling_options =
1589           SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear);
1590     }
1591 
1592     m_pCanvas->drawImageRect(
1593         skia_source,
1594         SkRect::MakeLTRB(src_rect.left, src_rect.top, src_rect.right,
1595                          src_rect.bottom),
1596         SkRect::MakeWH(src_rect.Width(), src_rect.Height()), sampling_options,
1597         &paint, SkCanvas::kFast_SrcRectConstraint);
1598   }
1599 
1600   DebugValidate(m_pBitmap, m_pBackdropBitmap);
1601   return true;
1602 }
1603 
1604 CFX_SkiaDeviceDriver::CharDetail::CharDetail() = default;
1605 CFX_SkiaDeviceDriver::CharDetail::~CharDetail() = default;
1606 
Clear(uint32_t color)1607 void CFX_DefaultRenderDevice::Clear(uint32_t color) {
1608   static_cast<CFX_SkiaDeviceDriver*>(GetDeviceDriver())->Clear(color);
1609 }
1610 
AttachSkiaImpl(RetainPtr<CFX_DIBitmap> pBitmap,bool bRgbByteOrder,RetainPtr<CFX_DIBitmap> pBackdropBitmap,bool bGroupKnockout)1611 bool CFX_DefaultRenderDevice::AttachSkiaImpl(
1612     RetainPtr<CFX_DIBitmap> pBitmap,
1613     bool bRgbByteOrder,
1614     RetainPtr<CFX_DIBitmap> pBackdropBitmap,
1615     bool bGroupKnockout) {
1616   if (!pBitmap)
1617     return false;
1618   SetBitmap(pBitmap);
1619   auto driver =
1620       CFX_SkiaDeviceDriver::Create(std::move(pBitmap), bRgbByteOrder,
1621                                    std::move(pBackdropBitmap), bGroupKnockout);
1622   if (!driver)
1623     return false;
1624 
1625   SetDeviceDriver(std::move(driver));
1626   return true;
1627 }
1628 
AttachCanvas(SkCanvas * canvas)1629 bool CFX_DefaultRenderDevice::AttachCanvas(SkCanvas* canvas) {
1630   if (!canvas) {
1631     return false;
1632   }
1633   SetDeviceDriver(std::make_unique<CFX_SkiaDeviceDriver>(canvas));
1634   return true;
1635 }
1636 
CreateSkia(int width,int height,FXDIB_Format format,RetainPtr<CFX_DIBitmap> pBackdropBitmap)1637 bool CFX_DefaultRenderDevice::CreateSkia(
1638     int width,
1639     int height,
1640     FXDIB_Format format,
1641     RetainPtr<CFX_DIBitmap> pBackdropBitmap) {
1642   auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
1643   if (!pBitmap->Create(width, height, format))
1644     return false;
1645 
1646   SetBitmap(pBitmap);
1647   auto driver = CFX_SkiaDeviceDriver::Create(std::move(pBitmap), false,
1648                                              std::move(pBackdropBitmap), false);
1649   if (!driver)
1650     return false;
1651 
1652   SetDeviceDriver(std::move(driver));
1653   return true;
1654 }
1655