1 // Copyright 2016 PDFium Authors. All rights reserved.
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 <algorithm>
10 #include <memory>
11 #include <utility>
12 #include <vector>
13
14 #include "core/fxcrt/fx_safe_types.h"
15 #include "core/fxge/cfx_defaultrenderdevice.h"
16 #include "core/fxge/cfx_facecache.h"
17 #include "core/fxge/cfx_font.h"
18 #include "core/fxge/cfx_fontmgr.h"
19 #include "core/fxge/cfx_gemodule.h"
20 #include "core/fxge/cfx_graphstatedata.h"
21 #include "core/fxge/cfx_pathdata.h"
22 #include "core/fxge/dib/cfx_imagerenderer.h"
23 #include "core/fxge/ifx_renderdevicedriver.h"
24
25 #if defined _SKIA_SUPPORT_ || defined _SKIA_SUPPORT_PATHS_
26 #include "third_party/skia/include/core/SkTypes.h"
27 #endif
28
29 namespace {
30
AdjustGlyphSpace(std::vector<FXTEXT_GLYPHPOS> * pGlyphAndPos)31 void AdjustGlyphSpace(std::vector<FXTEXT_GLYPHPOS>* pGlyphAndPos) {
32 ASSERT(pGlyphAndPos->size() > 1);
33 std::vector<FXTEXT_GLYPHPOS>& glyphs = *pGlyphAndPos;
34 bool bVertical = glyphs.back().m_Origin.x == glyphs.front().m_Origin.x;
35 if (!bVertical && (glyphs.back().m_Origin.y != glyphs.front().m_Origin.y))
36 return;
37
38 for (size_t i = glyphs.size() - 1; i > 1; --i) {
39 FXTEXT_GLYPHPOS& next = glyphs[i];
40 int next_origin = bVertical ? next.m_Origin.y : next.m_Origin.x;
41 float next_origin_f = bVertical ? next.m_fOrigin.y : next.m_fOrigin.x;
42
43 FXTEXT_GLYPHPOS& current = glyphs[i - 1];
44 int& current_origin = bVertical ? current.m_Origin.y : current.m_Origin.x;
45 float current_origin_f =
46 bVertical ? current.m_fOrigin.y : current.m_fOrigin.x;
47
48 int space = next_origin - current_origin;
49 float space_f = next_origin_f - current_origin_f;
50 float error = fabs(space_f) - fabs(static_cast<float>(space));
51 if (error > 0.5f)
52 current_origin += space > 0 ? -1 : 1;
53 }
54 }
55
56 const uint8_t g_TextGammaAdjust[256] = {
57 0, 2, 3, 4, 6, 7, 8, 10, 11, 12, 13, 15, 16, 17, 18,
58 19, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35,
59 36, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 52,
60 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
61 68, 69, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
62 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
63 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
64 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
65 129, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
66 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 156,
67 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171,
68 172, 173, 174, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185,
69 186, 187, 188, 189, 190, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
70 200, 201, 202, 203, 204, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213,
71 214, 215, 216, 217, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227,
72 228, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 239, 240,
73 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 250, 251, 252, 253, 254,
74 255,
75 };
76
TextGammaAdjust(int value)77 int TextGammaAdjust(int value) {
78 ASSERT(value >= 0);
79 ASSERT(value <= 255);
80 return g_TextGammaAdjust[value];
81 }
82
CalcAlpha(int src,int alpha)83 int CalcAlpha(int src, int alpha) {
84 return src * alpha / 255;
85 }
86
Merge(uint8_t src,int channel,int alpha,uint8_t * dest)87 void Merge(uint8_t src, int channel, int alpha, uint8_t* dest) {
88 *dest = FXDIB_ALPHA_MERGE(*dest, channel, CalcAlpha(src, alpha));
89 }
90
MergeGammaAdjust(uint8_t src,int channel,int alpha,uint8_t * dest)91 void MergeGammaAdjust(uint8_t src, int channel, int alpha, uint8_t* dest) {
92 *dest =
93 FXDIB_ALPHA_MERGE(*dest, channel, CalcAlpha(TextGammaAdjust(src), alpha));
94 }
95
MergeGammaAdjustBgr(const uint8_t * src,int r,int g,int b,int a,uint8_t * dest)96 void MergeGammaAdjustBgr(const uint8_t* src,
97 int r,
98 int g,
99 int b,
100 int a,
101 uint8_t* dest) {
102 MergeGammaAdjust(src[0], b, a, &dest[0]);
103 MergeGammaAdjust(src[1], g, a, &dest[1]);
104 MergeGammaAdjust(src[2], r, a, &dest[2]);
105 }
106
MergeGammaAdjustRgb(const uint8_t * src,int r,int g,int b,int a,uint8_t * dest)107 void MergeGammaAdjustRgb(const uint8_t* src,
108 int r,
109 int g,
110 int b,
111 int a,
112 uint8_t* dest) {
113 MergeGammaAdjust(src[2], b, a, &dest[0]);
114 MergeGammaAdjust(src[1], g, a, &dest[1]);
115 MergeGammaAdjust(src[0], r, a, &dest[2]);
116 }
117
AverageRgb(const uint8_t * src)118 int AverageRgb(const uint8_t* src) {
119 return (src[0] + src[1] + src[2]) / 3;
120 }
121
CalculateDestAlpha(uint8_t back_alpha,int src_alpha)122 uint8_t CalculateDestAlpha(uint8_t back_alpha, int src_alpha) {
123 return back_alpha + src_alpha - back_alpha * src_alpha / 255;
124 }
125
ApplyAlpha(uint8_t * dest,int b,int g,int r,int alpha)126 void ApplyAlpha(uint8_t* dest, int b, int g, int r, int alpha) {
127 dest[0] = FXDIB_ALPHA_MERGE(dest[0], b, alpha);
128 dest[1] = FXDIB_ALPHA_MERGE(dest[1], g, alpha);
129 dest[2] = FXDIB_ALPHA_MERGE(dest[2], r, alpha);
130 }
131
ApplyDestAlpha(uint8_t back_alpha,int src_alpha,int r,int g,int b,uint8_t * dest)132 void ApplyDestAlpha(uint8_t back_alpha,
133 int src_alpha,
134 int r,
135 int g,
136 int b,
137 uint8_t* dest) {
138 uint8_t dest_alpha = CalculateDestAlpha(back_alpha, src_alpha);
139 ApplyAlpha(dest, b, g, r, src_alpha * 255 / dest_alpha);
140 dest[3] = dest_alpha;
141 }
142
NormalizeArgb(int src_value,int r,int g,int b,int a,uint8_t * dest,int src_alpha)143 void NormalizeArgb(int src_value,
144 int r,
145 int g,
146 int b,
147 int a,
148 uint8_t* dest,
149 int src_alpha) {
150 uint8_t back_alpha = dest[3];
151 if (back_alpha == 0)
152 FXARGB_SETDIB(dest, FXARGB_MAKE(src_alpha, r, g, b));
153 else if (src_alpha != 0)
154 ApplyDestAlpha(back_alpha, src_alpha, r, g, b, dest);
155 }
156
NormalizeDest(bool has_alpha,int src_value,int r,int g,int b,int a,uint8_t * dest)157 void NormalizeDest(bool has_alpha,
158 int src_value,
159 int r,
160 int g,
161 int b,
162 int a,
163 uint8_t* dest) {
164 if (has_alpha) {
165 NormalizeArgb(src_value, r, g, b, a, dest,
166 CalcAlpha(TextGammaAdjust(src_value), a));
167 return;
168 }
169 int src_alpha = CalcAlpha(TextGammaAdjust(src_value), a);
170 if (src_alpha == 0)
171 return;
172
173 ApplyAlpha(dest, b, g, r, src_alpha);
174 }
175
NormalizeSrc(bool has_alpha,int src_value,int r,int g,int b,int a,uint8_t * dest)176 void NormalizeSrc(bool has_alpha,
177 int src_value,
178 int r,
179 int g,
180 int b,
181 int a,
182 uint8_t* dest) {
183 if (!has_alpha) {
184 ApplyAlpha(dest, b, g, r, CalcAlpha(TextGammaAdjust(src_value), a));
185 return;
186 }
187 int src_alpha = CalcAlpha(TextGammaAdjust(src_value), a);
188 if (src_alpha != 0)
189 NormalizeArgb(src_value, r, g, b, a, dest, src_alpha);
190 }
191
NextPixel(uint8_t ** src_scan,uint8_t ** dst_scan,int bpp)192 void NextPixel(uint8_t** src_scan, uint8_t** dst_scan, int bpp) {
193 *src_scan += 3;
194 *dst_scan += bpp;
195 }
196
SetAlpha(bool has_alpha,uint8_t * alpha)197 void SetAlpha(bool has_alpha, uint8_t* alpha) {
198 if (has_alpha)
199 alpha[3] = 255;
200 }
201
DrawNormalTextHelper(const RetainPtr<CFX_DIBitmap> & bitmap,const RetainPtr<CFX_DIBitmap> & pGlyph,int nrows,int left,int top,int start_col,int end_col,bool bNormal,bool bBGRStripe,int x_subpixel,int a,int r,int g,int b)202 void DrawNormalTextHelper(const RetainPtr<CFX_DIBitmap>& bitmap,
203 const RetainPtr<CFX_DIBitmap>& pGlyph,
204 int nrows,
205 int left,
206 int top,
207 int start_col,
208 int end_col,
209 bool bNormal,
210 bool bBGRStripe,
211 int x_subpixel,
212 int a,
213 int r,
214 int g,
215 int b) {
216 const bool has_alpha = bitmap->GetFormat() == FXDIB_Argb;
217 uint8_t* src_buf = pGlyph->GetBuffer();
218 int src_pitch = pGlyph->GetPitch();
219 uint8_t* dest_buf = bitmap->GetBuffer();
220 int dest_pitch = bitmap->GetPitch();
221 const int Bpp = has_alpha ? 4 : bitmap->GetBPP() / 8;
222 for (int row = 0; row < nrows; ++row) {
223 int dest_row = row + top;
224 if (dest_row < 0 || dest_row >= bitmap->GetHeight())
225 continue;
226
227 uint8_t* src_scan = src_buf + row * src_pitch + (start_col - left) * 3;
228 uint8_t* dest_scan = dest_buf + dest_row * dest_pitch + start_col * Bpp;
229 if (bBGRStripe) {
230 if (x_subpixel == 0) {
231 for (int col = start_col; col < end_col; ++col) {
232 if (has_alpha) {
233 Merge(src_scan[2], r, a, &dest_scan[2]);
234 Merge(src_scan[1], g, a, &dest_scan[1]);
235 Merge(src_scan[0], b, a, &dest_scan[0]);
236 } else {
237 MergeGammaAdjustBgr(&src_scan[0], r, g, b, a, &dest_scan[0]);
238 }
239 SetAlpha(has_alpha, dest_scan);
240 NextPixel(&src_scan, &dest_scan, Bpp);
241 }
242 continue;
243 }
244 if (x_subpixel == 1) {
245 MergeGammaAdjust(src_scan[1], r, a, &dest_scan[2]);
246 MergeGammaAdjust(src_scan[0], g, a, &dest_scan[1]);
247 if (start_col > left)
248 MergeGammaAdjust(src_scan[-1], b, a, &dest_scan[0]);
249 SetAlpha(has_alpha, dest_scan);
250 NextPixel(&src_scan, &dest_scan, Bpp);
251 for (int col = start_col + 1; col < end_col - 1; ++col) {
252 MergeGammaAdjustBgr(&src_scan[-1], r, g, b, a, &dest_scan[0]);
253 SetAlpha(has_alpha, dest_scan);
254 NextPixel(&src_scan, &dest_scan, Bpp);
255 }
256 continue;
257 }
258 MergeGammaAdjust(src_scan[0], r, a, &dest_scan[2]);
259 if (start_col > left) {
260 MergeGammaAdjust(src_scan[-1], g, a, &dest_scan[1]);
261 MergeGammaAdjust(src_scan[-2], b, a, &dest_scan[0]);
262 }
263 SetAlpha(has_alpha, dest_scan);
264 NextPixel(&src_scan, &dest_scan, Bpp);
265 for (int col = start_col + 1; col < end_col - 1; ++col) {
266 MergeGammaAdjustBgr(&src_scan[-2], r, g, b, a, &dest_scan[0]);
267 SetAlpha(has_alpha, dest_scan);
268 NextPixel(&src_scan, &dest_scan, Bpp);
269 }
270 continue;
271 }
272 if (x_subpixel == 0) {
273 for (int col = start_col; col < end_col; ++col) {
274 if (bNormal) {
275 int src_value = AverageRgb(&src_scan[0]);
276 NormalizeDest(has_alpha, src_value, r, g, b, a, dest_scan);
277 } else {
278 MergeGammaAdjustRgb(&src_scan[0], r, g, b, a, &dest_scan[0]);
279 SetAlpha(has_alpha, dest_scan);
280 }
281 NextPixel(&src_scan, &dest_scan, Bpp);
282 }
283 continue;
284 }
285 if (x_subpixel == 1) {
286 if (bNormal) {
287 int src_value = start_col > left ? AverageRgb(&src_scan[-1])
288 : (src_scan[0] + src_scan[1]) / 3;
289 NormalizeSrc(has_alpha, src_value, r, g, b, a, dest_scan);
290 } else {
291 if (start_col > left)
292 MergeGammaAdjust(src_scan[-1], r, a, &dest_scan[2]);
293 MergeGammaAdjust(src_scan[0], g, a, &dest_scan[1]);
294 MergeGammaAdjust(src_scan[1], b, a, &dest_scan[0]);
295 SetAlpha(has_alpha, dest_scan);
296 }
297 NextPixel(&src_scan, &dest_scan, Bpp);
298 for (int col = start_col + 1; col < end_col; ++col) {
299 if (bNormal) {
300 int src_value = AverageRgb(&src_scan[-1]);
301 NormalizeDest(has_alpha, src_value, r, g, b, a, dest_scan);
302 } else {
303 MergeGammaAdjustRgb(&src_scan[-1], r, g, b, a, &dest_scan[0]);
304 SetAlpha(has_alpha, dest_scan);
305 }
306 NextPixel(&src_scan, &dest_scan, Bpp);
307 }
308 continue;
309 }
310 if (bNormal) {
311 int src_value =
312 start_col > left ? AverageRgb(&src_scan[-2]) : src_scan[0] / 3;
313 NormalizeSrc(has_alpha, src_value, r, g, b, a, dest_scan);
314 } else {
315 if (start_col > left) {
316 MergeGammaAdjust(src_scan[-2], r, a, &dest_scan[2]);
317 MergeGammaAdjust(src_scan[-1], g, a, &dest_scan[1]);
318 }
319 MergeGammaAdjust(src_scan[0], b, a, &dest_scan[0]);
320 SetAlpha(has_alpha, dest_scan);
321 }
322 NextPixel(&src_scan, &dest_scan, Bpp);
323 for (int col = start_col + 1; col < end_col; ++col) {
324 if (bNormal) {
325 int src_value = AverageRgb(&src_scan[-2]);
326 NormalizeDest(has_alpha, src_value, r, g, b, a, dest_scan);
327 } else {
328 MergeGammaAdjustRgb(&src_scan[-2], r, g, b, a, &dest_scan[0]);
329 SetAlpha(has_alpha, dest_scan);
330 }
331 NextPixel(&src_scan, &dest_scan, Bpp);
332 }
333 }
334 }
335
ShouldDrawDeviceText(const CFX_Font * pFont,uint32_t text_flags)336 bool ShouldDrawDeviceText(const CFX_Font* pFont, uint32_t text_flags) {
337 #if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
338 if (text_flags & FXFONT_CIDFONT)
339 return false;
340
341 const ByteString bsPsName = pFont->GetPsName();
342 if (bsPsName.Contains("+ZJHL"))
343 return false;
344
345 if (bsPsName == "CNAAJI+cmex10")
346 return false;
347 #endif
348 return true;
349 }
350
351 } // namespace
352
FXTEXT_CHARPOS()353 FXTEXT_CHARPOS::FXTEXT_CHARPOS()
354 : m_Unicode(0),
355 m_GlyphIndex(0),
356 m_FontCharWidth(0),
357 #if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
358 m_ExtGID(0),
359 #endif
360 m_FallbackFontPosition(0),
361 m_bGlyphAdjust(false),
362 m_bFontStyle(false) {
363 }
364
365 FXTEXT_CHARPOS::FXTEXT_CHARPOS(const FXTEXT_CHARPOS&) = default;
366
~FXTEXT_CHARPOS()367 FXTEXT_CHARPOS::~FXTEXT_CHARPOS(){};
368
CFX_RenderDevice()369 CFX_RenderDevice::CFX_RenderDevice()
370 : m_pBitmap(nullptr),
371 m_Width(0),
372 m_Height(0),
373 m_bpp(0),
374 m_RenderCaps(0),
375 m_DeviceClass(0) {}
376
~CFX_RenderDevice()377 CFX_RenderDevice::~CFX_RenderDevice() {
378 RestoreState(false);
379 #if defined _SKIA_SUPPORT_ || defined _SKIA_SUPPORT_PATHS_
380 Flush(true);
381 #endif
382 }
383
384 #if defined _SKIA_SUPPORT_ || defined _SKIA_SUPPORT_PATHS_
Flush(bool release)385 void CFX_RenderDevice::Flush(bool release) {
386 if (release)
387 m_pDeviceDriver.reset();
388 else
389 m_pDeviceDriver->Flush();
390 }
391 #endif
392
SetDeviceDriver(std::unique_ptr<IFX_RenderDeviceDriver> pDriver)393 void CFX_RenderDevice::SetDeviceDriver(
394 std::unique_ptr<IFX_RenderDeviceDriver> pDriver) {
395 m_pDeviceDriver = std::move(pDriver);
396 InitDeviceInfo();
397 }
398
InitDeviceInfo()399 void CFX_RenderDevice::InitDeviceInfo() {
400 m_Width = m_pDeviceDriver->GetDeviceCaps(FXDC_PIXEL_WIDTH);
401 m_Height = m_pDeviceDriver->GetDeviceCaps(FXDC_PIXEL_HEIGHT);
402 m_bpp = m_pDeviceDriver->GetDeviceCaps(FXDC_BITS_PIXEL);
403 m_RenderCaps = m_pDeviceDriver->GetDeviceCaps(FXDC_RENDER_CAPS);
404 m_DeviceClass = m_pDeviceDriver->GetDeviceCaps(FXDC_DEVICE_CLASS);
405 if (!m_pDeviceDriver->GetClipBox(&m_ClipBox)) {
406 m_ClipBox.left = 0;
407 m_ClipBox.top = 0;
408 m_ClipBox.right = m_Width;
409 m_ClipBox.bottom = m_Height;
410 }
411 }
412
SaveState()413 void CFX_RenderDevice::SaveState() {
414 m_pDeviceDriver->SaveState();
415 }
416
RestoreState(bool bKeepSaved)417 void CFX_RenderDevice::RestoreState(bool bKeepSaved) {
418 if (m_pDeviceDriver) {
419 m_pDeviceDriver->RestoreState(bKeepSaved);
420 UpdateClipBox();
421 }
422 }
423
GetDeviceCaps(int caps_id) const424 int CFX_RenderDevice::GetDeviceCaps(int caps_id) const {
425 return m_pDeviceDriver->GetDeviceCaps(caps_id);
426 }
427
GetCTM() const428 CFX_Matrix CFX_RenderDevice::GetCTM() const {
429 return m_pDeviceDriver->GetCTM();
430 }
431
GetBitmap() const432 RetainPtr<CFX_DIBitmap> CFX_RenderDevice::GetBitmap() const {
433 return m_pBitmap;
434 }
435
SetBitmap(const RetainPtr<CFX_DIBitmap> & pBitmap)436 void CFX_RenderDevice::SetBitmap(const RetainPtr<CFX_DIBitmap>& pBitmap) {
437 m_pBitmap = pBitmap;
438 }
439
CreateCompatibleBitmap(const RetainPtr<CFX_DIBitmap> & pDIB,int width,int height) const440 bool CFX_RenderDevice::CreateCompatibleBitmap(
441 const RetainPtr<CFX_DIBitmap>& pDIB,
442 int width,
443 int height) const {
444 if (m_RenderCaps & FXRC_CMYK_OUTPUT) {
445 return pDIB->Create(
446 width, height,
447 m_RenderCaps & FXRC_ALPHA_OUTPUT ? FXDIB_Cmyka : FXDIB_Cmyk);
448 }
449 if (m_RenderCaps & FXRC_BYTEMASK_OUTPUT)
450 return pDIB->Create(width, height, FXDIB_8bppMask);
451 #if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_ || defined _SKIA_SUPPORT_PATHS_
452 return pDIB->Create(
453 width, height,
454 m_RenderCaps & FXRC_ALPHA_OUTPUT ? FXDIB_Argb : FXDIB_Rgb32);
455 #else
456 return pDIB->Create(
457 width, height, m_RenderCaps & FXRC_ALPHA_OUTPUT ? FXDIB_Argb : FXDIB_Rgb);
458 #endif
459 }
460
SetClip_PathFill(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,int fill_mode)461 bool CFX_RenderDevice::SetClip_PathFill(const CFX_PathData* pPathData,
462 const CFX_Matrix* pObject2Device,
463 int fill_mode) {
464 if (!m_pDeviceDriver->SetClip_PathFill(pPathData, pObject2Device,
465 fill_mode)) {
466 return false;
467 }
468 UpdateClipBox();
469 return true;
470 }
471
SetClip_PathStroke(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState)472 bool CFX_RenderDevice::SetClip_PathStroke(
473 const CFX_PathData* pPathData,
474 const CFX_Matrix* pObject2Device,
475 const CFX_GraphStateData* pGraphState) {
476 if (!m_pDeviceDriver->SetClip_PathStroke(pPathData, pObject2Device,
477 pGraphState)) {
478 return false;
479 }
480 UpdateClipBox();
481 return true;
482 }
483
SetClip_Rect(const CFX_RectF & rtClip)484 bool CFX_RenderDevice::SetClip_Rect(const CFX_RectF& rtClip) {
485 return SetClip_Rect(FX_RECT(static_cast<int32_t>(floor(rtClip.left)),
486 static_cast<int32_t>(floor(rtClip.top)),
487 static_cast<int32_t>(ceil(rtClip.right())),
488 static_cast<int32_t>(ceil(rtClip.bottom()))));
489 }
490
SetClip_Rect(const FX_RECT & rect)491 bool CFX_RenderDevice::SetClip_Rect(const FX_RECT& rect) {
492 CFX_PathData path;
493 path.AppendRect(rect.left, rect.bottom, rect.right, rect.top);
494 if (!SetClip_PathFill(&path, nullptr, FXFILL_WINDING))
495 return false;
496
497 UpdateClipBox();
498 return true;
499 }
500
UpdateClipBox()501 void CFX_RenderDevice::UpdateClipBox() {
502 if (m_pDeviceDriver->GetClipBox(&m_ClipBox))
503 return;
504 m_ClipBox.left = 0;
505 m_ClipBox.top = 0;
506 m_ClipBox.right = m_Width;
507 m_ClipBox.bottom = m_Height;
508 }
509
DrawPathWithBlend(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState,uint32_t fill_color,uint32_t stroke_color,int fill_mode,int blend_type)510 bool CFX_RenderDevice::DrawPathWithBlend(const CFX_PathData* pPathData,
511 const CFX_Matrix* pObject2Device,
512 const CFX_GraphStateData* pGraphState,
513 uint32_t fill_color,
514 uint32_t stroke_color,
515 int fill_mode,
516 int blend_type) {
517 uint8_t stroke_alpha = pGraphState ? FXARGB_A(stroke_color) : 0;
518 uint8_t fill_alpha = (fill_mode & 3) ? FXARGB_A(fill_color) : 0;
519 const std::vector<FX_PATHPOINT>& pPoints = pPathData->GetPoints();
520 if (stroke_alpha == 0 && pPoints.size() == 2) {
521 CFX_PointF pos1 = pPoints[0].m_Point;
522 CFX_PointF pos2 = pPoints[1].m_Point;
523 if (pObject2Device) {
524 pos1 = pObject2Device->Transform(pos1);
525 pos2 = pObject2Device->Transform(pos2);
526 }
527 DrawCosmeticLine(pos1, pos2, fill_color, fill_mode, blend_type);
528 return true;
529 }
530
531 if ((pPoints.size() == 5 || pPoints.size() == 4) && stroke_alpha == 0) {
532 CFX_FloatRect rect_f;
533 if (!(fill_mode & FXFILL_RECT_AA) &&
534 pPathData->IsRect(pObject2Device, &rect_f)) {
535 FX_RECT rect_i = rect_f.GetOuterRect();
536
537 // Depending on the top/bottom, left/right values of the rect it's
538 // possible to overflow the Width() and Height() calculations. Check that
539 // the rect will have valid dimension before continuing.
540 if (!rect_i.Valid())
541 return false;
542
543 int width = static_cast<int>(ceil(rect_f.right - rect_f.left));
544 if (width < 1) {
545 width = 1;
546 if (rect_i.left == rect_i.right)
547 ++rect_i.right;
548 }
549 int height = static_cast<int>(ceil(rect_f.top - rect_f.bottom));
550 if (height < 1) {
551 height = 1;
552 if (rect_i.bottom == rect_i.top)
553 ++rect_i.bottom;
554 }
555 if (rect_i.Width() >= width + 1) {
556 if (rect_f.left - static_cast<float>(rect_i.left) >
557 static_cast<float>(rect_i.right) - rect_f.right) {
558 ++rect_i.left;
559 } else {
560 --rect_i.right;
561 }
562 }
563 if (rect_i.Height() >= height + 1) {
564 if (rect_f.top - static_cast<float>(rect_i.top) >
565 static_cast<float>(rect_i.bottom) - rect_f.bottom) {
566 ++rect_i.top;
567 } else {
568 --rect_i.bottom;
569 }
570 }
571 if (FillRectWithBlend(&rect_i, fill_color, blend_type))
572 return true;
573 }
574 }
575 if ((fill_mode & 3) && stroke_alpha == 0 && !(fill_mode & FX_FILL_STROKE) &&
576 !(fill_mode & FX_FILL_TEXT_MODE)) {
577 CFX_PathData newPath;
578 bool bThin = false;
579 bool setIdentity = false;
580 if (pPathData->GetZeroAreaPath(pObject2Device,
581 !!m_pDeviceDriver->GetDriverType(), &newPath,
582 &bThin, &setIdentity)) {
583 CFX_GraphStateData graphState;
584 graphState.m_LineWidth = 0.0f;
585
586 uint32_t strokecolor = fill_color;
587 if (bThin)
588 strokecolor = (((fill_alpha >> 2) << 24) | (strokecolor & 0x00ffffff));
589
590 const CFX_Matrix* pMatrix = nullptr;
591 if (pObject2Device && !pObject2Device->IsIdentity() && !setIdentity)
592 pMatrix = pObject2Device;
593
594 int smooth_path = FX_ZEROAREA_FILL;
595 if (fill_mode & FXFILL_NOPATHSMOOTH)
596 smooth_path |= FXFILL_NOPATHSMOOTH;
597
598 m_pDeviceDriver->DrawPath(&newPath, pMatrix, &graphState, 0, strokecolor,
599 smooth_path, blend_type);
600 }
601 }
602 if ((fill_mode & 3) && fill_alpha && stroke_alpha < 0xff &&
603 (fill_mode & FX_FILL_STROKE)) {
604 if (m_RenderCaps & FXRC_FILLSTROKE_PATH) {
605 return m_pDeviceDriver->DrawPath(pPathData, pObject2Device, pGraphState,
606 fill_color, stroke_color, fill_mode,
607 blend_type);
608 }
609 return DrawFillStrokePath(pPathData, pObject2Device, pGraphState,
610 fill_color, stroke_color, fill_mode, blend_type);
611 }
612 return m_pDeviceDriver->DrawPath(pPathData, pObject2Device, pGraphState,
613 fill_color, stroke_color, fill_mode,
614 blend_type);
615 }
616
617 // This can be removed once PDFium entirely relies on Skia
DrawFillStrokePath(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState,uint32_t fill_color,uint32_t stroke_color,int fill_mode,int blend_type)618 bool CFX_RenderDevice::DrawFillStrokePath(const CFX_PathData* pPathData,
619 const CFX_Matrix* pObject2Device,
620 const CFX_GraphStateData* pGraphState,
621 uint32_t fill_color,
622 uint32_t stroke_color,
623 int fill_mode,
624 int blend_type) {
625 if (!(m_RenderCaps & FXRC_GET_BITS))
626 return false;
627 CFX_FloatRect bbox;
628 if (pGraphState) {
629 bbox = pPathData->GetBoundingBox(pGraphState->m_LineWidth,
630 pGraphState->m_MiterLimit);
631 } else {
632 bbox = pPathData->GetBoundingBox();
633 }
634 if (pObject2Device)
635 bbox = pObject2Device->TransformRect(bbox);
636
637 CFX_Matrix ctm = GetCTM();
638 float fScaleX = fabs(ctm.a);
639 float fScaleY = fabs(ctm.d);
640 FX_RECT rect = bbox.GetOuterRect();
641 auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
642 auto Backdrop = pdfium::MakeRetain<CFX_DIBitmap>();
643 if (!CreateCompatibleBitmap(bitmap, FXSYS_round(rect.Width() * fScaleX),
644 FXSYS_round(rect.Height() * fScaleY))) {
645 return false;
646 }
647 if (bitmap->HasAlpha()) {
648 bitmap->Clear(0);
649 Backdrop->Copy(bitmap);
650 } else {
651 if (!m_pDeviceDriver->GetDIBits(bitmap, rect.left, rect.top))
652 return false;
653 Backdrop->Copy(bitmap);
654 }
655 CFX_DefaultRenderDevice bitmap_device;
656 bitmap_device.Attach(bitmap, false, Backdrop, true);
657
658 CFX_Matrix matrix;
659 if (pObject2Device)
660 matrix = *pObject2Device;
661 matrix.Translate(-rect.left, -rect.top);
662 matrix.Concat(CFX_Matrix(fScaleX, 0, 0, fScaleY, 0, 0));
663 if (!bitmap_device.GetDeviceDriver()->DrawPath(
664 pPathData, &matrix, pGraphState, fill_color, stroke_color, fill_mode,
665 blend_type)) {
666 return false;
667 }
668 #if defined _SKIA_SUPPORT_ || defined _SKIA_SUPPORT_PATHS_
669 bitmap_device.GetDeviceDriver()->Flush();
670 #endif
671 FX_RECT src_rect(0, 0, FXSYS_round(rect.Width() * fScaleX),
672 FXSYS_round(rect.Height() * fScaleY));
673 return m_pDeviceDriver->SetDIBits(bitmap, 0, &src_rect, rect.left, rect.top,
674 FXDIB_BLEND_NORMAL);
675 }
676
FillRectWithBlend(const FX_RECT * pRect,uint32_t fill_color,int blend_type)677 bool CFX_RenderDevice::FillRectWithBlend(const FX_RECT* pRect,
678 uint32_t fill_color,
679 int blend_type) {
680 if (m_pDeviceDriver->FillRectWithBlend(pRect, fill_color, blend_type))
681 return true;
682
683 if (!(m_RenderCaps & FXRC_GET_BITS))
684 return false;
685
686 auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
687 if (!CreateCompatibleBitmap(bitmap, pRect->Width(), pRect->Height()))
688 return false;
689
690 if (!m_pDeviceDriver->GetDIBits(bitmap, pRect->left, pRect->top))
691 return false;
692
693 if (!bitmap->CompositeRect(0, 0, pRect->Width(), pRect->Height(), fill_color,
694 0)) {
695 return false;
696 }
697 FX_RECT src_rect(0, 0, pRect->Width(), pRect->Height());
698 m_pDeviceDriver->SetDIBits(bitmap, 0, &src_rect, pRect->left, pRect->top,
699 FXDIB_BLEND_NORMAL);
700 return true;
701 }
702
DrawCosmeticLine(const CFX_PointF & ptMoveTo,const CFX_PointF & ptLineTo,uint32_t color,int fill_mode,int blend_type)703 bool CFX_RenderDevice::DrawCosmeticLine(const CFX_PointF& ptMoveTo,
704 const CFX_PointF& ptLineTo,
705 uint32_t color,
706 int fill_mode,
707 int blend_type) {
708 if ((color >= 0xff000000) && m_pDeviceDriver->DrawCosmeticLine(
709 ptMoveTo, ptLineTo, color, blend_type)) {
710 return true;
711 }
712 CFX_GraphStateData graph_state;
713 CFX_PathData path;
714 path.AppendPoint(ptMoveTo, FXPT_TYPE::MoveTo, false);
715 path.AppendPoint(ptLineTo, FXPT_TYPE::LineTo, false);
716 return m_pDeviceDriver->DrawPath(&path, nullptr, &graph_state, 0, color,
717 fill_mode, blend_type);
718 }
719
GetDIBits(const RetainPtr<CFX_DIBitmap> & pBitmap,int left,int top)720 bool CFX_RenderDevice::GetDIBits(const RetainPtr<CFX_DIBitmap>& pBitmap,
721 int left,
722 int top) {
723 return (m_RenderCaps & FXRC_GET_BITS) &&
724 m_pDeviceDriver->GetDIBits(pBitmap, left, top);
725 }
726
GetBackDrop()727 RetainPtr<CFX_DIBitmap> CFX_RenderDevice::GetBackDrop() {
728 return m_pDeviceDriver->GetBackDrop();
729 }
730
SetDIBitsWithBlend(const RetainPtr<CFX_DIBSource> & pBitmap,int left,int top,int blend_mode)731 bool CFX_RenderDevice::SetDIBitsWithBlend(
732 const RetainPtr<CFX_DIBSource>& pBitmap,
733 int left,
734 int top,
735 int blend_mode) {
736 ASSERT(!pBitmap->IsAlphaMask());
737 CFX_Matrix ctm = GetCTM();
738 float fScaleX = fabs(ctm.a);
739 float fScaleY = fabs(ctm.d);
740 FX_RECT dest_rect(left, top,
741 FXSYS_round(left + pBitmap->GetWidth() / fScaleX),
742 FXSYS_round(top + pBitmap->GetHeight() / fScaleY));
743 dest_rect.Intersect(m_ClipBox);
744 if (dest_rect.IsEmpty())
745 return true;
746
747 FX_RECT src_rect(dest_rect.left - left, dest_rect.top - top,
748 dest_rect.left - left + dest_rect.Width(),
749 dest_rect.top - top + dest_rect.Height());
750 src_rect.left = FXSYS_round(src_rect.left * fScaleX);
751 src_rect.top = FXSYS_round(src_rect.top * fScaleY);
752 src_rect.right = FXSYS_round(src_rect.right * fScaleX);
753 src_rect.bottom = FXSYS_round(src_rect.bottom * fScaleY);
754 if ((blend_mode == FXDIB_BLEND_NORMAL || (m_RenderCaps & FXRC_BLEND_MODE)) &&
755 (!pBitmap->HasAlpha() || (m_RenderCaps & FXRC_ALPHA_IMAGE))) {
756 return m_pDeviceDriver->SetDIBits(pBitmap, 0, &src_rect, dest_rect.left,
757 dest_rect.top, blend_mode);
758 }
759 if (!(m_RenderCaps & FXRC_GET_BITS))
760 return false;
761
762 int bg_pixel_width = FXSYS_round(dest_rect.Width() * fScaleX);
763 int bg_pixel_height = FXSYS_round(dest_rect.Height() * fScaleY);
764 auto background = pdfium::MakeRetain<CFX_DIBitmap>();
765 if (!background->Create(
766 bg_pixel_width, bg_pixel_height,
767 (m_RenderCaps & FXRC_CMYK_OUTPUT) ? FXDIB_Cmyk : FXDIB_Rgb32)) {
768 return false;
769 }
770 if (!m_pDeviceDriver->GetDIBits(background, dest_rect.left, dest_rect.top)) {
771 return false;
772 }
773 if (!background->CompositeBitmap(0, 0, bg_pixel_width, bg_pixel_height,
774 pBitmap, src_rect.left, src_rect.top,
775 blend_mode, nullptr, false)) {
776 return false;
777 }
778 FX_RECT rect(0, 0, bg_pixel_width, bg_pixel_height);
779 return m_pDeviceDriver->SetDIBits(background, 0, &rect, dest_rect.left,
780 dest_rect.top, FXDIB_BLEND_NORMAL);
781 }
782
StretchDIBitsWithFlagsAndBlend(const RetainPtr<CFX_DIBSource> & pBitmap,int left,int top,int dest_width,int dest_height,uint32_t flags,int blend_mode)783 bool CFX_RenderDevice::StretchDIBitsWithFlagsAndBlend(
784 const RetainPtr<CFX_DIBSource>& pBitmap,
785 int left,
786 int top,
787 int dest_width,
788 int dest_height,
789 uint32_t flags,
790 int blend_mode) {
791 FX_RECT dest_rect(left, top, left + dest_width, top + dest_height);
792 FX_RECT clip_box = m_ClipBox;
793 clip_box.Intersect(dest_rect);
794 return clip_box.IsEmpty() || m_pDeviceDriver->StretchDIBits(
795 pBitmap, 0, left, top, dest_width,
796 dest_height, &clip_box, flags, blend_mode);
797 }
798
SetBitMask(const RetainPtr<CFX_DIBSource> & pBitmap,int left,int top,uint32_t argb)799 bool CFX_RenderDevice::SetBitMask(const RetainPtr<CFX_DIBSource>& pBitmap,
800 int left,
801 int top,
802 uint32_t argb) {
803 FX_RECT src_rect(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight());
804 return m_pDeviceDriver->SetDIBits(pBitmap, argb, &src_rect, left, top,
805 FXDIB_BLEND_NORMAL);
806 }
807
StretchBitMask(const RetainPtr<CFX_DIBSource> & pBitmap,int left,int top,int dest_width,int dest_height,uint32_t color)808 bool CFX_RenderDevice::StretchBitMask(const RetainPtr<CFX_DIBSource>& pBitmap,
809 int left,
810 int top,
811 int dest_width,
812 int dest_height,
813 uint32_t color) {
814 return StretchBitMaskWithFlags(pBitmap, left, top, dest_width, dest_height,
815 color, 0);
816 }
817
StretchBitMaskWithFlags(const RetainPtr<CFX_DIBSource> & pBitmap,int left,int top,int dest_width,int dest_height,uint32_t argb,uint32_t flags)818 bool CFX_RenderDevice::StretchBitMaskWithFlags(
819 const RetainPtr<CFX_DIBSource>& pBitmap,
820 int left,
821 int top,
822 int dest_width,
823 int dest_height,
824 uint32_t argb,
825 uint32_t flags) {
826 FX_RECT dest_rect(left, top, left + dest_width, top + dest_height);
827 FX_RECT clip_box = m_ClipBox;
828 clip_box.Intersect(dest_rect);
829 return m_pDeviceDriver->StretchDIBits(pBitmap, argb, left, top, dest_width,
830 dest_height, &clip_box, flags,
831 FXDIB_BLEND_NORMAL);
832 }
833
StartDIBitsWithBlend(const RetainPtr<CFX_DIBSource> & pBitmap,int bitmap_alpha,uint32_t argb,const CFX_Matrix * pMatrix,uint32_t flags,std::unique_ptr<CFX_ImageRenderer> * handle,int blend_mode)834 bool CFX_RenderDevice::StartDIBitsWithBlend(
835 const RetainPtr<CFX_DIBSource>& pBitmap,
836 int bitmap_alpha,
837 uint32_t argb,
838 const CFX_Matrix* pMatrix,
839 uint32_t flags,
840 std::unique_ptr<CFX_ImageRenderer>* handle,
841 int blend_mode) {
842 return m_pDeviceDriver->StartDIBits(pBitmap, bitmap_alpha, argb, pMatrix,
843 flags, handle, blend_mode);
844 }
845
ContinueDIBits(CFX_ImageRenderer * handle,IFX_PauseIndicator * pPause)846 bool CFX_RenderDevice::ContinueDIBits(CFX_ImageRenderer* handle,
847 IFX_PauseIndicator* pPause) {
848 return m_pDeviceDriver->ContinueDIBits(handle, pPause);
849 }
850
851 #ifdef _SKIA_SUPPORT_
DebugVerifyBitmapIsPreMultiplied() const852 void CFX_RenderDevice::DebugVerifyBitmapIsPreMultiplied() const {
853 SkASSERT(0);
854 }
855
SetBitsWithMask(const RetainPtr<CFX_DIBSource> & pBitmap,const RetainPtr<CFX_DIBSource> & pMask,int left,int top,int bitmap_alpha,int blend_type)856 bool CFX_RenderDevice::SetBitsWithMask(const RetainPtr<CFX_DIBSource>& pBitmap,
857 const RetainPtr<CFX_DIBSource>& pMask,
858 int left,
859 int top,
860 int bitmap_alpha,
861 int blend_type) {
862 return m_pDeviceDriver->SetBitsWithMask(pBitmap, pMask, left, top,
863 bitmap_alpha, blend_type);
864 }
865 #endif
866
DrawNormalText(int nChars,const FXTEXT_CHARPOS * pCharPos,CFX_Font * pFont,float font_size,const CFX_Matrix * pText2Device,uint32_t fill_color,uint32_t text_flags)867 bool CFX_RenderDevice::DrawNormalText(int nChars,
868 const FXTEXT_CHARPOS* pCharPos,
869 CFX_Font* pFont,
870 float font_size,
871 const CFX_Matrix* pText2Device,
872 uint32_t fill_color,
873 uint32_t text_flags) {
874 int nativetext_flags = text_flags;
875 if (m_DeviceClass != FXDC_DISPLAY) {
876 if (!(text_flags & FXTEXT_PRINTGRAPHICTEXT)) {
877 if (ShouldDrawDeviceText(pFont, text_flags) &&
878 m_pDeviceDriver->DrawDeviceText(nChars, pCharPos, pFont, pText2Device,
879 font_size, fill_color)) {
880 return true;
881 }
882 }
883 if (FXARGB_A(fill_color) < 255)
884 return false;
885 } else if (!(text_flags & FXTEXT_NO_NATIVETEXT)) {
886 if (ShouldDrawDeviceText(pFont, text_flags) &&
887 m_pDeviceDriver->DrawDeviceText(nChars, pCharPos, pFont, pText2Device,
888 font_size, fill_color)) {
889 return true;
890 }
891 }
892 CFX_Matrix char2device;
893 CFX_Matrix text2Device;
894 if (pText2Device) {
895 char2device = *pText2Device;
896 text2Device = *pText2Device;
897 }
898
899 char2device.Scale(font_size, -font_size);
900 if (fabs(char2device.a) + fabs(char2device.b) > 50 * 1.0f ||
901 ((m_DeviceClass == FXDC_PRINTER) &&
902 !(text_flags & FXTEXT_PRINTIMAGETEXT))) {
903 if (pFont->GetFace()) {
904 int nPathFlags =
905 (text_flags & FXTEXT_NOSMOOTH) == 0 ? 0 : FXFILL_NOPATHSMOOTH;
906 return DrawTextPath(nChars, pCharPos, pFont, font_size, pText2Device,
907 nullptr, nullptr, fill_color, 0, nullptr, nPathFlags);
908 }
909 }
910 int anti_alias = FXFT_RENDER_MODE_MONO;
911 bool bNormal = false;
912 if ((text_flags & FXTEXT_NOSMOOTH) == 0) {
913 if (m_DeviceClass == FXDC_DISPLAY && m_bpp > 1) {
914 if (!CFX_GEModule::Get()->GetFontMgr()->FTLibrarySupportsHinting()) {
915 // Some Freetype implementations (like the one packaged with Fedora) do
916 // not support hinting due to patents 6219025, 6239783, 6307566,
917 // 6225973, 6243070, 6393145, 6421054, 6282327, and 6624828; the latest
918 // one expires 10/7/19. This makes LCD antialiasing very ugly, so we
919 // instead fall back on NORMAL antialiasing.
920 anti_alias = FXFT_RENDER_MODE_NORMAL;
921 } else if ((m_RenderCaps & (FXRC_ALPHA_OUTPUT | FXRC_CMYK_OUTPUT))) {
922 anti_alias = FXFT_RENDER_MODE_LCD;
923 bNormal = true;
924 } else if (m_bpp < 16) {
925 anti_alias = FXFT_RENDER_MODE_NORMAL;
926 } else {
927 anti_alias = FXFT_RENDER_MODE_LCD;
928
929 bool bClearType = false;
930 if (pFont->GetFace())
931 bClearType = !!(text_flags & FXTEXT_CLEARTYPE);
932 bNormal = !bClearType;
933 }
934 }
935 }
936 std::vector<FXTEXT_GLYPHPOS> glyphs(nChars);
937 CFX_Matrix matrixCTM = GetCTM();
938 float scale_x = fabs(matrixCTM.a);
939 float scale_y = fabs(matrixCTM.d);
940 CFX_Matrix deviceCtm = char2device;
941 CFX_Matrix m(scale_x, 0, 0, scale_y, 0, 0);
942 deviceCtm.Concat(m);
943 text2Device.Concat(m);
944
945 for (size_t i = 0; i < glyphs.size(); ++i) {
946 FXTEXT_GLYPHPOS& glyph = glyphs[i];
947 const FXTEXT_CHARPOS& charpos = pCharPos[i];
948
949 glyph.m_fOrigin = text2Device.Transform(charpos.m_Origin);
950 if (anti_alias < FXFT_RENDER_MODE_LCD)
951 glyph.m_Origin.x = FXSYS_round(glyph.m_fOrigin.x);
952 else
953 glyph.m_Origin.x = static_cast<int>(floor(glyph.m_fOrigin.x));
954 glyph.m_Origin.y = FXSYS_round(glyph.m_fOrigin.y);
955
956 if (charpos.m_bGlyphAdjust) {
957 CFX_Matrix new_matrix(
958 charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
959 charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0);
960 new_matrix.Concat(deviceCtm);
961 glyph.m_pGlyph = pFont->LoadGlyphBitmap(
962 charpos.m_GlyphIndex, charpos.m_bFontStyle, &new_matrix,
963 charpos.m_FontCharWidth, anti_alias, nativetext_flags);
964 } else {
965 glyph.m_pGlyph = pFont->LoadGlyphBitmap(
966 charpos.m_GlyphIndex, charpos.m_bFontStyle, &deviceCtm,
967 charpos.m_FontCharWidth, anti_alias, nativetext_flags);
968 }
969 }
970 if (anti_alias < FXFT_RENDER_MODE_LCD && glyphs.size() > 1)
971 AdjustGlyphSpace(&glyphs);
972
973 FX_RECT bmp_rect1 = FXGE_GetGlyphsBBox(glyphs, anti_alias, 1.0f, 1.0f);
974 if (scale_x > 1 && scale_y > 1) {
975 --bmp_rect1.left;
976 --bmp_rect1.top;
977 ++bmp_rect1.right;
978 ++bmp_rect1.bottom;
979 }
980 FX_RECT bmp_rect(FXSYS_round((float)(bmp_rect1.left) / scale_x),
981 FXSYS_round((float)(bmp_rect1.top) / scale_y),
982 FXSYS_round((float)bmp_rect1.right / scale_x),
983 FXSYS_round((float)bmp_rect1.bottom / scale_y));
984 bmp_rect.Intersect(m_ClipBox);
985 if (bmp_rect.IsEmpty())
986 return true;
987
988 int pixel_width = FXSYS_round(bmp_rect.Width() * scale_x);
989 int pixel_height = FXSYS_round(bmp_rect.Height() * scale_y);
990 int pixel_left = FXSYS_round(bmp_rect.left * scale_x);
991 int pixel_top = FXSYS_round(bmp_rect.top * scale_y);
992 if (anti_alias == FXFT_RENDER_MODE_MONO) {
993 auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
994 if (!bitmap->Create(pixel_width, pixel_height, FXDIB_1bppMask))
995 return false;
996 bitmap->Clear(0);
997 for (const FXTEXT_GLYPHPOS& glyph : glyphs) {
998 if (!glyph.m_pGlyph)
999 continue;
1000 RetainPtr<CFX_DIBitmap> pGlyph = glyph.m_pGlyph->m_pBitmap;
1001 bitmap->TransferBitmap(
1002 glyph.m_Origin.x + glyph.m_pGlyph->m_Left - pixel_left,
1003 glyph.m_Origin.y - glyph.m_pGlyph->m_Top - pixel_top,
1004 pGlyph->GetWidth(), pGlyph->GetHeight(), pGlyph, 0, 0);
1005 }
1006 return SetBitMask(bitmap, bmp_rect.left, bmp_rect.top, fill_color);
1007 }
1008 auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
1009 if (m_bpp == 8) {
1010 if (!bitmap->Create(pixel_width, pixel_height, FXDIB_8bppMask))
1011 return false;
1012 } else {
1013 if (!CreateCompatibleBitmap(bitmap, pixel_width, pixel_height))
1014 return false;
1015 }
1016 if (!bitmap->HasAlpha() && !bitmap->IsAlphaMask()) {
1017 bitmap->Clear(0xFFFFFFFF);
1018 if (!GetDIBits(bitmap, bmp_rect.left, bmp_rect.top))
1019 return false;
1020 } else {
1021 bitmap->Clear(0);
1022 if (bitmap->m_pAlphaMask)
1023 bitmap->m_pAlphaMask->Clear(0);
1024 }
1025 int dest_width = pixel_width;
1026 int a = 0;
1027 int r = 0;
1028 int g = 0;
1029 int b = 0;
1030 if (anti_alias == FXFT_RENDER_MODE_LCD)
1031 std::tie(a, r, g, b) = ArgbDecode(fill_color);
1032
1033 for (const FXTEXT_GLYPHPOS& glyph : glyphs) {
1034 if (!glyph.m_pGlyph)
1035 continue;
1036
1037 pdfium::base::CheckedNumeric<int> left = glyph.m_Origin.x;
1038 left += glyph.m_pGlyph->m_Left;
1039 left -= pixel_left;
1040 if (!left.IsValid())
1041 return false;
1042
1043 pdfium::base::CheckedNumeric<int> top = glyph.m_Origin.y;
1044 top -= glyph.m_pGlyph->m_Top;
1045 top -= pixel_top;
1046 if (!top.IsValid())
1047 return false;
1048
1049 RetainPtr<CFX_DIBitmap> pGlyph = glyph.m_pGlyph->m_pBitmap;
1050 int ncols = pGlyph->GetWidth();
1051 int nrows = pGlyph->GetHeight();
1052 if (anti_alias == FXFT_RENDER_MODE_NORMAL) {
1053 if (!bitmap->CompositeMask(left.ValueOrDie(), top.ValueOrDie(), ncols,
1054 nrows, pGlyph, fill_color, 0, 0,
1055 FXDIB_BLEND_NORMAL, nullptr, false, 0)) {
1056 return false;
1057 }
1058 continue;
1059 }
1060 bool bBGRStripe = !!(text_flags & FXTEXT_BGR_STRIPE);
1061 ncols /= 3;
1062 int x_subpixel = static_cast<int>(glyph.m_fOrigin.x * 3) % 3;
1063 int start_col =
1064 pdfium::base::ValueOrDieForType<int>(pdfium::base::CheckMax(left, 0));
1065 pdfium::base::CheckedNumeric<int> end_col_safe = left;
1066 end_col_safe += ncols;
1067 if (!end_col_safe.IsValid())
1068 return false;
1069
1070 int end_col =
1071 std::min(static_cast<int>(end_col_safe.ValueOrDie<int>()), dest_width);
1072 if (start_col >= end_col)
1073 continue;
1074
1075 DrawNormalTextHelper(bitmap, pGlyph, nrows, left.ValueOrDie(),
1076 top.ValueOrDie(), start_col, end_col, bNormal,
1077 bBGRStripe, x_subpixel, a, r, g, b);
1078 }
1079 if (bitmap->IsAlphaMask())
1080 SetBitMask(bitmap, bmp_rect.left, bmp_rect.top, fill_color);
1081 else
1082 SetDIBits(bitmap, bmp_rect.left, bmp_rect.top);
1083 return true;
1084 }
1085
DrawTextPath(int nChars,const FXTEXT_CHARPOS * pCharPos,CFX_Font * pFont,float font_size,const CFX_Matrix * pText2User,const CFX_Matrix * pUser2Device,const CFX_GraphStateData * pGraphState,uint32_t fill_color,FX_ARGB stroke_color,CFX_PathData * pClippingPath,int nFlag)1086 bool CFX_RenderDevice::DrawTextPath(int nChars,
1087 const FXTEXT_CHARPOS* pCharPos,
1088 CFX_Font* pFont,
1089 float font_size,
1090 const CFX_Matrix* pText2User,
1091 const CFX_Matrix* pUser2Device,
1092 const CFX_GraphStateData* pGraphState,
1093 uint32_t fill_color,
1094 FX_ARGB stroke_color,
1095 CFX_PathData* pClippingPath,
1096 int nFlag) {
1097 for (int iChar = 0; iChar < nChars; ++iChar) {
1098 const FXTEXT_CHARPOS& charpos = pCharPos[iChar];
1099 CFX_Matrix matrix;
1100 if (charpos.m_bGlyphAdjust) {
1101 matrix = CFX_Matrix(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
1102 charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3],
1103 0, 0);
1104 }
1105 matrix.Concat(CFX_Matrix(font_size, 0, 0, font_size, charpos.m_Origin.x,
1106 charpos.m_Origin.y));
1107 const CFX_PathData* pPath =
1108 pFont->LoadGlyphPath(charpos.m_GlyphIndex, charpos.m_FontCharWidth);
1109 if (!pPath)
1110 continue;
1111
1112 matrix.Concat(*pText2User);
1113
1114 CFX_PathData TransformedPath(*pPath);
1115 TransformedPath.Transform(&matrix);
1116 if (fill_color || stroke_color) {
1117 int fill_mode = nFlag;
1118 if (fill_color)
1119 fill_mode |= FXFILL_WINDING;
1120 fill_mode |= FX_FILL_TEXT_MODE;
1121 if (!DrawPathWithBlend(&TransformedPath, pUser2Device, pGraphState,
1122 fill_color, stroke_color, fill_mode,
1123 FXDIB_BLEND_NORMAL)) {
1124 return false;
1125 }
1126 }
1127 if (pClippingPath)
1128 pClippingPath->Append(&TransformedPath, pUser2Device);
1129 }
1130 return true;
1131 }
1132
DrawFillRect(const CFX_Matrix * pUser2Device,const CFX_FloatRect & rect,const FX_COLORREF & color)1133 void CFX_RenderDevice::DrawFillRect(const CFX_Matrix* pUser2Device,
1134 const CFX_FloatRect& rect,
1135 const FX_COLORREF& color) {
1136 CFX_PathData path;
1137 CFX_FloatRect rcTemp(rect);
1138 path.AppendRect(rcTemp.left, rcTemp.bottom, rcTemp.right, rcTemp.top);
1139 DrawPath(&path, pUser2Device, nullptr, color, 0, FXFILL_WINDING);
1140 }
1141
DrawFillArea(const CFX_Matrix * pUser2Device,const CFX_PointF * pPts,int32_t nCount,const FX_COLORREF & color)1142 void CFX_RenderDevice::DrawFillArea(const CFX_Matrix* pUser2Device,
1143 const CFX_PointF* pPts,
1144 int32_t nCount,
1145 const FX_COLORREF& color) {
1146 CFX_PathData path;
1147 path.AppendPoint(pPts[0], FXPT_TYPE::MoveTo, false);
1148 for (int32_t i = 1; i < nCount; i++)
1149 path.AppendPoint(pPts[i], FXPT_TYPE::LineTo, false);
1150
1151 DrawPath(&path, pUser2Device, nullptr, color, 0, FXFILL_ALTERNATE);
1152 }
1153
DrawStrokeRect(const CFX_Matrix * pUser2Device,const CFX_FloatRect & rect,const FX_COLORREF & color,float fWidth)1154 void CFX_RenderDevice::DrawStrokeRect(const CFX_Matrix* pUser2Device,
1155 const CFX_FloatRect& rect,
1156 const FX_COLORREF& color,
1157 float fWidth) {
1158 CFX_PathData path;
1159 CFX_FloatRect rcTemp(rect);
1160 path.AppendRect(rcTemp.left, rcTemp.bottom, rcTemp.right, rcTemp.top);
1161
1162 CFX_GraphStateData gsd;
1163 gsd.m_LineWidth = fWidth;
1164
1165 DrawPath(&path, pUser2Device, &gsd, 0, color, FXFILL_ALTERNATE);
1166 }
1167
DrawStrokeLine(const CFX_Matrix * pUser2Device,const CFX_PointF & ptMoveTo,const CFX_PointF & ptLineTo,const FX_COLORREF & color,float fWidth)1168 void CFX_RenderDevice::DrawStrokeLine(const CFX_Matrix* pUser2Device,
1169 const CFX_PointF& ptMoveTo,
1170 const CFX_PointF& ptLineTo,
1171 const FX_COLORREF& color,
1172 float fWidth) {
1173 CFX_PathData path;
1174 path.AppendPoint(ptMoveTo, FXPT_TYPE::MoveTo, false);
1175 path.AppendPoint(ptLineTo, FXPT_TYPE::LineTo, false);
1176
1177 CFX_GraphStateData gsd;
1178 gsd.m_LineWidth = fWidth;
1179
1180 DrawPath(&path, pUser2Device, &gsd, 0, color, FXFILL_ALTERNATE);
1181 }
1182
DrawFillRect(const CFX_Matrix * pUser2Device,const CFX_FloatRect & rect,const CFX_Color & color,int32_t nTransparency)1183 void CFX_RenderDevice::DrawFillRect(const CFX_Matrix* pUser2Device,
1184 const CFX_FloatRect& rect,
1185 const CFX_Color& color,
1186 int32_t nTransparency) {
1187 DrawFillRect(pUser2Device, rect, color.ToFXColor(nTransparency));
1188 }
1189
DrawShadow(const CFX_Matrix * pUser2Device,bool bVertical,bool bHorizontal,CFX_FloatRect rect,int32_t nTransparency,int32_t nStartGray,int32_t nEndGray)1190 void CFX_RenderDevice::DrawShadow(const CFX_Matrix* pUser2Device,
1191 bool bVertical,
1192 bool bHorizontal,
1193 CFX_FloatRect rect,
1194 int32_t nTransparency,
1195 int32_t nStartGray,
1196 int32_t nEndGray) {
1197 float fStepGray = 1.0f;
1198
1199 if (bVertical) {
1200 fStepGray = (nEndGray - nStartGray) / rect.Height();
1201
1202 for (float fy = rect.bottom + 0.5f; fy <= rect.top - 0.5f; fy += 1.0f) {
1203 int32_t nGray = nStartGray + (int32_t)(fStepGray * (fy - rect.bottom));
1204 DrawStrokeLine(pUser2Device, CFX_PointF(rect.left, fy),
1205 CFX_PointF(rect.right, fy),
1206 ArgbEncode(nTransparency, nGray, nGray, nGray), 1.5f);
1207 }
1208 }
1209
1210 if (bHorizontal) {
1211 fStepGray = (nEndGray - nStartGray) / rect.Width();
1212
1213 for (float fx = rect.left + 0.5f; fx <= rect.right - 0.5f; fx += 1.0f) {
1214 int32_t nGray = nStartGray + (int32_t)(fStepGray * (fx - rect.left));
1215 DrawStrokeLine(pUser2Device, CFX_PointF(fx, rect.bottom),
1216 CFX_PointF(fx, rect.top),
1217 ArgbEncode(nTransparency, nGray, nGray, nGray), 1.5f);
1218 }
1219 }
1220 }
1221
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)1222 void CFX_RenderDevice::DrawBorder(const CFX_Matrix* pUser2Device,
1223 const CFX_FloatRect& rect,
1224 float fWidth,
1225 const CFX_Color& color,
1226 const CFX_Color& crLeftTop,
1227 const CFX_Color& crRightBottom,
1228 BorderStyle nStyle,
1229 int32_t nTransparency) {
1230 float fLeft = rect.left;
1231 float fRight = rect.right;
1232 float fTop = rect.top;
1233 float fBottom = rect.bottom;
1234
1235 if (fWidth > 0.0f) {
1236 float fHalfWidth = fWidth / 2.0f;
1237
1238 switch (nStyle) {
1239 default:
1240 case BorderStyle::SOLID: {
1241 CFX_PathData path;
1242 path.AppendRect(fLeft, fBottom, fRight, fTop);
1243 path.AppendRect(fLeft + fWidth, fBottom + fWidth, fRight - fWidth,
1244 fTop - fWidth);
1245 DrawPath(&path, pUser2Device, nullptr, color.ToFXColor(nTransparency),
1246 0, FXFILL_ALTERNATE);
1247 break;
1248 }
1249 case BorderStyle::DASH: {
1250 CFX_PathData path;
1251 path.AppendPoint(
1252 CFX_PointF(fLeft + fWidth / 2.0f, fBottom + fWidth / 2.0f),
1253 FXPT_TYPE::MoveTo, false);
1254 path.AppendPoint(
1255 CFX_PointF(fLeft + fWidth / 2.0f, fTop - fWidth / 2.0f),
1256 FXPT_TYPE::LineTo, false);
1257 path.AppendPoint(
1258 CFX_PointF(fRight - fWidth / 2.0f, fTop - fWidth / 2.0f),
1259 FXPT_TYPE::LineTo, false);
1260 path.AppendPoint(
1261 CFX_PointF(fRight - fWidth / 2.0f, fBottom + fWidth / 2.0f),
1262 FXPT_TYPE::LineTo, false);
1263 path.AppendPoint(
1264 CFX_PointF(fLeft + fWidth / 2.0f, fBottom + fWidth / 2.0f),
1265 FXPT_TYPE::LineTo, false);
1266
1267 CFX_GraphStateData gsd;
1268 gsd.SetDashCount(2);
1269 gsd.m_DashArray[0] = 3.0f;
1270 gsd.m_DashArray[1] = 3.0f;
1271 gsd.m_DashPhase = 0;
1272
1273 gsd.m_LineWidth = fWidth;
1274 DrawPath(&path, pUser2Device, &gsd, 0, color.ToFXColor(nTransparency),
1275 FXFILL_WINDING);
1276 break;
1277 }
1278 case BorderStyle::BEVELED:
1279 case BorderStyle::INSET: {
1280 CFX_GraphStateData gsd;
1281 gsd.m_LineWidth = fHalfWidth;
1282
1283 CFX_PathData pathLT;
1284
1285 pathLT.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth),
1286 FXPT_TYPE::MoveTo, false);
1287 pathLT.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fTop - fHalfWidth),
1288 FXPT_TYPE::LineTo, false);
1289 pathLT.AppendPoint(CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth),
1290 FXPT_TYPE::LineTo, false);
1291 pathLT.AppendPoint(
1292 CFX_PointF(fRight - fHalfWidth * 2, fTop - fHalfWidth * 2),
1293 FXPT_TYPE::LineTo, false);
1294 pathLT.AppendPoint(
1295 CFX_PointF(fLeft + fHalfWidth * 2, fTop - fHalfWidth * 2),
1296 FXPT_TYPE::LineTo, false);
1297 pathLT.AppendPoint(
1298 CFX_PointF(fLeft + fHalfWidth * 2, fBottom + fHalfWidth * 2),
1299 FXPT_TYPE::LineTo, false);
1300 pathLT.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth),
1301 FXPT_TYPE::LineTo, false);
1302
1303 DrawPath(&pathLT, pUser2Device, &gsd,
1304 crLeftTop.ToFXColor(nTransparency), 0, FXFILL_ALTERNATE);
1305
1306 CFX_PathData pathRB;
1307 pathRB.AppendPoint(CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth),
1308 FXPT_TYPE::MoveTo, false);
1309 pathRB.AppendPoint(
1310 CFX_PointF(fRight - fHalfWidth, fBottom + fHalfWidth),
1311 FXPT_TYPE::LineTo, false);
1312 pathRB.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth),
1313 FXPT_TYPE::LineTo, false);
1314 pathRB.AppendPoint(
1315 CFX_PointF(fLeft + fHalfWidth * 2, fBottom + fHalfWidth * 2),
1316 FXPT_TYPE::LineTo, false);
1317 pathRB.AppendPoint(
1318 CFX_PointF(fRight - fHalfWidth * 2, fBottom + fHalfWidth * 2),
1319 FXPT_TYPE::LineTo, false);
1320 pathRB.AppendPoint(
1321 CFX_PointF(fRight - fHalfWidth * 2, fTop - fHalfWidth * 2),
1322 FXPT_TYPE::LineTo, false);
1323 pathRB.AppendPoint(CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth),
1324 FXPT_TYPE::LineTo, false);
1325
1326 DrawPath(&pathRB, pUser2Device, &gsd,
1327 crRightBottom.ToFXColor(nTransparency), 0, FXFILL_ALTERNATE);
1328
1329 CFX_PathData path;
1330
1331 path.AppendRect(fLeft, fBottom, fRight, fTop);
1332 path.AppendRect(fLeft + fHalfWidth, fBottom + fHalfWidth,
1333 fRight - fHalfWidth, fTop - fHalfWidth);
1334
1335 DrawPath(&path, pUser2Device, &gsd, color.ToFXColor(nTransparency), 0,
1336 FXFILL_ALTERNATE);
1337 break;
1338 }
1339 case BorderStyle::UNDERLINE: {
1340 CFX_PathData path;
1341 path.AppendPoint(CFX_PointF(fLeft, fBottom + fWidth / 2),
1342 FXPT_TYPE::MoveTo, false);
1343 path.AppendPoint(CFX_PointF(fRight, fBottom + fWidth / 2),
1344 FXPT_TYPE::LineTo, false);
1345
1346 CFX_GraphStateData gsd;
1347 gsd.m_LineWidth = fWidth;
1348
1349 DrawPath(&path, pUser2Device, &gsd, 0, color.ToFXColor(nTransparency),
1350 FXFILL_ALTERNATE);
1351 break;
1352 }
1353 }
1354 }
1355 }
1356
StateRestorer(CFX_RenderDevice * pDevice)1357 CFX_RenderDevice::StateRestorer::StateRestorer(CFX_RenderDevice* pDevice)
1358 : m_pDevice(pDevice) {
1359 m_pDevice->SaveState();
1360 }
1361
~StateRestorer()1362 CFX_RenderDevice::StateRestorer::~StateRestorer() {
1363 m_pDevice->RestoreState(false);
1364 }
1365