1 // Copyright 2016 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 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "core/fxge/cfx_renderdevice.h"
8
9 #include <math.h>
10
11 #include <algorithm>
12 #include <memory>
13 #include <utility>
14
15 #include "build/build_config.h"
16 #include "core/fxcrt/fx_safe_types.h"
17 #include "core/fxge/cfx_color.h"
18 #include "core/fxge/cfx_defaultrenderdevice.h"
19 #include "core/fxge/cfx_fillrenderoptions.h"
20 #include "core/fxge/cfx_font.h"
21 #include "core/fxge/cfx_fontmgr.h"
22 #include "core/fxge/cfx_gemodule.h"
23 #include "core/fxge/cfx_glyphbitmap.h"
24 #include "core/fxge/cfx_glyphcache.h"
25 #include "core/fxge/cfx_graphstatedata.h"
26 #include "core/fxge/cfx_path.h"
27 #include "core/fxge/cfx_textrenderoptions.h"
28 #include "core/fxge/dib/cfx_dibitmap.h"
29 #include "core/fxge/dib/cfx_imagerenderer.h"
30 #include "core/fxge/fx_font.h"
31 #include "core/fxge/renderdevicedriver_iface.h"
32 #include "core/fxge/text_char_pos.h"
33 #include "core/fxge/text_glyph_pos.h"
34 #include "third_party/base/check.h"
35 #include "third_party/base/check_op.h"
36 #include "third_party/base/containers/span.h"
37
38 #if defined(_SKIA_SUPPORT_)
39 #include "third_party/skia/include/core/SkTypes.h" // nogncheck
40 #endif
41
42 namespace {
43
AdjustGlyphSpace(std::vector<TextGlyphPos> * pGlyphAndPos)44 void AdjustGlyphSpace(std::vector<TextGlyphPos>* pGlyphAndPos) {
45 DCHECK_GT(pGlyphAndPos->size(), 1u);
46 std::vector<TextGlyphPos>& glyphs = *pGlyphAndPos;
47 bool bVertical = glyphs.back().m_Origin.x == glyphs.front().m_Origin.x;
48 if (!bVertical && (glyphs.back().m_Origin.y != glyphs.front().m_Origin.y))
49 return;
50
51 for (size_t i = glyphs.size() - 1; i > 1; --i) {
52 const TextGlyphPos& next = glyphs[i];
53 int next_origin = bVertical ? next.m_Origin.y : next.m_Origin.x;
54 float next_origin_f =
55 bVertical ? next.m_fDeviceOrigin.y : next.m_fDeviceOrigin.x;
56
57 TextGlyphPos& current = glyphs[i - 1];
58 int& current_origin = bVertical ? current.m_Origin.y : current.m_Origin.x;
59 float current_origin_f =
60 bVertical ? current.m_fDeviceOrigin.y : current.m_fDeviceOrigin.x;
61
62 FX_SAFE_INT32 safe_space = next_origin;
63 safe_space -= current_origin;
64 if (!safe_space.IsValid())
65 continue;
66
67 int space = safe_space.ValueOrDie();
68 float space_f = next_origin_f - current_origin_f;
69 float error = fabs(space_f) - fabs(static_cast<float>(space));
70 if (error <= 0.5f)
71 continue;
72
73 FX_SAFE_INT32 safe_origin = current_origin;
74 safe_origin += space > 0 ? -1 : 1;
75 if (!safe_origin.IsValid())
76 continue;
77
78 current_origin = safe_origin.ValueOrDie();
79 }
80 }
81
82 constexpr uint8_t kTextGammaAdjust[256] = {
83 0, 2, 3, 4, 6, 7, 8, 10, 11, 12, 13, 15, 16, 17, 18,
84 19, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35,
85 36, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 52,
86 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
87 68, 69, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
88 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
89 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
90 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
91 129, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
92 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 156,
93 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171,
94 172, 173, 174, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185,
95 186, 187, 188, 189, 190, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
96 200, 201, 202, 203, 204, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213,
97 214, 215, 216, 217, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227,
98 228, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 239, 240,
99 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 250, 251, 252, 253, 254,
100 255,
101 };
102
TextGammaAdjust(int value)103 int TextGammaAdjust(int value) {
104 DCHECK_GE(value, 0);
105 DCHECK_LE(value, 255);
106 return kTextGammaAdjust[value];
107 }
108
CalcAlpha(int src,int alpha)109 int CalcAlpha(int src, int alpha) {
110 return src * alpha / 255;
111 }
112
MergeGammaAdjust(uint8_t src,int channel,int alpha,uint8_t * dest)113 void MergeGammaAdjust(uint8_t src, int channel, int alpha, uint8_t* dest) {
114 *dest =
115 FXDIB_ALPHA_MERGE(*dest, channel, CalcAlpha(TextGammaAdjust(src), alpha));
116 }
117
MergeGammaAdjustRgb(const uint8_t * src,int r,int g,int b,int a,uint8_t * dest)118 void MergeGammaAdjustRgb(const uint8_t* src,
119 int r,
120 int g,
121 int b,
122 int a,
123 uint8_t* dest) {
124 MergeGammaAdjust(src[2], b, a, &dest[0]);
125 MergeGammaAdjust(src[1], g, a, &dest[1]);
126 MergeGammaAdjust(src[0], r, a, &dest[2]);
127 }
128
AverageRgb(const uint8_t * src)129 int AverageRgb(const uint8_t* src) {
130 return (src[0] + src[1] + src[2]) / 3;
131 }
132
CalculateDestAlpha(uint8_t back_alpha,int src_alpha)133 uint8_t CalculateDestAlpha(uint8_t back_alpha, int src_alpha) {
134 return back_alpha + src_alpha - back_alpha * src_alpha / 255;
135 }
136
ApplyAlpha(uint8_t * dest,int b,int g,int r,int alpha)137 void ApplyAlpha(uint8_t* dest, int b, int g, int r, int alpha) {
138 dest[0] = FXDIB_ALPHA_MERGE(dest[0], b, alpha);
139 dest[1] = FXDIB_ALPHA_MERGE(dest[1], g, alpha);
140 dest[2] = FXDIB_ALPHA_MERGE(dest[2], r, alpha);
141 }
142
ApplyDestAlpha(uint8_t back_alpha,int src_alpha,int r,int g,int b,uint8_t * dest)143 void ApplyDestAlpha(uint8_t back_alpha,
144 int src_alpha,
145 int r,
146 int g,
147 int b,
148 uint8_t* dest) {
149 uint8_t dest_alpha = CalculateDestAlpha(back_alpha, src_alpha);
150 ApplyAlpha(dest, b, g, r, src_alpha * 255 / dest_alpha);
151 dest[3] = dest_alpha;
152 }
153
NormalizeArgb(int src_value,int r,int g,int b,int a,uint8_t * dest,int src_alpha)154 void NormalizeArgb(int src_value,
155 int r,
156 int g,
157 int b,
158 int a,
159 uint8_t* dest,
160 int src_alpha) {
161 uint8_t back_alpha = dest[3];
162 if (back_alpha == 0)
163 FXARGB_SETDIB(dest, ArgbEncode(src_alpha, r, g, b));
164 else if (src_alpha != 0)
165 ApplyDestAlpha(back_alpha, src_alpha, r, g, b, dest);
166 }
167
NormalizeDest(bool has_alpha,int src_value,int r,int g,int b,int a,uint8_t * dest)168 void NormalizeDest(bool has_alpha,
169 int src_value,
170 int r,
171 int g,
172 int b,
173 int a,
174 uint8_t* dest) {
175 if (has_alpha) {
176 NormalizeArgb(src_value, r, g, b, a, dest,
177 CalcAlpha(TextGammaAdjust(src_value), a));
178 return;
179 }
180 int src_alpha = CalcAlpha(TextGammaAdjust(src_value), a);
181 if (src_alpha == 0)
182 return;
183
184 ApplyAlpha(dest, b, g, r, src_alpha);
185 }
186
NormalizeSrc(bool has_alpha,int src_value,int r,int g,int b,int a,uint8_t * dest)187 void NormalizeSrc(bool has_alpha,
188 int src_value,
189 int r,
190 int g,
191 int b,
192 int a,
193 uint8_t* dest) {
194 if (!has_alpha) {
195 ApplyAlpha(dest, b, g, r, CalcAlpha(TextGammaAdjust(src_value), a));
196 return;
197 }
198 int src_alpha = CalcAlpha(TextGammaAdjust(src_value), a);
199 if (src_alpha != 0)
200 NormalizeArgb(src_value, r, g, b, a, dest, src_alpha);
201 }
202
NextPixel(const uint8_t ** src_scan,uint8_t ** dst_scan,int bpp)203 void NextPixel(const uint8_t** src_scan, uint8_t** dst_scan, int bpp) {
204 *src_scan += 3;
205 *dst_scan += bpp;
206 }
207
SetAlpha(bool has_alpha,uint8_t * alpha)208 void SetAlpha(bool has_alpha, uint8_t* alpha) {
209 if (has_alpha)
210 alpha[3] = 255;
211 }
212
DrawNormalTextHelper(const RetainPtr<CFX_DIBitmap> & bitmap,const RetainPtr<CFX_DIBitmap> & pGlyph,int nrows,int left,int top,int start_col,int end_col,bool normalize,int x_subpixel,int a,int r,int g,int b)213 void DrawNormalTextHelper(const RetainPtr<CFX_DIBitmap>& bitmap,
214 const RetainPtr<CFX_DIBitmap>& pGlyph,
215 int nrows,
216 int left,
217 int top,
218 int start_col,
219 int end_col,
220 bool normalize,
221 int x_subpixel,
222 int a,
223 int r,
224 int g,
225 int b) {
226 const bool has_alpha = bitmap->GetFormat() == FXDIB_Format::kArgb;
227 const int Bpp = has_alpha ? 4 : bitmap->GetBPP() / 8;
228 for (int row = 0; row < nrows; ++row) {
229 int dest_row = row + top;
230 if (dest_row < 0 || dest_row >= bitmap->GetHeight())
231 continue;
232
233 const uint8_t* src_scan =
234 pGlyph->GetScanline(row).subspan((start_col - left) * 3).data();
235 uint8_t* dest_scan =
236 bitmap->GetWritableScanline(dest_row).subspan(start_col * Bpp).data();
237 if (x_subpixel == 0) {
238 for (int col = start_col; col < end_col; ++col) {
239 if (normalize) {
240 int src_value = AverageRgb(&src_scan[0]);
241 NormalizeDest(has_alpha, src_value, r, g, b, a, dest_scan);
242 } else {
243 MergeGammaAdjustRgb(&src_scan[0], r, g, b, a, &dest_scan[0]);
244 SetAlpha(has_alpha, dest_scan);
245 }
246 NextPixel(&src_scan, &dest_scan, Bpp);
247 }
248 continue;
249 }
250 if (x_subpixel == 1) {
251 if (normalize) {
252 int src_value = start_col > left ? AverageRgb(&src_scan[-1])
253 : (src_scan[0] + src_scan[1]) / 3;
254 NormalizeSrc(has_alpha, src_value, r, g, b, a, dest_scan);
255 } else {
256 if (start_col > left)
257 MergeGammaAdjust(src_scan[-1], r, a, &dest_scan[2]);
258 MergeGammaAdjust(src_scan[0], g, a, &dest_scan[1]);
259 MergeGammaAdjust(src_scan[1], b, a, &dest_scan[0]);
260 SetAlpha(has_alpha, dest_scan);
261 }
262 NextPixel(&src_scan, &dest_scan, Bpp);
263 for (int col = start_col + 1; col < end_col; ++col) {
264 if (normalize) {
265 int src_value = AverageRgb(&src_scan[-1]);
266 NormalizeDest(has_alpha, src_value, r, g, b, a, dest_scan);
267 } else {
268 MergeGammaAdjustRgb(&src_scan[-1], r, g, b, a, &dest_scan[0]);
269 SetAlpha(has_alpha, dest_scan);
270 }
271 NextPixel(&src_scan, &dest_scan, Bpp);
272 }
273 continue;
274 }
275 if (normalize) {
276 int src_value =
277 start_col > left ? AverageRgb(&src_scan[-2]) : src_scan[0] / 3;
278 NormalizeSrc(has_alpha, src_value, r, g, b, a, dest_scan);
279 } else {
280 if (start_col > left) {
281 MergeGammaAdjust(src_scan[-2], r, a, &dest_scan[2]);
282 MergeGammaAdjust(src_scan[-1], g, a, &dest_scan[1]);
283 }
284 MergeGammaAdjust(src_scan[0], b, a, &dest_scan[0]);
285 SetAlpha(has_alpha, dest_scan);
286 }
287 NextPixel(&src_scan, &dest_scan, Bpp);
288 for (int col = start_col + 1; col < end_col; ++col) {
289 if (normalize) {
290 int src_value = AverageRgb(&src_scan[-2]);
291 NormalizeDest(has_alpha, src_value, r, g, b, a, dest_scan);
292 } else {
293 MergeGammaAdjustRgb(&src_scan[-2], r, g, b, a, &dest_scan[0]);
294 SetAlpha(has_alpha, dest_scan);
295 }
296 NextPixel(&src_scan, &dest_scan, Bpp);
297 }
298 }
299 }
300
ShouldDrawDeviceText(const CFX_Font * pFont,const CFX_TextRenderOptions & options)301 bool ShouldDrawDeviceText(const CFX_Font* pFont,
302 const CFX_TextRenderOptions& options) {
303 #if BUILDFLAG(IS_APPLE)
304 if (options.font_is_cid)
305 return false;
306
307 const ByteString bsPsName = pFont->GetPsName();
308 if (bsPsName.Contains("+ZJHL"))
309 return false;
310
311 if (bsPsName == "CNAAJI+cmex10")
312 return false;
313 #endif
314 return true;
315 }
316
317 // Returns true if the path is a 3-point path that draws A->B->A and forms a
318 // zero area, or a 2-point path which draws A->B.
CheckSimpleLinePath(pdfium::span<const CFX_Path::Point> points,const CFX_Matrix * matrix,bool adjust,CFX_Path * new_path,bool * thin,bool * set_identity)319 bool CheckSimpleLinePath(pdfium::span<const CFX_Path::Point> points,
320 const CFX_Matrix* matrix,
321 bool adjust,
322 CFX_Path* new_path,
323 bool* thin,
324 bool* set_identity) {
325 if (points.size() != 2 && points.size() != 3)
326 return false;
327
328 if (points[0].m_Type != CFX_Path::Point::Type::kMove ||
329 points[1].m_Type != CFX_Path::Point::Type::kLine ||
330 (points.size() == 3 &&
331 (points[2].m_Type != CFX_Path::Point::Type::kLine ||
332 points[0].m_Point != points[2].m_Point))) {
333 return false;
334 }
335
336 // A special case that all points are identical, zero area is formed and no
337 // thin line needs to be drawn.
338 if (points[0].m_Point == points[1].m_Point)
339 return true;
340
341 for (size_t i = 0; i < 2; i++) {
342 CFX_PointF point = points[i].m_Point;
343 if (adjust) {
344 if (matrix)
345 point = matrix->Transform(point);
346
347 point = CFX_PointF(static_cast<int>(point.x) + 0.5f,
348 static_cast<int>(point.y) + 0.5f);
349 }
350 new_path->AppendPoint(point, points[i].m_Type);
351 }
352 if (adjust && matrix)
353 *set_identity = true;
354
355 *thin = true;
356 return true;
357 }
358
359 // Returns true if `points` is palindromic and forms zero area. Otherwise,
360 // returns false.
CheckPalindromicPath(pdfium::span<const CFX_Path::Point> points,CFX_Path * new_path,bool * thin)361 bool CheckPalindromicPath(pdfium::span<const CFX_Path::Point> points,
362 CFX_Path* new_path,
363 bool* thin) {
364 if (points.size() <= 3 || !(points.size() % 2))
365 return false;
366
367 const size_t mid = points.size() / 2;
368 CFX_Path temp_path;
369 for (size_t i = 0; i < mid; i++) {
370 const CFX_Path::Point& left = points[mid - i - 1];
371 const CFX_Path::Point& right = points[mid + i + 1];
372 bool zero_area = left.m_Point == right.m_Point &&
373 left.m_Type != CFX_Path::Point::Type::kBezier &&
374 right.m_Type != CFX_Path::Point::Type::kBezier;
375 if (!zero_area)
376 return false;
377
378 temp_path.AppendPoint(points[mid - i].m_Point,
379 CFX_Path::Point::Type::kMove);
380 temp_path.AppendPoint(left.m_Point, CFX_Path::Point::Type::kLine);
381 }
382
383 new_path->Append(temp_path, nullptr);
384 *thin = true;
385 return true;
386 }
387
IsFoldingVerticalLine(const CFX_PointF & a,const CFX_PointF & b,const CFX_PointF & c)388 bool IsFoldingVerticalLine(const CFX_PointF& a,
389 const CFX_PointF& b,
390 const CFX_PointF& c) {
391 return a.x == b.x && b.x == c.x && (b.y - a.y) * (b.y - c.y) > 0;
392 }
393
IsFoldingHorizontalLine(const CFX_PointF & a,const CFX_PointF & b,const CFX_PointF & c)394 bool IsFoldingHorizontalLine(const CFX_PointF& a,
395 const CFX_PointF& b,
396 const CFX_PointF& c) {
397 return a.y == b.y && b.y == c.y && (b.x - a.x) * (b.x - c.x) > 0;
398 }
399
IsFoldingDiagonalLine(const CFX_PointF & a,const CFX_PointF & b,const CFX_PointF & c)400 bool IsFoldingDiagonalLine(const CFX_PointF& a,
401 const CFX_PointF& b,
402 const CFX_PointF& c) {
403 return a.x != b.x && c.x != b.x && a.y != b.y && c.y != b.y &&
404 (a.y - b.y) * (c.x - b.x) == (c.y - b.y) * (a.x - b.x);
405 }
406
GetZeroAreaPath(pdfium::span<const CFX_Path::Point> points,const CFX_Matrix * matrix,bool adjust,CFX_Path * new_path,bool * thin,bool * set_identity)407 bool GetZeroAreaPath(pdfium::span<const CFX_Path::Point> points,
408 const CFX_Matrix* matrix,
409 bool adjust,
410 CFX_Path* new_path,
411 bool* thin,
412 bool* set_identity) {
413 *set_identity = false;
414
415 if (points.size() < 2)
416 return false;
417
418 if (CheckSimpleLinePath(points, matrix, adjust, new_path, thin,
419 set_identity)) {
420 return true;
421 }
422
423 if (CheckPalindromicPath(points, new_path, thin))
424 return true;
425
426 for (size_t i = 0; i < points.size(); i++) {
427 CFX_Path::Point::Type point_type = points[i].m_Type;
428 if (point_type == CFX_Path::Point::Type::kMove) {
429 DCHECK_EQ(0u, i);
430 continue;
431 }
432
433 if (point_type == CFX_Path::Point::Type::kBezier) {
434 i += 2;
435 DCHECK_LT(i, points.size());
436 continue;
437 }
438
439 DCHECK_EQ(point_type, CFX_Path::Point::Type::kLine);
440 size_t next_index = (i + 1) % (points.size());
441 const CFX_Path::Point& next = points[next_index];
442 if (next.m_Type != CFX_Path::Point::Type::kLine)
443 continue;
444
445 const CFX_Path::Point& prev = points[i - 1];
446 const CFX_Path::Point& cur = points[i];
447 if (IsFoldingVerticalLine(prev.m_Point, cur.m_Point, next.m_Point)) {
448 bool use_prev = fabs(cur.m_Point.y - prev.m_Point.y) <
449 fabs(cur.m_Point.y - next.m_Point.y);
450 const CFX_Path::Point& start = use_prev ? prev : cur;
451 const CFX_Path::Point& end = use_prev ? cur : next;
452 new_path->AppendPoint(start.m_Point, CFX_Path::Point::Type::kMove);
453 new_path->AppendPoint(end.m_Point, CFX_Path::Point::Type::kLine);
454 continue;
455 }
456
457 if (IsFoldingHorizontalLine(prev.m_Point, cur.m_Point, next.m_Point) ||
458 IsFoldingDiagonalLine(prev.m_Point, cur.m_Point, next.m_Point)) {
459 bool use_prev = fabs(cur.m_Point.x - prev.m_Point.x) <
460 fabs(cur.m_Point.x - next.m_Point.x);
461 const CFX_Path::Point& start = use_prev ? prev : cur;
462 const CFX_Path::Point& end = use_prev ? cur : next;
463 new_path->AppendPoint(start.m_Point, CFX_Path::Point::Type::kMove);
464 new_path->AppendPoint(end.m_Point, CFX_Path::Point::Type::kLine);
465 continue;
466 }
467 }
468
469 size_t new_path_size = new_path->GetPoints().size();
470 if (points.size() > 3 && new_path_size > 0)
471 *thin = true;
472 return new_path_size != 0;
473 }
474
GetCreateCompatibleBitmapFormat(int render_caps)475 FXDIB_Format GetCreateCompatibleBitmapFormat(int render_caps) {
476 if (render_caps & FXRC_BYTEMASK_OUTPUT)
477 return FXDIB_Format::k8bppMask;
478 if (render_caps & FXRC_ALPHA_OUTPUT)
479 return FXDIB_Format::kArgb;
480 return CFX_DIBBase::kPlatformRGBFormat;
481 }
482
483 } // namespace
484
485 CFX_RenderDevice::CFX_RenderDevice() = default;
486
~CFX_RenderDevice()487 CFX_RenderDevice::~CFX_RenderDevice() {
488 RestoreState(false);
489 }
490
491 // static
GetFlipMatrix(float width,float height,float left,float top)492 CFX_Matrix CFX_RenderDevice::GetFlipMatrix(float width,
493 float height,
494 float left,
495 float top) {
496 return CFX_Matrix(width, 0, 0, -height, left, top + height);
497 }
498
SetDeviceDriver(std::unique_ptr<RenderDeviceDriverIface> pDriver)499 void CFX_RenderDevice::SetDeviceDriver(
500 std::unique_ptr<RenderDeviceDriverIface> pDriver) {
501 DCHECK(pDriver);
502 DCHECK(!m_pDeviceDriver);
503 m_pDeviceDriver = std::move(pDriver);
504 InitDeviceInfo();
505 }
506
InitDeviceInfo()507 void CFX_RenderDevice::InitDeviceInfo() {
508 m_Width = m_pDeviceDriver->GetDeviceCaps(FXDC_PIXEL_WIDTH);
509 m_Height = m_pDeviceDriver->GetDeviceCaps(FXDC_PIXEL_HEIGHT);
510 m_bpp = m_pDeviceDriver->GetDeviceCaps(FXDC_BITS_PIXEL);
511 m_RenderCaps = m_pDeviceDriver->GetDeviceCaps(FXDC_RENDER_CAPS);
512 m_DeviceType = m_pDeviceDriver->GetDeviceType();
513 if (!m_pDeviceDriver->GetClipBox(&m_ClipBox)) {
514 m_ClipBox.left = 0;
515 m_ClipBox.top = 0;
516 m_ClipBox.right = m_Width;
517 m_ClipBox.bottom = m_Height;
518 }
519 }
520
SaveState()521 void CFX_RenderDevice::SaveState() {
522 m_pDeviceDriver->SaveState();
523 }
524
RestoreState(bool bKeepSaved)525 void CFX_RenderDevice::RestoreState(bool bKeepSaved) {
526 if (m_pDeviceDriver) {
527 m_pDeviceDriver->RestoreState(bKeepSaved);
528 UpdateClipBox();
529 }
530 }
531
GetDeviceCaps(int caps_id) const532 int CFX_RenderDevice::GetDeviceCaps(int caps_id) const {
533 return m_pDeviceDriver->GetDeviceCaps(caps_id);
534 }
535
GetBitmap() const536 RetainPtr<CFX_DIBitmap> CFX_RenderDevice::GetBitmap() const {
537 return m_pBitmap;
538 }
539
SetBitmap(const RetainPtr<CFX_DIBitmap> & pBitmap)540 void CFX_RenderDevice::SetBitmap(const RetainPtr<CFX_DIBitmap>& pBitmap) {
541 m_pBitmap = pBitmap;
542 }
543
CreateCompatibleBitmap(const RetainPtr<CFX_DIBitmap> & pDIB,int width,int height) const544 bool CFX_RenderDevice::CreateCompatibleBitmap(
545 const RetainPtr<CFX_DIBitmap>& pDIB,
546 int width,
547 int height) const {
548 return pDIB->Create(width, height,
549 GetCreateCompatibleBitmapFormat(m_RenderCaps));
550 }
551
SetBaseClip(const FX_RECT & rect)552 void CFX_RenderDevice::SetBaseClip(const FX_RECT& rect) {
553 m_pDeviceDriver->SetBaseClip(rect);
554 }
555
SetClip_PathFill(const CFX_Path & path,const CFX_Matrix * pObject2Device,const CFX_FillRenderOptions & fill_options)556 bool CFX_RenderDevice::SetClip_PathFill(
557 const CFX_Path& path,
558 const CFX_Matrix* pObject2Device,
559 const CFX_FillRenderOptions& fill_options) {
560 if (!m_pDeviceDriver->SetClip_PathFill(path, pObject2Device, fill_options))
561 return false;
562
563 UpdateClipBox();
564 return true;
565 }
566
SetClip_PathStroke(const CFX_Path & path,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState)567 bool CFX_RenderDevice::SetClip_PathStroke(
568 const CFX_Path& path,
569 const CFX_Matrix* pObject2Device,
570 const CFX_GraphStateData* pGraphState) {
571 if (!m_pDeviceDriver->SetClip_PathStroke(path, pObject2Device, pGraphState))
572 return false;
573
574 UpdateClipBox();
575 return true;
576 }
577
SetClip_Rect(const FX_RECT & rect)578 bool CFX_RenderDevice::SetClip_Rect(const FX_RECT& rect) {
579 CFX_Path path;
580 path.AppendRect(rect.left, rect.bottom, rect.right, rect.top);
581 if (!SetClip_PathFill(path, nullptr, CFX_FillRenderOptions::WindingOptions()))
582 return false;
583
584 UpdateClipBox();
585 return true;
586 }
587
UpdateClipBox()588 void CFX_RenderDevice::UpdateClipBox() {
589 if (m_pDeviceDriver->GetClipBox(&m_ClipBox))
590 return;
591 m_ClipBox.left = 0;
592 m_ClipBox.top = 0;
593 m_ClipBox.right = m_Width;
594 m_ClipBox.bottom = m_Height;
595 }
596
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)597 bool CFX_RenderDevice::DrawPath(const CFX_Path& path,
598 const CFX_Matrix* pObject2Device,
599 const CFX_GraphStateData* pGraphState,
600 uint32_t fill_color,
601 uint32_t stroke_color,
602 const CFX_FillRenderOptions& fill_options) {
603 return DrawPathWithBlend(path, pObject2Device, pGraphState, fill_color,
604 stroke_color, fill_options, BlendMode::kNormal);
605 }
606
DrawPathWithBlend(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)607 bool CFX_RenderDevice::DrawPathWithBlend(
608 const CFX_Path& path,
609 const CFX_Matrix* pObject2Device,
610 const CFX_GraphStateData* pGraphState,
611 uint32_t fill_color,
612 uint32_t stroke_color,
613 const CFX_FillRenderOptions& fill_options,
614 BlendMode blend_type) {
615 const bool fill =
616 fill_options.fill_type != CFX_FillRenderOptions::FillType::kNoFill;
617 uint8_t fill_alpha = fill ? FXARGB_A(fill_color) : 0;
618 uint8_t stroke_alpha = pGraphState ? FXARGB_A(stroke_color) : 0;
619 pdfium::span<const CFX_Path::Point> points = path.GetPoints();
620 if (stroke_alpha == 0 && points.size() == 2) {
621 CFX_PointF pos1 = points[0].m_Point;
622 CFX_PointF pos2 = points[1].m_Point;
623 if (pObject2Device) {
624 pos1 = pObject2Device->Transform(pos1);
625 pos2 = pObject2Device->Transform(pos2);
626 }
627 DrawCosmeticLine(pos1, pos2, fill_color, fill_options, blend_type);
628 return true;
629 }
630
631 if (stroke_alpha == 0 && !fill_options.rect_aa) {
632 absl::optional<CFX_FloatRect> maybe_rect_f = path.GetRect(pObject2Device);
633 if (maybe_rect_f.has_value()) {
634 const CFX_FloatRect& rect_f = maybe_rect_f.value();
635 FX_RECT rect_i = rect_f.GetOuterRect();
636
637 // Depending on the top/bottom, left/right values of the rect it's
638 // possible to overflow the Width() and Height() calculations. Check that
639 // the rect will have valid dimension before continuing.
640 if (!rect_i.Valid())
641 return false;
642
643 int width = static_cast<int>(ceil(rect_f.right - rect_f.left));
644 if (width < 1) {
645 width = 1;
646 if (rect_i.left == rect_i.right)
647 ++rect_i.right;
648 }
649 int height = static_cast<int>(ceil(rect_f.top - rect_f.bottom));
650 if (height < 1) {
651 height = 1;
652 if (rect_i.bottom == rect_i.top)
653 ++rect_i.bottom;
654 }
655 if (rect_i.Width() >= width + 1) {
656 if (rect_f.left - static_cast<float>(rect_i.left) >
657 static_cast<float>(rect_i.right) - rect_f.right) {
658 ++rect_i.left;
659 } else {
660 --rect_i.right;
661 }
662 }
663 if (rect_i.Height() >= height + 1) {
664 if (rect_f.top - static_cast<float>(rect_i.top) >
665 static_cast<float>(rect_i.bottom) - rect_f.bottom) {
666 ++rect_i.top;
667 } else {
668 --rect_i.bottom;
669 }
670 }
671 if (FillRectWithBlend(rect_i, fill_color, blend_type))
672 return true;
673 }
674 }
675
676 if (fill && stroke_alpha == 0 && !fill_options.stroke &&
677 !fill_options.text_mode) {
678 bool adjust = !!m_pDeviceDriver->GetDriverType();
679 std::vector<CFX_Path::Point> sub_path;
680 for (size_t i = 0; i < points.size(); i++) {
681 CFX_Path::Point::Type point_type = points[i].m_Type;
682 if (point_type == CFX_Path::Point::Type::kMove) {
683 // Process the existing sub path.
684 DrawZeroAreaPath(sub_path, pObject2Device, adjust,
685 fill_options.aliased_path, fill_color, fill_alpha,
686 blend_type);
687 sub_path.clear();
688
689 // Start forming the next sub path.
690 sub_path.push_back(points[i]);
691 continue;
692 }
693
694 if (point_type == CFX_Path::Point::Type::kBezier) {
695 sub_path.push_back(points[i]);
696 sub_path.push_back(points[i + 1]);
697 sub_path.push_back(points[i + 2]);
698 i += 2;
699 continue;
700 }
701
702 DCHECK_EQ(point_type, CFX_Path::Point::Type::kLine);
703 sub_path.push_back(points[i]);
704 }
705 // Process the last sub paths.
706 DrawZeroAreaPath(sub_path, pObject2Device, adjust,
707 fill_options.aliased_path, fill_color, fill_alpha,
708 blend_type);
709 }
710
711 if (fill && fill_alpha && stroke_alpha < 0xff && fill_options.stroke) {
712 if (m_RenderCaps & FXRC_FILLSTROKE_PATH) {
713 #if defined(_SKIA_SUPPORT_)
714 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
715 m_pDeviceDriver->SetGroupKnockout(true);
716 }
717 #endif
718 bool draw_fillstroke_path_result = m_pDeviceDriver->DrawPath(
719 path, pObject2Device, pGraphState, fill_color, stroke_color,
720 fill_options, blend_type);
721
722 #if defined(_SKIA_SUPPORT_)
723 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
724 // Restore the group knockout status for `m_pDeviceDriver` after
725 // finishing painting a fill-and-stroke path.
726 m_pDeviceDriver->SetGroupKnockout(false);
727 }
728 #endif
729 return draw_fillstroke_path_result;
730 }
731 return DrawFillStrokePath(path, pObject2Device, pGraphState, fill_color,
732 stroke_color, fill_options, blend_type);
733 }
734 return m_pDeviceDriver->DrawPath(path, pObject2Device, pGraphState,
735 fill_color, stroke_color, fill_options,
736 blend_type);
737 }
738
739 // This can be removed once PDFium entirely relies on Skia
DrawFillStrokePath(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)740 bool CFX_RenderDevice::DrawFillStrokePath(
741 const CFX_Path& path,
742 const CFX_Matrix* pObject2Device,
743 const CFX_GraphStateData* pGraphState,
744 uint32_t fill_color,
745 uint32_t stroke_color,
746 const CFX_FillRenderOptions& fill_options,
747 BlendMode blend_type) {
748 if (!(m_RenderCaps & FXRC_GET_BITS))
749 return false;
750 CFX_FloatRect bbox;
751 if (pGraphState) {
752 bbox = path.GetBoundingBoxForStrokePath(pGraphState->m_LineWidth,
753 pGraphState->m_MiterLimit);
754 } else {
755 bbox = path.GetBoundingBox();
756 }
757 if (pObject2Device)
758 bbox = pObject2Device->TransformRect(bbox);
759
760 FX_RECT rect = bbox.GetOuterRect();
761 if (!rect.Valid())
762 return false;
763
764 auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
765 auto backdrop = pdfium::MakeRetain<CFX_DIBitmap>();
766 if (!CreateCompatibleBitmap(bitmap, rect.Width(), rect.Height()))
767 return false;
768
769 if (bitmap->IsAlphaFormat()) {
770 backdrop->Copy(bitmap);
771 } else {
772 if (!m_pDeviceDriver->GetDIBits(bitmap, rect.left, rect.top))
773 return false;
774 backdrop->Copy(bitmap);
775 }
776 CFX_DefaultRenderDevice bitmap_device;
777 bitmap_device.AttachWithBackdropAndGroupKnockout(bitmap, std::move(backdrop),
778 /*bGroupKnockout=*/true);
779
780 CFX_Matrix matrix;
781 if (pObject2Device)
782 matrix = *pObject2Device;
783 matrix.Translate(-rect.left, -rect.top);
784 if (!bitmap_device.GetDeviceDriver()->DrawPath(path, &matrix, pGraphState,
785 fill_color, stroke_color,
786 fill_options, blend_type)) {
787 return false;
788 }
789 FX_RECT src_rect(0, 0, rect.Width(), rect.Height());
790 return m_pDeviceDriver->SetDIBits(bitmap, 0, src_rect, rect.left, rect.top,
791 BlendMode::kNormal);
792 }
793
FillRectWithBlend(const FX_RECT & rect,uint32_t fill_color,BlendMode blend_type)794 bool CFX_RenderDevice::FillRectWithBlend(const FX_RECT& rect,
795 uint32_t fill_color,
796 BlendMode blend_type) {
797 if (m_pDeviceDriver->FillRectWithBlend(rect, fill_color, blend_type))
798 return true;
799
800 if (!(m_RenderCaps & FXRC_GET_BITS))
801 return false;
802
803 auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
804 if (!CreateCompatibleBitmap(bitmap, rect.Width(), rect.Height()))
805 return false;
806
807 if (!m_pDeviceDriver->GetDIBits(bitmap, rect.left, rect.top))
808 return false;
809
810 if (!bitmap->CompositeRect(0, 0, rect.Width(), rect.Height(), fill_color))
811 return false;
812
813 FX_RECT src_rect(0, 0, rect.Width(), rect.Height());
814 m_pDeviceDriver->SetDIBits(bitmap, 0, src_rect, rect.left, rect.top,
815 BlendMode::kNormal);
816 return true;
817 }
818
DrawCosmeticLine(const CFX_PointF & ptMoveTo,const CFX_PointF & ptLineTo,uint32_t color,const CFX_FillRenderOptions & fill_options,BlendMode blend_type)819 bool CFX_RenderDevice::DrawCosmeticLine(
820 const CFX_PointF& ptMoveTo,
821 const CFX_PointF& ptLineTo,
822 uint32_t color,
823 const CFX_FillRenderOptions& fill_options,
824 BlendMode blend_type) {
825 if ((color >= 0xff000000) && m_pDeviceDriver->DrawCosmeticLine(
826 ptMoveTo, ptLineTo, color, blend_type)) {
827 return true;
828 }
829 CFX_GraphStateData graph_state;
830 CFX_Path path;
831 path.AppendPoint(ptMoveTo, CFX_Path::Point::Type::kMove);
832 path.AppendPoint(ptLineTo, CFX_Path::Point::Type::kLine);
833 return m_pDeviceDriver->DrawPath(path, nullptr, &graph_state, 0, color,
834 fill_options, blend_type);
835 }
836
DrawZeroAreaPath(const std::vector<CFX_Path::Point> & path,const CFX_Matrix * matrix,bool adjust,bool aliased_path,uint32_t fill_color,uint8_t fill_alpha,BlendMode blend_type)837 void CFX_RenderDevice::DrawZeroAreaPath(
838 const std::vector<CFX_Path::Point>& path,
839 const CFX_Matrix* matrix,
840 bool adjust,
841 bool aliased_path,
842 uint32_t fill_color,
843 uint8_t fill_alpha,
844 BlendMode blend_type) {
845 if (path.empty())
846 return;
847
848 CFX_Path new_path;
849 bool thin = false;
850 bool set_identity = false;
851
852 if (!GetZeroAreaPath(path, matrix, adjust, &new_path, &thin, &set_identity))
853 return;
854
855 CFX_GraphStateData graph_state;
856 graph_state.m_LineWidth = 0.0f;
857
858 uint32_t stroke_color = fill_color;
859 if (thin)
860 stroke_color = (((fill_alpha >> 2) << 24) | (stroke_color & 0x00ffffff));
861
862 const CFX_Matrix* new_matrix = nullptr;
863 if (matrix && !matrix->IsIdentity() && !set_identity)
864 new_matrix = matrix;
865
866 CFX_FillRenderOptions path_options;
867 path_options.zero_area = true;
868 path_options.aliased_path = aliased_path;
869
870 m_pDeviceDriver->DrawPath(new_path, new_matrix, &graph_state, 0, stroke_color,
871 path_options, blend_type);
872 }
873
GetDIBits(const RetainPtr<CFX_DIBitmap> & pBitmap,int left,int top)874 bool CFX_RenderDevice::GetDIBits(const RetainPtr<CFX_DIBitmap>& pBitmap,
875 int left,
876 int top) {
877 return (m_RenderCaps & FXRC_GET_BITS) &&
878 m_pDeviceDriver->GetDIBits(pBitmap, left, top);
879 }
880
GetBackDrop()881 RetainPtr<CFX_DIBitmap> CFX_RenderDevice::GetBackDrop() {
882 return m_pDeviceDriver->GetBackDrop();
883 }
884
SetDIBitsWithBlend(const RetainPtr<CFX_DIBBase> & pBitmap,int left,int top,BlendMode blend_mode)885 bool CFX_RenderDevice::SetDIBitsWithBlend(const RetainPtr<CFX_DIBBase>& pBitmap,
886 int left,
887 int top,
888 BlendMode blend_mode) {
889 DCHECK(!pBitmap->IsMaskFormat());
890 FX_RECT dest_rect(left, top, left + pBitmap->GetWidth(),
891 top + pBitmap->GetHeight());
892 dest_rect.Intersect(m_ClipBox);
893 if (dest_rect.IsEmpty())
894 return true;
895
896 FX_RECT src_rect(dest_rect.left - left, dest_rect.top - top,
897 dest_rect.left - left + dest_rect.Width(),
898 dest_rect.top - top + dest_rect.Height());
899 if ((blend_mode == BlendMode::kNormal || (m_RenderCaps & FXRC_BLEND_MODE)) &&
900 (!pBitmap->IsAlphaFormat() || (m_RenderCaps & FXRC_ALPHA_IMAGE))) {
901 return m_pDeviceDriver->SetDIBits(pBitmap, 0, src_rect, dest_rect.left,
902 dest_rect.top, blend_mode);
903 }
904 if (!(m_RenderCaps & FXRC_GET_BITS))
905 return false;
906
907 int bg_pixel_width = dest_rect.Width();
908 int bg_pixel_height = dest_rect.Height();
909 auto background = pdfium::MakeRetain<CFX_DIBitmap>();
910 if (!background->Create(bg_pixel_width, bg_pixel_height,
911 FXDIB_Format::kRgb32)) {
912 return false;
913 }
914 if (!m_pDeviceDriver->GetDIBits(background, dest_rect.left, dest_rect.top))
915 return false;
916
917 if (!background->CompositeBitmap(0, 0, bg_pixel_width, bg_pixel_height,
918 pBitmap, src_rect.left, src_rect.top,
919 blend_mode, nullptr, false)) {
920 return false;
921 }
922 FX_RECT rect(0, 0, bg_pixel_width, bg_pixel_height);
923 return m_pDeviceDriver->SetDIBits(background, 0, rect, dest_rect.left,
924 dest_rect.top, BlendMode::kNormal);
925 }
926
StretchDIBitsWithFlagsAndBlend(const RetainPtr<CFX_DIBBase> & pBitmap,int left,int top,int dest_width,int dest_height,const FXDIB_ResampleOptions & options,BlendMode blend_mode)927 bool CFX_RenderDevice::StretchDIBitsWithFlagsAndBlend(
928 const RetainPtr<CFX_DIBBase>& pBitmap,
929 int left,
930 int top,
931 int dest_width,
932 int dest_height,
933 const FXDIB_ResampleOptions& options,
934 BlendMode blend_mode) {
935 FX_RECT dest_rect(left, top, left + dest_width, top + dest_height);
936 FX_RECT clip_box = m_ClipBox;
937 clip_box.Intersect(dest_rect);
938 return clip_box.IsEmpty() || m_pDeviceDriver->StretchDIBits(
939 pBitmap, 0, left, top, dest_width,
940 dest_height, &clip_box, options, blend_mode);
941 }
942
SetBitMask(const RetainPtr<CFX_DIBBase> & pBitmap,int left,int top,uint32_t argb)943 bool CFX_RenderDevice::SetBitMask(const RetainPtr<CFX_DIBBase>& pBitmap,
944 int left,
945 int top,
946 uint32_t argb) {
947 FX_RECT src_rect(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight());
948 return m_pDeviceDriver->SetDIBits(pBitmap, argb, src_rect, left, top,
949 BlendMode::kNormal);
950 }
951
StretchBitMask(const RetainPtr<CFX_DIBBase> & pBitmap,int left,int top,int dest_width,int dest_height,uint32_t color)952 bool CFX_RenderDevice::StretchBitMask(const RetainPtr<CFX_DIBBase>& pBitmap,
953 int left,
954 int top,
955 int dest_width,
956 int dest_height,
957 uint32_t color) {
958 return StretchBitMaskWithFlags(pBitmap, left, top, dest_width, dest_height,
959 color, FXDIB_ResampleOptions());
960 }
961
StretchBitMaskWithFlags(const RetainPtr<CFX_DIBBase> & pBitmap,int left,int top,int dest_width,int dest_height,uint32_t argb,const FXDIB_ResampleOptions & options)962 bool CFX_RenderDevice::StretchBitMaskWithFlags(
963 const RetainPtr<CFX_DIBBase>& pBitmap,
964 int left,
965 int top,
966 int dest_width,
967 int dest_height,
968 uint32_t argb,
969 const FXDIB_ResampleOptions& options) {
970 FX_RECT dest_rect(left, top, left + dest_width, top + dest_height);
971 FX_RECT clip_box = m_ClipBox;
972 clip_box.Intersect(dest_rect);
973 return m_pDeviceDriver->StretchDIBits(pBitmap, argb, left, top, dest_width,
974 dest_height, &clip_box, options,
975 BlendMode::kNormal);
976 }
977
StartDIBitsWithBlend(const RetainPtr<CFX_DIBBase> & pBitmap,int bitmap_alpha,uint32_t argb,const CFX_Matrix & matrix,const FXDIB_ResampleOptions & options,std::unique_ptr<CFX_ImageRenderer> * handle,BlendMode blend_mode)978 bool CFX_RenderDevice::StartDIBitsWithBlend(
979 const RetainPtr<CFX_DIBBase>& pBitmap,
980 int bitmap_alpha,
981 uint32_t argb,
982 const CFX_Matrix& matrix,
983 const FXDIB_ResampleOptions& options,
984 std::unique_ptr<CFX_ImageRenderer>* handle,
985 BlendMode blend_mode) {
986 return m_pDeviceDriver->StartDIBits(pBitmap, bitmap_alpha, argb, matrix,
987 options, handle, blend_mode);
988 }
989
ContinueDIBits(CFX_ImageRenderer * handle,PauseIndicatorIface * pPause)990 bool CFX_RenderDevice::ContinueDIBits(CFX_ImageRenderer* handle,
991 PauseIndicatorIface* pPause) {
992 return m_pDeviceDriver->ContinueDIBits(handle, pPause);
993 }
994
995 #if defined(_SKIA_SUPPORT_)
SetBitsWithMask(const RetainPtr<CFX_DIBBase> & pBitmap,const RetainPtr<CFX_DIBBase> & pMask,int left,int top,int bitmap_alpha,BlendMode blend_type)996 bool CFX_RenderDevice::SetBitsWithMask(const RetainPtr<CFX_DIBBase>& pBitmap,
997 const RetainPtr<CFX_DIBBase>& pMask,
998 int left,
999 int top,
1000 int bitmap_alpha,
1001 BlendMode blend_type) {
1002 return m_pDeviceDriver->SetBitsWithMask(pBitmap, pMask, left, top,
1003 bitmap_alpha, blend_type);
1004 }
1005 #endif
1006
DrawNormalText(pdfium::span<const TextCharPos> pCharPos,CFX_Font * pFont,float font_size,const CFX_Matrix & mtText2Device,uint32_t fill_color,const CFX_TextRenderOptions & options)1007 bool CFX_RenderDevice::DrawNormalText(pdfium::span<const TextCharPos> pCharPos,
1008 CFX_Font* pFont,
1009 float font_size,
1010 const CFX_Matrix& mtText2Device,
1011 uint32_t fill_color,
1012 const CFX_TextRenderOptions& options) {
1013 // `anti_alias` and `normalize` don't affect Skia rendering.
1014 int anti_alias = FT_RENDER_MODE_MONO;
1015 bool normalize = false;
1016 const bool is_text_smooth = options.IsSmooth();
1017 // |text_options| has the potential to affect all derived classes of
1018 // RenderDeviceDriverIface. But now it only affects Skia rendering.
1019 CFX_TextRenderOptions text_options(options);
1020 if (is_text_smooth) {
1021 if (GetDeviceType() == DeviceType::kDisplay && m_bpp > 1) {
1022 if (!CFX_GEModule::Get()->GetFontMgr()->FTLibrarySupportsHinting()) {
1023 // Some Freetype implementations (like the one packaged with Fedora) do
1024 // not support hinting due to patents 6219025, 6239783, 6307566,
1025 // 6225973, 6243070, 6393145, 6421054, 6282327, and 6624828; the latest
1026 // one expires 10/7/19. This makes LCD anti-aliasing very ugly, so we
1027 // instead fall back on NORMAL anti-aliasing.
1028 anti_alias = FT_RENDER_MODE_NORMAL;
1029 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
1030 // Since |anti_alias| doesn't affect Skia rendering, and Skia only
1031 // follows strictly to the options provided by |text_options|, we need
1032 // to update |text_options| so that Skia falls back on normal
1033 // anti-aliasing as well.
1034 text_options.aliasing_type = CFX_TextRenderOptions::kAntiAliasing;
1035 }
1036 } else if ((m_RenderCaps & FXRC_ALPHA_OUTPUT)) {
1037 // Whether Skia uses LCD optimization should strictly follow the
1038 // rendering options provided by |text_options|. No change needs to be
1039 // done for |text_options| here.
1040 anti_alias = FT_RENDER_MODE_LCD;
1041 normalize = true;
1042 } else if (m_bpp < 16) {
1043 // This case doesn't apply to Skia since Skia always have |m_bpp| = 32.
1044 anti_alias = FT_RENDER_MODE_NORMAL;
1045 } else {
1046 // Whether Skia uses LCD optimization should strictly follow the
1047 // rendering options provided by |text_options|. No change needs to be
1048 // done for |text_options| here.
1049 anti_alias = FT_RENDER_MODE_LCD;
1050 normalize = !pFont->GetFaceRec() ||
1051 options.aliasing_type != CFX_TextRenderOptions::kLcd;
1052 }
1053 }
1054 }
1055
1056 if (GetDeviceType() != DeviceType::kDisplay) {
1057 if (ShouldDrawDeviceText(pFont, options) &&
1058 m_pDeviceDriver->DrawDeviceText(pCharPos, pFont, mtText2Device,
1059 font_size, fill_color, text_options)) {
1060 return true;
1061 }
1062 if (FXARGB_A(fill_color) < 255)
1063 return false;
1064 } else if (options.native_text) {
1065 if (ShouldDrawDeviceText(pFont, options) &&
1066 m_pDeviceDriver->DrawDeviceText(pCharPos, pFont, mtText2Device,
1067 font_size, fill_color, text_options)) {
1068 return true;
1069 }
1070 }
1071
1072 CFX_Matrix char2device = mtText2Device;
1073 CFX_Matrix text2Device = mtText2Device;
1074 char2device.Scale(font_size, -font_size);
1075 if (fabs(char2device.a) + fabs(char2device.b) > 50 * 1.0f ||
1076 GetDeviceType() == DeviceType::kPrinter) {
1077 if (pFont->GetFaceRec()) {
1078 CFX_FillRenderOptions path_options;
1079 path_options.aliased_path = !is_text_smooth;
1080 return DrawTextPath(pCharPos, pFont, font_size, mtText2Device, nullptr,
1081 nullptr, fill_color, 0, nullptr, path_options);
1082 }
1083 }
1084 std::vector<TextGlyphPos> glyphs(pCharPos.size());
1085 for (size_t i = 0; i < glyphs.size(); ++i) {
1086 TextGlyphPos& glyph = glyphs[i];
1087 const TextCharPos& charpos = pCharPos[i];
1088
1089 glyph.m_fDeviceOrigin = text2Device.Transform(charpos.m_Origin);
1090 if (anti_alias < FT_RENDER_MODE_LCD)
1091 glyph.m_Origin.x = FXSYS_roundf(glyph.m_fDeviceOrigin.x);
1092 else
1093 glyph.m_Origin.x = static_cast<int>(floor(glyph.m_fDeviceOrigin.x));
1094 glyph.m_Origin.y = FXSYS_roundf(glyph.m_fDeviceOrigin.y);
1095
1096 CFX_Matrix matrix = charpos.GetEffectiveMatrix(char2device);
1097 glyph.m_pGlyph = pFont->LoadGlyphBitmap(
1098 charpos.m_GlyphIndex, charpos.m_bFontStyle, matrix,
1099 charpos.m_FontCharWidth, anti_alias, &text_options);
1100 }
1101 if (anti_alias < FT_RENDER_MODE_LCD && glyphs.size() > 1)
1102 AdjustGlyphSpace(&glyphs);
1103
1104 FX_RECT bmp_rect = GetGlyphsBBox(glyphs, anti_alias);
1105 bmp_rect.Intersect(m_ClipBox);
1106 if (bmp_rect.IsEmpty())
1107 return true;
1108
1109 int pixel_width = bmp_rect.Width();
1110 int pixel_height = bmp_rect.Height();
1111 int pixel_left = bmp_rect.left;
1112 int pixel_top = bmp_rect.top;
1113 if (anti_alias == FT_RENDER_MODE_MONO) {
1114 auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
1115 if (!bitmap->Create(pixel_width, pixel_height, FXDIB_Format::k1bppMask))
1116 return false;
1117 for (const TextGlyphPos& glyph : glyphs) {
1118 if (!glyph.m_pGlyph)
1119 continue;
1120
1121 absl::optional<CFX_Point> point =
1122 glyph.GetOrigin({pixel_left, pixel_top});
1123 if (!point.has_value())
1124 continue;
1125
1126 const RetainPtr<CFX_DIBitmap>& pGlyph = glyph.m_pGlyph->GetBitmap();
1127 bitmap->CompositeOneBPPMask(point.value().x, point.value().y,
1128 pGlyph->GetWidth(), pGlyph->GetHeight(),
1129 pGlyph, 0, 0);
1130 }
1131 return SetBitMask(bitmap, bmp_rect.left, bmp_rect.top, fill_color);
1132 }
1133 auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
1134 if (m_bpp == 8) {
1135 if (!bitmap->Create(pixel_width, pixel_height, FXDIB_Format::k8bppMask))
1136 return false;
1137 } else {
1138 if (!CreateCompatibleBitmap(bitmap, pixel_width, pixel_height))
1139 return false;
1140 }
1141 if (!bitmap->IsAlphaFormat() && !bitmap->IsMaskFormat()) {
1142 bitmap->Clear(0xFFFFFFFF);
1143 if (!GetDIBits(bitmap, bmp_rect.left, bmp_rect.top))
1144 return false;
1145 }
1146 int dest_width = pixel_width;
1147 int a = 0;
1148 int r = 0;
1149 int g = 0;
1150 int b = 0;
1151 if (anti_alias == FT_RENDER_MODE_LCD)
1152 std::tie(a, r, g, b) = ArgbDecode(fill_color);
1153
1154 for (const TextGlyphPos& glyph : glyphs) {
1155 if (!glyph.m_pGlyph)
1156 continue;
1157
1158 absl::optional<CFX_Point> point = glyph.GetOrigin({pixel_left, pixel_top});
1159 if (!point.has_value())
1160 continue;
1161
1162 const RetainPtr<CFX_DIBitmap>& pGlyph = glyph.m_pGlyph->GetBitmap();
1163 int ncols = pGlyph->GetWidth();
1164 int nrows = pGlyph->GetHeight();
1165 if (anti_alias == FT_RENDER_MODE_NORMAL) {
1166 if (!bitmap->CompositeMask(point.value().x, point.value().y, ncols, nrows,
1167 pGlyph, fill_color, 0, 0, BlendMode::kNormal,
1168 nullptr, false)) {
1169 return false;
1170 }
1171 continue;
1172 }
1173 ncols /= 3;
1174 int x_subpixel = static_cast<int>(glyph.m_fDeviceOrigin.x * 3) % 3;
1175 int start_col = std::max(point->x, 0);
1176 FX_SAFE_INT32 end_col_safe = point->x;
1177 end_col_safe += ncols;
1178 if (!end_col_safe.IsValid())
1179 continue;
1180
1181 int end_col = std::min<int>(end_col_safe.ValueOrDie(), dest_width);
1182 if (start_col >= end_col)
1183 continue;
1184
1185 DrawNormalTextHelper(bitmap, pGlyph, nrows, point->x, point->y, start_col,
1186 end_col, normalize, x_subpixel, a, r, g, b);
1187 }
1188
1189 if (bitmap->IsMaskFormat())
1190 SetBitMask(bitmap, bmp_rect.left, bmp_rect.top, fill_color);
1191 else
1192 SetDIBits(bitmap, bmp_rect.left, bmp_rect.top);
1193 return true;
1194 }
1195
DrawTextPath(pdfium::span<const TextCharPos> pCharPos,CFX_Font * pFont,float font_size,const CFX_Matrix & mtText2User,const CFX_Matrix * pUser2Device,const CFX_GraphStateData * pGraphState,uint32_t fill_color,FX_ARGB stroke_color,CFX_Path * pClippingPath,const CFX_FillRenderOptions & fill_options)1196 bool CFX_RenderDevice::DrawTextPath(pdfium::span<const TextCharPos> pCharPos,
1197 CFX_Font* pFont,
1198 float font_size,
1199 const CFX_Matrix& mtText2User,
1200 const CFX_Matrix* pUser2Device,
1201 const CFX_GraphStateData* pGraphState,
1202 uint32_t fill_color,
1203 FX_ARGB stroke_color,
1204 CFX_Path* pClippingPath,
1205 const CFX_FillRenderOptions& fill_options) {
1206 for (const auto& charpos : pCharPos) {
1207 const CFX_Path* pPath =
1208 pFont->LoadGlyphPath(charpos.m_GlyphIndex, charpos.m_FontCharWidth);
1209 if (!pPath)
1210 continue;
1211
1212 CFX_Matrix matrix(font_size, 0, 0, font_size, charpos.m_Origin.x,
1213 charpos.m_Origin.y);
1214 matrix = charpos.GetEffectiveMatrix(matrix);
1215 matrix.Concat(mtText2User);
1216
1217 CFX_Path transformed_path(*pPath);
1218 transformed_path.Transform(matrix);
1219 if (fill_color || stroke_color) {
1220 CFX_FillRenderOptions options(fill_options);
1221 if (fill_color)
1222 options.fill_type = CFX_FillRenderOptions::FillType::kWinding;
1223 options.text_mode = true;
1224 if (!DrawPathWithBlend(transformed_path, pUser2Device, pGraphState,
1225 fill_color, stroke_color, options,
1226 BlendMode::kNormal)) {
1227 return false;
1228 }
1229 }
1230 if (pClippingPath)
1231 pClippingPath->Append(transformed_path, pUser2Device);
1232 }
1233 return true;
1234 }
1235
DrawFillRect(const CFX_Matrix * pUser2Device,const CFX_FloatRect & rect,const FX_COLORREF & color)1236 void CFX_RenderDevice::DrawFillRect(const CFX_Matrix* pUser2Device,
1237 const CFX_FloatRect& rect,
1238 const FX_COLORREF& color) {
1239 CFX_Path path;
1240 path.AppendFloatRect(rect);
1241 DrawPath(path, pUser2Device, nullptr, color, 0,
1242 CFX_FillRenderOptions::WindingOptions());
1243 }
1244
DrawFillArea(const CFX_Matrix & mtUser2Device,const std::vector<CFX_PointF> & points,const FX_COLORREF & color)1245 void CFX_RenderDevice::DrawFillArea(const CFX_Matrix& mtUser2Device,
1246 const std::vector<CFX_PointF>& points,
1247 const FX_COLORREF& color) {
1248 DCHECK(!points.empty());
1249 CFX_Path path;
1250 path.AppendPoint(points[0], CFX_Path::Point::Type::kMove);
1251 for (size_t i = 1; i < points.size(); ++i)
1252 path.AppendPoint(points[i], CFX_Path::Point::Type::kLine);
1253
1254 DrawPath(path, &mtUser2Device, nullptr, color, 0,
1255 CFX_FillRenderOptions::EvenOddOptions());
1256 }
1257
DrawStrokeRect(const CFX_Matrix & mtUser2Device,const CFX_FloatRect & rect,const FX_COLORREF & color,float fWidth)1258 void CFX_RenderDevice::DrawStrokeRect(const CFX_Matrix& mtUser2Device,
1259 const CFX_FloatRect& rect,
1260 const FX_COLORREF& color,
1261 float fWidth) {
1262 CFX_GraphStateData gsd;
1263 gsd.m_LineWidth = fWidth;
1264
1265 CFX_Path path;
1266 path.AppendFloatRect(rect);
1267 DrawPath(path, &mtUser2Device, &gsd, 0, color,
1268 CFX_FillRenderOptions::EvenOddOptions());
1269 }
1270
DrawStrokeLine(const CFX_Matrix * pUser2Device,const CFX_PointF & ptMoveTo,const CFX_PointF & ptLineTo,const FX_COLORREF & color,float fWidth)1271 void CFX_RenderDevice::DrawStrokeLine(const CFX_Matrix* pUser2Device,
1272 const CFX_PointF& ptMoveTo,
1273 const CFX_PointF& ptLineTo,
1274 const FX_COLORREF& color,
1275 float fWidth) {
1276 CFX_Path path;
1277 path.AppendPoint(ptMoveTo, CFX_Path::Point::Type::kMove);
1278 path.AppendPoint(ptLineTo, CFX_Path::Point::Type::kLine);
1279
1280 CFX_GraphStateData gsd;
1281 gsd.m_LineWidth = fWidth;
1282
1283 DrawPath(path, pUser2Device, &gsd, 0, color,
1284 CFX_FillRenderOptions::EvenOddOptions());
1285 }
1286
DrawFillRect(const CFX_Matrix * pUser2Device,const CFX_FloatRect & rect,const CFX_Color & color,int32_t nTransparency)1287 void CFX_RenderDevice::DrawFillRect(const CFX_Matrix* pUser2Device,
1288 const CFX_FloatRect& rect,
1289 const CFX_Color& color,
1290 int32_t nTransparency) {
1291 DrawFillRect(pUser2Device, rect, color.ToFXColor(nTransparency));
1292 }
1293
DrawShadow(const CFX_Matrix & mtUser2Device,const CFX_FloatRect & rect,int32_t nTransparency,int32_t nStartGray,int32_t nEndGray)1294 void CFX_RenderDevice::DrawShadow(const CFX_Matrix& mtUser2Device,
1295 const CFX_FloatRect& rect,
1296 int32_t nTransparency,
1297 int32_t nStartGray,
1298 int32_t nEndGray) {
1299 constexpr float kBorder = 0.5f;
1300 constexpr float kSegmentWidth = 1.0f;
1301 constexpr float kLineWidth = 1.5f;
1302
1303 float fStepGray = (nEndGray - nStartGray) / rect.Height();
1304 CFX_PointF start(rect.left, 0);
1305 CFX_PointF end(rect.right, 0);
1306
1307 for (float fy = rect.bottom + kBorder; fy <= rect.top - kBorder;
1308 fy += kSegmentWidth) {
1309 start.y = fy;
1310 end.y = fy;
1311 int nGray = nStartGray + static_cast<int>(fStepGray * (fy - rect.bottom));
1312 FX_ARGB color = ArgbEncode(nTransparency, nGray, nGray, nGray);
1313 DrawStrokeLine(&mtUser2Device, start, end, color, kLineWidth);
1314 }
1315 }
1316
DrawShading(const CPDF_ShadingPattern * pPattern,const CFX_Matrix * pMatrix,const FX_RECT & clip_rect,int alpha,bool bAlphaMode)1317 bool CFX_RenderDevice::DrawShading(const CPDF_ShadingPattern* pPattern,
1318 const CFX_Matrix* pMatrix,
1319 const FX_RECT& clip_rect,
1320 int alpha,
1321 bool bAlphaMode) {
1322 return m_pDeviceDriver->DrawShading(pPattern, pMatrix, clip_rect, alpha,
1323 bAlphaMode);
1324 }
1325
DrawBorder(const CFX_Matrix * pUser2Device,const CFX_FloatRect & rect,float fWidth,const CFX_Color & color,const CFX_Color & crLeftTop,const CFX_Color & crRightBottom,BorderStyle nStyle,int32_t nTransparency)1326 void CFX_RenderDevice::DrawBorder(const CFX_Matrix* pUser2Device,
1327 const CFX_FloatRect& rect,
1328 float fWidth,
1329 const CFX_Color& color,
1330 const CFX_Color& crLeftTop,
1331 const CFX_Color& crRightBottom,
1332 BorderStyle nStyle,
1333 int32_t nTransparency) {
1334 if (fWidth <= 0.0f)
1335 return;
1336
1337 const float fLeft = rect.left;
1338 const float fRight = rect.right;
1339 const float fTop = rect.top;
1340 const float fBottom = rect.bottom;
1341 const float fHalfWidth = fWidth / 2.0f;
1342
1343 switch (nStyle) {
1344 case BorderStyle::kSolid: {
1345 CFX_Path path;
1346 path.AppendRect(fLeft, fBottom, fRight, fTop);
1347 path.AppendRect(fLeft + fWidth, fBottom + fWidth, fRight - fWidth,
1348 fTop - fWidth);
1349 DrawPath(path, pUser2Device, nullptr, color.ToFXColor(nTransparency), 0,
1350 CFX_FillRenderOptions::EvenOddOptions());
1351 break;
1352 }
1353 case BorderStyle::kDash: {
1354 CFX_GraphStateData gsd;
1355 gsd.m_DashArray = {3.0f, 3.0f};
1356 gsd.m_DashPhase = 0;
1357 gsd.m_LineWidth = fWidth;
1358
1359 CFX_Path path;
1360 path.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth),
1361 CFX_Path::Point::Type::kMove);
1362 path.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fTop - fHalfWidth),
1363 CFX_Path::Point::Type::kLine);
1364 path.AppendPoint(CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth),
1365 CFX_Path::Point::Type::kLine);
1366 path.AppendPoint(CFX_PointF(fRight - fHalfWidth, fBottom + fHalfWidth),
1367 CFX_Path::Point::Type::kLine);
1368 path.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth),
1369 CFX_Path::Point::Type::kLine);
1370 DrawPath(path, pUser2Device, &gsd, 0, color.ToFXColor(nTransparency),
1371 CFX_FillRenderOptions::WindingOptions());
1372 break;
1373 }
1374 case BorderStyle::kBeveled:
1375 case BorderStyle::kInset: {
1376 CFX_GraphStateData gsd;
1377 gsd.m_LineWidth = fHalfWidth;
1378
1379 CFX_Path path_left_top;
1380 path_left_top.AppendPoint(
1381 CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth),
1382 CFX_Path::Point::Type::kMove);
1383 path_left_top.AppendPoint(
1384 CFX_PointF(fLeft + fHalfWidth, fTop - fHalfWidth),
1385 CFX_Path::Point::Type::kLine);
1386 path_left_top.AppendPoint(
1387 CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth),
1388 CFX_Path::Point::Type::kLine);
1389 path_left_top.AppendPoint(CFX_PointF(fRight - fWidth, fTop - fWidth),
1390 CFX_Path::Point::Type::kLine);
1391 path_left_top.AppendPoint(CFX_PointF(fLeft + fWidth, fTop - fWidth),
1392 CFX_Path::Point::Type::kLine);
1393 path_left_top.AppendPoint(CFX_PointF(fLeft + fWidth, fBottom + fWidth),
1394 CFX_Path::Point::Type::kLine);
1395 path_left_top.AppendPoint(
1396 CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth),
1397 CFX_Path::Point::Type::kLine);
1398 DrawPath(path_left_top, pUser2Device, &gsd,
1399 crLeftTop.ToFXColor(nTransparency), 0,
1400 CFX_FillRenderOptions::EvenOddOptions());
1401
1402 CFX_Path path_right_bottom;
1403 path_right_bottom.AppendPoint(
1404 CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth),
1405 CFX_Path::Point::Type::kMove);
1406 path_right_bottom.AppendPoint(
1407 CFX_PointF(fRight - fHalfWidth, fBottom + fHalfWidth),
1408 CFX_Path::Point::Type::kLine);
1409 path_right_bottom.AppendPoint(
1410 CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth),
1411 CFX_Path::Point::Type::kLine);
1412 path_right_bottom.AppendPoint(
1413 CFX_PointF(fLeft + fWidth, fBottom + fWidth),
1414 CFX_Path::Point::Type::kLine);
1415 path_right_bottom.AppendPoint(
1416 CFX_PointF(fRight - fWidth, fBottom + fWidth),
1417 CFX_Path::Point::Type::kLine);
1418 path_right_bottom.AppendPoint(CFX_PointF(fRight - fWidth, fTop - fWidth),
1419 CFX_Path::Point::Type::kLine);
1420 path_right_bottom.AppendPoint(
1421 CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth),
1422 CFX_Path::Point::Type::kLine);
1423 DrawPath(path_right_bottom, pUser2Device, &gsd,
1424 crRightBottom.ToFXColor(nTransparency), 0,
1425 CFX_FillRenderOptions::EvenOddOptions());
1426
1427 CFX_Path path;
1428 path.AppendRect(fLeft, fBottom, fRight, fTop);
1429 path.AppendRect(fLeft + fHalfWidth, fBottom + fHalfWidth,
1430 fRight - fHalfWidth, fTop - fHalfWidth);
1431 DrawPath(path, pUser2Device, &gsd, color.ToFXColor(nTransparency), 0,
1432 CFX_FillRenderOptions::EvenOddOptions());
1433 break;
1434 }
1435 case BorderStyle::kUnderline: {
1436 CFX_GraphStateData gsd;
1437 gsd.m_LineWidth = fWidth;
1438
1439 CFX_Path path;
1440 path.AppendPoint(CFX_PointF(fLeft, fBottom + fHalfWidth),
1441 CFX_Path::Point::Type::kMove);
1442 path.AppendPoint(CFX_PointF(fRight, fBottom + fHalfWidth),
1443 CFX_Path::Point::Type::kLine);
1444 DrawPath(path, pUser2Device, &gsd, 0, color.ToFXColor(nTransparency),
1445 CFX_FillRenderOptions::EvenOddOptions());
1446 break;
1447 }
1448 }
1449 }
1450
MultiplyAlpha(float alpha)1451 bool CFX_RenderDevice::MultiplyAlpha(float alpha) {
1452 return m_pDeviceDriver->MultiplyAlpha(alpha);
1453 }
1454
MultiplyAlpha(const RetainPtr<CFX_DIBBase> & mask)1455 bool CFX_RenderDevice::MultiplyAlpha(const RetainPtr<CFX_DIBBase>& mask) {
1456 return m_pDeviceDriver->MultiplyAlpha(mask);
1457 }
1458
StateRestorer(CFX_RenderDevice * pDevice)1459 CFX_RenderDevice::StateRestorer::StateRestorer(CFX_RenderDevice* pDevice)
1460 : m_pDevice(pDevice) {
1461 m_pDevice->SaveState();
1462 }
1463
~StateRestorer()1464 CFX_RenderDevice::StateRestorer::~StateRestorer() {
1465 m_pDevice->RestoreState(false);
1466 }
1467