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