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