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