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