7#include "core/fxge/cfx_renderdevice.h"
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"
38#if defined(PDF_USE_SKIA)
39#include "third_party/skia/include/core/SkTypes.h"
44void 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))
51 for (size_t i = glyphs.size() - 1; i > 1; --i) {
53 int next_origin = bVertical ? next.m_Origin.y : next.m_Origin.x;
55 bVertical ? next.m_fDeviceOrigin.y : next.m_fDeviceOrigin.x;
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;
62 FX_SAFE_INT32 safe_space = next_origin;
63 safe_space -= current_origin;
64 if (!safe_space.IsValid())
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));
73 FX_SAFE_INT32 safe_origin = current_origin;
74 safe_origin += space > 0 ? -1 : 1;
75 if (!safe_origin.IsValid())
78 current_origin = safe_origin.ValueOrDie();
82constexpr 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,
103int TextGammaAdjust(
int value) {
105 DCHECK_LE(value, 255);
106 return kTextGammaAdjust[value];
109int CalcAlpha(
int src,
int alpha) {
110 return src * alpha / 255;
113void MergeGammaAdjust(uint8_t src,
int channel,
int alpha, uint8_t* dest) {
118void MergeGammaAdjustRgb(
const uint8_t* src,
124 MergeGammaAdjust(src[2], b, a, &dest[0]);
125 MergeGammaAdjust(src[1], g, a, &dest[1]);
126 MergeGammaAdjust(src[0], r, a, &dest[2]);
129int AverageRgb(
const uint8_t* src) {
130 return (src[0] + src[1] + src[2]) / 3;
133uint8_t CalculateDestAlpha(uint8_t back_alpha,
int src_alpha) {
134 return back_alpha + src_alpha - back_alpha * src_alpha / 255;
137void ApplyAlpha(uint8_t* dest,
int b,
int g,
int r,
int alpha) {
143void ApplyDestAlpha(uint8_t back_alpha,
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;
154void NormalizeArgb(
int src_value,
161 uint8_t back_alpha = dest[3];
164 else if (src_alpha != 0)
165 ApplyDestAlpha(back_alpha, src_alpha, r, g, b, dest);
168void NormalizeDest(
bool has_alpha,
176 NormalizeArgb(src_value, r, g, b, a, dest,
177 CalcAlpha(TextGammaAdjust(src_value), a));
180 int src_alpha = CalcAlpha(TextGammaAdjust(src_value), a);
184 ApplyAlpha(dest, b, g, r, src_alpha);
187void NormalizeSrc(
bool has_alpha,
195 ApplyAlpha(dest, b, g, r, CalcAlpha(TextGammaAdjust(src_value), a));
198 int src_alpha = CalcAlpha(TextGammaAdjust(src_value), a);
200 NormalizeArgb(src_value, r, g, b, a, dest, src_alpha);
203void NextPixel(
const uint8_t** src_scan, uint8_t** dst_scan,
int bpp) {
208void SetAlpha(
bool has_alpha, uint8_t* alpha) {
213void DrawNormalTextHelper(
const RetainPtr<CFX_DIBitmap>& bitmap,
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())
233 const uint8_t* src_scan =
234 pGlyph->GetScanline(row).subspan((start_col - left) * 3).data();
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) {
240 int src_value = AverageRgb(&src_scan[0]);
241 NormalizeDest(has_alpha, src_value, r, g, b, a, dest_scan);
243 MergeGammaAdjustRgb(&src_scan[0], r, g, b, a, &dest_scan[0]);
244 SetAlpha(has_alpha, dest_scan);
246 NextPixel(&src_scan, &dest_scan, Bpp);
250 if (x_subpixel == 1) {
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);
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);
262 NextPixel(&src_scan, &dest_scan, Bpp);
263 for (
int col = start_col + 1; col < end_col; ++col) {
265 int src_value = AverageRgb(&src_scan[-1]);
266 NormalizeDest(has_alpha, src_value, r, g, b, a, dest_scan);
268 MergeGammaAdjustRgb(&src_scan[-1], r, g, b, a, &dest_scan[0]);
269 SetAlpha(has_alpha, dest_scan);
271 NextPixel(&src_scan, &dest_scan, Bpp);
277 start_col > left ? AverageRgb(&src_scan[-2]) : src_scan[0] / 3;
278 NormalizeSrc(has_alpha, src_value, r, g, b, a, dest_scan);
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]);
284 MergeGammaAdjust(src_scan[0], b, a, &dest_scan[0]);
285 SetAlpha(has_alpha, dest_scan);
287 NextPixel(&src_scan, &dest_scan, Bpp);
288 for (
int col = start_col + 1; col < end_col; ++col) {
290 int src_value = AverageRgb(&src_scan[-2]);
291 NormalizeDest(has_alpha, src_value, r, g, b, a, dest_scan);
293 MergeGammaAdjustRgb(&src_scan[-2], r, g, b, a, &dest_scan[0]);
294 SetAlpha(has_alpha, dest_scan);
296 NextPixel(&src_scan, &dest_scan, Bpp);
301bool ShouldDrawDeviceText(
const CFX_Font* pFont,
303#if BUILDFLAG(IS_APPLE)
304 if (options.font_is_cid)
307 const ByteString bsPsName = pFont->GetPsName();
308 if (bsPsName.Contains(
"+ZJHL"))
311 if (bsPsName ==
"CNAAJI+cmex10")
319bool CheckSimpleLinePath(pdfium::span<
const CFX_Path::
Point> points,
324 bool* set_identity) {
325 if (points.size() != 2 && points.size() != 3)
330 (points.size() == 3 &&
332 points[0].m_Point != points[2].m_Point))) {
338 if (points[0].m_Point == points[1].m_Point)
341 for (size_t i = 0; i < 2; i++) {
342 CFX_PointF point = points[i].m_Point;
347 point = CFX_PointF(
static_cast<
int>(point.x) + 0.5f,
348 static_cast<
int>(point.y) + 0.5f);
352 if (adjust && matrix)
353 *set_identity =
true;
361bool CheckPalindromicPath(pdfium::span<
const CFX_Path::
Point> points,
364 if (points.size() <= 3 || !(points.size() % 2))
367 const size_t mid = points.size() / 2;
369 for (size_t i = 0; i < mid; i++) {
372 bool zero_area = left.m_Point == right.m_Point &&
388bool IsFoldingVerticalLine(
const CFX_PointF& a,
390 const CFX_PointF& c) {
391 return a.x == b.x && b.x == c.x && (b.y - a.y) * (b.y - c.y) > 0;
394bool IsFoldingHorizontalLine(
const CFX_PointF& a,
396 const CFX_PointF& c) {
397 return a.y == b.y && b.y == c.y && (b.x - a.x) * (b.x - c.x) > 0;
400bool IsFoldingDiagonalLine(
const CFX_PointF& a,
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);
407bool GetZeroAreaPath(pdfium::span<
const CFX_Path::
Point> points,
412 bool* set_identity) {
413 *set_identity =
false;
415 if (points.size() < 2)
418 if (CheckSimpleLinePath(points, matrix, adjust, new_path, thin,
423 if (CheckPalindromicPath(points, new_path, thin))
426 for (size_t i = 0; i < points.size(); i++) {
435 DCHECK_LT(i, points.size());
440 size_t next_index = (i + 1) % (points.size());
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);
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);
469 size_t new_path_size = new_path->GetPoints().size();
470 if (points.size() > 3 && new_path_size > 0)
472 return new_path_size != 0;
475FXDIB_Format GetCreateCompatibleBitmapFormat(
int render_caps) {
500 std::unique_ptr<RenderDeviceDriverIface> pDriver) {
502 DCHECK(!m_pDeviceDriver);
503 m_pDeviceDriver = std::move(pDriver);
512 m_DeviceType = m_pDeviceDriver->GetDeviceType();
513 if (!m_pDeviceDriver->GetClipBox(&m_ClipBox)) {
516 m_ClipBox
.right = m_Width;
522 m_pDeviceDriver->SaveState();
526 if (m_pDeviceDriver) {
527 m_pDeviceDriver->RestoreState(bKeepSaved);
533 return m_pDeviceDriver->GetDeviceCaps(caps_id);
545 m_pBitmap = std::move(bitmap);
552 return pDIB->Create(width, height,
553 GetCreateCompatibleBitmapFormat(m_RenderCaps));
557 m_pDeviceDriver->SetBaseClip(rect);
564 if (!m_pDeviceDriver->SetClip_PathFill(path, pObject2Device, fill_options))
575 if (!m_pDeviceDriver->SetClip_PathStroke(path, pObject2Device, pGraphState))
595 if (m_pDeviceDriver->GetClipBox(&m_ClipBox))
599 m_ClipBox
.right = m_Width;
607 uint32_t stroke_color,
618 uint32_t stroke_color,
623 uint8_t fill_alpha = fill ?
FXARGB_A(fill_color) : 0;
624 uint8_t stroke_alpha = pGraphState ?
FXARGB_A(stroke_color) : 0;
625 pdfium::span<
const CFX_Path::
Point> points = path.GetPoints();
626 if (stroke_alpha == 0 && points.size() == 2) {
627 CFX_PointF pos1 = points[0].m_Point;
628 CFX_PointF pos2 = points[1].m_Point;
629 if (pObject2Device) {
633 DrawCosmeticLine(pos1, pos2, fill_color, fill_options, blend_type);
637 if (stroke_alpha == 0 && !fill_options
.rect_aa) {
638 absl::optional<CFX_FloatRect> maybe_rect_f = path.GetRect(pObject2Device);
639 if (maybe_rect_f.has_value()) {
649 int width =
static_cast<
int>(ceil(rect_f
.right - rect_f
.left));
655 int height =
static_cast<
int>(ceil(rect_f
.top - rect_f
.bottom));
662 if (rect_f
.left -
static_cast<
float>(rect_i
.left) >
670 if (rect_f
.top -
static_cast<
float>(rect_i
.top) >
677 if (FillRectWithBlend(rect_i, fill_color, blend_type))
682 if (fill && stroke_alpha == 0 && !fill_options
.stroke &&
684 bool adjust = !!m_pDeviceDriver->GetDriverType();
685 std::vector<CFX_Path::Point> sub_path;
686 for (size_t i = 0; i < points.size(); i++) {
690 DrawZeroAreaPath(sub_path, pObject2Device, adjust,
691 fill_options.aliased_path, fill_color, fill_alpha,
696 sub_path.push_back(points[i]);
701 sub_path.push_back(points[i]);
702 sub_path.push_back(points[i + 1]);
703 sub_path.push_back(points[i + 2]);
709 sub_path.push_back(points[i]);
712 DrawZeroAreaPath(sub_path, pObject2Device, adjust,
713 fill_options.aliased_path, fill_color, fill_alpha,
717 if (fill && fill_alpha && stroke_alpha < 0xff && fill_options
.stroke) {
719#if defined(PDF_USE_SKIA)
720 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
721 m_pDeviceDriver->SetGroupKnockout(
true);
724 bool draw_fillstroke_path_result = m_pDeviceDriver->DrawPath(
725 path, pObject2Device, pGraphState, fill_color, stroke_color,
726 fill_options, blend_type);
728#if defined(PDF_USE_SKIA)
729 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
732 m_pDeviceDriver->SetGroupKnockout(
false);
735 return draw_fillstroke_path_result;
737 return DrawFillStrokePath(path, pObject2Device, pGraphState, fill_color,
738 stroke_color, fill_options, blend_type);
740 return m_pDeviceDriver->DrawPath(path, pObject2Device, pGraphState,
741 fill_color, stroke_color, fill_options,
751 uint32_t stroke_color,
770 auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
771 auto backdrop = pdfium::MakeRetain<CFX_DIBitmap>();
775 if (bitmap->IsAlphaFormat()) {
776 backdrop->Copy(bitmap);
778 if (!m_pDeviceDriver->GetDIBits(bitmap, rect.left, rect.top))
780 backdrop->Copy(bitmap);
782 CFX_DefaultRenderDevice bitmap_device;
788 matrix
= *pObject2Device;
791 fill_color, stroke_color,
792 fill_options, blend_type)) {
796 return m_pDeviceDriver->SetDIBits(std::move(bitmap), 0, src_rect, rect.left,
797 rect.top, BlendMode::kNormal);
803 if (m_pDeviceDriver->FillRectWithBlend(rect, fill_color, blend_type))
809 auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
813 if (!m_pDeviceDriver->GetDIBits(bitmap, rect.left, rect.top))
820 m_pDeviceDriver->SetDIBits(bitmap, 0, src_rect, rect.left, rect.top,
826 const CFX_PointF& ptMoveTo,
827 const CFX_PointF& ptLineTo,
831 if ((color >= 0xff000000) && m_pDeviceDriver->DrawCosmeticLine(
832 ptMoveTo, ptLineTo, color, blend_type)) {
839 return m_pDeviceDriver->DrawPath(path,
nullptr, &graph_state, 0, color,
840 fill_options, blend_type);
844 const std::vector<CFX_Path::Point>& path,
856 bool set_identity =
false;
858 if (!GetZeroAreaPath(path, matrix, adjust, &new_path, &thin, &set_identity))
864 uint32_t stroke_color = fill_color;
866 stroke_color = (((fill_alpha >> 2) << 24) | (stroke_color & 0x00ffffff));
876 m_pDeviceDriver->DrawPath(new_path, new_matrix, &graph_state, 0, stroke_color,
877 path_options, blend_type);
884 m_pDeviceDriver->GetDIBits(pBitmap, left, top);
888 return m_pDeviceDriver->GetBackDrop();
896 DCHECK(!pBitmap->IsMaskFormat());
897 FX_RECT dest_rect(left, top, left + pBitmap->GetWidth(),
898 top + pBitmap->GetHeight());
906 if ((blend_mode == BlendMode::kNormal || (m_RenderCaps &
FXRC_BLEND_MODE)) &&
908 return m_pDeviceDriver->SetDIBits(std::move(pBitmap), 0, src_rect,
909 dest_rect.left, dest_rect.top,
915 int bg_pixel_width = dest_rect
.Width();
916 int bg_pixel_height = dest_rect
.Height();
917 auto background = pdfium::MakeRetain<CFX_DIBitmap>();
918 if (!background->Create(bg_pixel_width, bg_pixel_height,
922 if (!m_pDeviceDriver->GetDIBits(background, dest_rect.left, dest_rect.top))
925 if (!background->CompositeBitmap(0, 0, bg_pixel_width, bg_pixel_height,
927 src_rect
.top, blend_mode,
nullptr,
false)) {
931 return m_pDeviceDriver->SetDIBits(background, 0, rect, dest_rect.left,
932 dest_rect.top, BlendMode::kNormal);
941 std::move(bitmap)
, left
, top
, dest_width
, dest_height
,
953 FX_RECT dest_rect
(left
, top
, left + dest_width
, top + dest_height
);
956 return clip_box.IsEmpty() || m_pDeviceDriver->StretchDIBits(
957 std::move(bitmap), 0, left, top, dest_width,
958 dest_height, &clip_box, options, blend_mode);
965 FX_RECT src_rect(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight());
966 return m_pDeviceDriver->SetDIBits(pBitmap, argb, src_rect, left, top,
988 FX_RECT dest_rect
(left
, top
, left + dest_width
, top + dest_height
);
991 return m_pDeviceDriver->StretchDIBits(std::move(bitmap), argb, left, top,
992 dest_width, dest_height, &clip_box,
993 options, BlendMode::kNormal);
1001 std::unique_ptr<CFX_ImageRenderer>* handle) {
1002 return StartDIBitsWithBlend(std::move(bitmap), alpha, argb, matrix, options,
1003 handle, BlendMode::kNormal);
1012 std::unique_ptr<CFX_ImageRenderer>* handle,
1014 return m_pDeviceDriver->StartDIBits(std::move(bitmap), alpha, argb, matrix,
1015 options, handle, blend_mode);
1020 return m_pDeviceDriver->ContinueDIBits(handle, pPause);
1023#if defined(PDF_USE_SKIA)
1024bool CFX_RenderDevice::SetBitsWithMask(RetainPtr<
const CFX_DIBBase> bitmap,
1025 RetainPtr<
const CFX_DIBBase> mask,
1029 BlendMode blend_type) {
1030 return m_pDeviceDriver->SetBitsWithMask(std::move(bitmap), std::move(mask),
1031 left, top, alpha, blend_type);
1034bool CFX_RenderDevice::SyncInternalBitmaps() {
1035 return m_pDeviceDriver->SyncInternalBitmaps();
1043 uint32_t fill_color,
1046 int anti_alias = FT_RENDER_MODE_MONO;
1047 bool normalize =
false;
1052 if (is_text_smooth) {
1060 anti_alias = FT_RENDER_MODE_NORMAL;
1072 anti_alias = FT_RENDER_MODE_LCD;
1074 }
else if (m_bpp < 16) {
1076 anti_alias = FT_RENDER_MODE_NORMAL;
1081 anti_alias = FT_RENDER_MODE_LCD;
1089 if (ShouldDrawDeviceText(pFont, options) &&
1090 m_pDeviceDriver->DrawDeviceText(pCharPos, pFont, mtText2Device,
1091 font_size, fill_color, text_options)) {
1097 if (ShouldDrawDeviceText(pFont, options) &&
1098 m_pDeviceDriver->DrawDeviceText(pCharPos, pFont, mtText2Device,
1099 font_size, fill_color, text_options)) {
1106 char2device
.Scale(font_size
, -font_size
);
1107 if (fabs(char2device
.a) + fabs(char2device
.b) > 50 * 1.0f ||
1113 nullptr, fill_color
, 0
, nullptr, path_options
);
1116 std::vector<TextGlyphPos> glyphs(pCharPos.size());
1117 for (size_t i = 0; i < glyphs.size(); ++i) {
1121 glyph.m_fDeviceOrigin = text2Device
.Transform(charpos.m_Origin
);
1122 if (anti_alias < FT_RENDER_MODE_LCD)
1123 glyph.m_Origin.x = FXSYS_roundf(glyph.m_fDeviceOrigin.x);
1125 glyph.m_Origin.x =
static_cast<
int>(floor(glyph.m_fDeviceOrigin.x));
1126 glyph.m_Origin.y = FXSYS_roundf(glyph.m_fDeviceOrigin.y);
1133 if (anti_alias < FT_RENDER_MODE_LCD && glyphs.size() > 1)
1134 AdjustGlyphSpace(&glyphs);
1136 FX_RECT bmp_rect = GetGlyphsBBox(glyphs, anti_alias);
1141 int pixel_width = bmp_rect
.Width();
1143 int pixel_left = bmp_rect
.left;
1144 int pixel_top = bmp_rect
.top;
1145 if (anti_alias == FT_RENDER_MODE_MONO) {
1146 auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
1149 for (
const TextGlyphPos& glyph : glyphs) {
1150 if (!glyph.m_pGlyph)
1153 absl::optional<CFX_Point> point =
1154 glyph.GetOrigin({pixel_left, pixel_top});
1155 if (!point.has_value())
1158 const RetainPtr<CFX_DIBitmap>& pGlyph = glyph.m_pGlyph->GetBitmap();
1159 bitmap->CompositeOneBPPMask(point.value().x, point.value().y,
1160 pGlyph->GetWidth(), pGlyph->GetHeight(),
1165 auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
1173 if (!bitmap->IsAlphaFormat() && !bitmap->IsMaskFormat()) {
1174 bitmap->Clear(0xFFFFFFFF);
1178 int dest_width = pixel_width;
1183 if (anti_alias == FT_RENDER_MODE_LCD)
1184 std::tie(a, r, g, b) = ArgbDecode(fill_color);
1186 for (
const TextGlyphPos& glyph : glyphs) {
1187 if (!glyph.m_pGlyph)
1190 absl::optional<CFX_Point> point = glyph.GetOrigin({pixel_left, pixel_top});
1191 if (!point.has_value())
1194 const RetainPtr<CFX_DIBitmap>& pGlyph = glyph.m_pGlyph->GetBitmap();
1195 int ncols = pGlyph->GetWidth();
1196 int nrows = pGlyph->GetHeight();
1197 if (anti_alias == FT_RENDER_MODE_NORMAL) {
1198 if (!bitmap->CompositeMask(point.value().x, point.value().y, ncols, nrows,
1199 pGlyph, fill_color, 0, 0, BlendMode::kNormal,
1206 int x_subpixel =
static_cast<
int>(glyph.m_fDeviceOrigin.x * 3) % 3;
1207 int start_col = std::max(point->x, 0);
1208 FX_SAFE_INT32 end_col_safe = point->x;
1209 end_col_safe += ncols;
1210 if (!end_col_safe.IsValid())
1213 int end_col = std::min<
int>(end_col_safe.ValueOrDie(), dest_width);
1214 if (start_col >= end_col)
1217 DrawNormalTextHelper(bitmap, pGlyph, nrows, point->x, point->y, start_col,
1218 end_col, normalize, x_subpixel, a, r, g, b);
1221 if (bitmap->IsMaskFormat())
1234 uint32_t fill_color,
1235 FX_ARGB stroke_color,
1238 for (
const auto& charpos : pCharPos) {
1239 const CFX_Path* pPath =
1240 pFont->LoadGlyphPath(charpos.m_GlyphIndex, charpos.m_FontCharWidth);
1244 CFX_Matrix matrix(font_size, 0, 0, font_size, charpos.m_Origin.x,
1245 charpos.m_Origin.y);
1246 matrix = charpos.GetEffectiveMatrix(matrix);
1247 matrix.Concat(mtText2User);
1249 CFX_Path transformed_path(*pPath);
1250 transformed_path.Transform(matrix);
1251 if (fill_color || stroke_color) {
1252 CFX_FillRenderOptions options(fill_options);
1254 options.fill_type = CFX_FillRenderOptions::FillType::kWinding;
1256 options.text_mode =
true;
1257 if (!DrawPathWithBlend(transformed_path, pUser2Device, pGraphState,
1258 fill_color, stroke_color, options,
1259 BlendMode::kNormal)) {
1264 pClippingPath->Append(transformed_path, pUser2Device);
1271 const FX_COLORREF& color) {
1279 const std::vector<CFX_PointF>& points,
1280 const FX_COLORREF& color) {
1281 DCHECK(!points.empty());
1284 for (size_t i = 1; i < points.size(); ++i)
1293 const FX_COLORREF& color,
1305 const CFX_PointF& ptMoveTo,
1306 const CFX_PointF& ptLineTo,
1307 const FX_COLORREF& color,
1323 int32_t nTransparency) {
1329 int32_t nTransparency,
1332 constexpr float kBorder = 0.5f;
1333 constexpr float kSegmentWidth = 1.0f;
1334 constexpr float kLineWidth = 1.5f;
1336 float fStepGray = (nEndGray - nStartGray) / rect
.Height();
1337 CFX_PointF start(rect.left, 0);
1338 CFX_PointF end(rect.right, 0);
1340 for (
float fy = rect
.bottom + kBorder; fy <= rect
.top - kBorder;
1341 fy += kSegmentWidth) {
1344 int nGray = nStartGray +
static_cast<
int>(fStepGray * (fy - rect
.bottom));
1355 return m_pDeviceDriver->DrawShading(pPattern, pMatrix, clip_rect, alpha,
1366 int32_t nTransparency) {
1370 const float fLeft = rect
.left;
1371 const float fRight = rect
.right;
1372 const float fTop = rect
.top;
1373 const float fBottom = rect
.bottom;
1374 const float fHalfWidth = fWidth / 2.0f;
1388 gsd.m_DashArray = {3.0f, 3.0f};
1393 path
.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth)
,
1395 path
.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fTop - fHalfWidth)
,
1397 path
.AppendPoint(CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth)
,
1399 path
.AppendPoint(CFX_PointF(fRight - fHalfWidth, fBottom + fHalfWidth)
,
1401 path
.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth)
,
1414 CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth)
,
1417 CFX_PointF(fLeft + fHalfWidth, fTop - fHalfWidth)
,
1420 CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth)
,
1422 path_left_top
.AppendPoint(CFX_PointF(fRight - fWidth, fTop - fWidth)
,
1424 path_left_top
.AppendPoint(CFX_PointF(fLeft + fWidth, fTop - fWidth)
,
1426 path_left_top
.AppendPoint(CFX_PointF(fLeft + fWidth, fBottom + fWidth)
,
1429 CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth)
,
1437 CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth)
,
1440 CFX_PointF(fRight - fHalfWidth, fBottom + fHalfWidth)
,
1443 CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth)
,
1446 CFX_PointF(fLeft + fWidth, fBottom + fWidth)
,
1449 CFX_PointF(fRight - fWidth, fBottom + fWidth)
,
1451 path_right_bottom
.AppendPoint(CFX_PointF(fRight - fWidth, fTop - fWidth)
,
1454 CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth)
,
1463 fRight - fHalfWidth
, fTop - fHalfWidth
);
1485 return m_pDeviceDriver->MultiplyAlpha(alpha);
1490 return m_pDeviceDriver->MultiplyAlphaMask(mask);
1495 m_pDevice->SaveState();
1499 m_pDevice->RestoreState(
false);
static constexpr FXDIB_Format kPlatformRGBFormat
static bool UseSkiaRenderer()
bool AttachWithBackdropAndGroupKnockout(RetainPtr< CFX_DIBitmap > pBitmap, RetainPtr< CFX_DIBitmap > pBackdropBitmap, bool bGroupKnockout)
CFX_FloatRect & operator=(const CFX_FloatRect &that)=default
FX_RECT GetOuterRect() const
bool FTLibrarySupportsHinting() const
const CFX_GlyphBitmap * LoadGlyphBitmap(uint32_t glyph_index, bool bFontStyle, const CFX_Matrix &matrix, int dest_width, int anti_alias, CFX_TextRenderOptions *text_options) const
FXFT_FaceRec * GetFaceRec() const
static CFX_GEModule * Get()
CFX_FontMgr * GetFontMgr() const
CFX_Matrix & operator=(const CFX_Matrix &other)=default
CFX_FloatRect TransformRect(const CFX_FloatRect &rect) const
CFX_Matrix(float a1, float b1, float c1, float d1, float e1, float f1)
CFX_PointF Transform(const CFX_PointF &point) const
void Translate(int32_t x, int32_t y)
void Scale(float sx, float sy)
CFX_FloatRect GetBoundingBox() const
void AppendRect(float left, float bottom, float right, float top)
void Append(const CFX_Path &src, const CFX_Matrix *matrix)
CFX_FloatRect GetBoundingBoxForStrokePath(float line_width, float miter_limit) const
void AppendFloatRect(const CFX_FloatRect &rect)
void AppendPoint(const CFX_PointF &point, Point::Type type)
StateRestorer(CFX_RenderDevice *pDevice)
void 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)
bool StretchBitMask(RetainPtr< CFX_DIBBase > bitmap, int left, int top, int dest_width, int dest_height, uint32_t color)
bool MultiplyAlpha(float alpha)
bool 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, uint32_t stroke_color, CFX_Path *pClippingPath, const CFX_FillRenderOptions &fill_options)
bool SetClip_Rect(const FX_RECT &pRect)
virtual ~CFX_RenderDevice()
bool SetClip_PathFill(const CFX_Path &path, const CFX_Matrix *pObject2Device, const CFX_FillRenderOptions &fill_options)
bool StretchDIBits(RetainPtr< const CFX_DIBBase > bitmap, int left, int top, int dest_width, int dest_height)
bool SetClip_PathStroke(const CFX_Path &path, const CFX_Matrix *pObject2Device, const CFX_GraphStateData *pGraphState)
RenderDeviceDriverIface * GetDeviceDriver() const
void SetBaseClip(const FX_RECT &rect)
bool GetDIBits(const RetainPtr< CFX_DIBitmap > &pBitmap, int left, int top)
bool StretchDIBitsWithFlagsAndBlend(RetainPtr< const CFX_DIBBase > bitmap, int left, int top, int dest_width, int dest_height, const FXDIB_ResampleOptions &options, BlendMode blend_mode)
bool MultiplyAlphaMask(const RetainPtr< const CFX_DIBBase > &mask)
bool ContinueDIBits(CFX_ImageRenderer *handle, PauseIndicatorIface *pPause)
void DrawFillRect(const CFX_Matrix *pUser2Device, const CFX_FloatRect &rect, const FX_COLORREF &color)
RetainPtr< const CFX_DIBitmap > GetBitmap() const
void SetDeviceDriver(std::unique_ptr< RenderDeviceDriverIface > pDriver)
bool DrawShading(const CPDF_ShadingPattern *pPattern, const CFX_Matrix *pMatrix, const FX_RECT &clip_rect, int alpha, bool bAlphaMode)
static CFX_Matrix GetFlipMatrix(float width, float height, float left, float top)
void DrawFillArea(const CFX_Matrix &mtUser2Device, const std::vector< CFX_PointF > &points, const FX_COLORREF &color)
bool StartDIBits(RetainPtr< const CFX_DIBBase > bitmap, float alpha, uint32_t argb, const CFX_Matrix &matrix, const FXDIB_ResampleOptions &options, std::unique_ptr< CFX_ImageRenderer > *handle)
bool StretchBitMaskWithFlags(RetainPtr< CFX_DIBBase > bitmap, int left, int top, int dest_width, int dest_height, uint32_t argb, const FXDIB_ResampleOptions &options)
bool 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)
RetainPtr< CFX_DIBitmap > GetBackDrop()
void SetBitmap(RetainPtr< CFX_DIBitmap > bitmap)
void DrawShadow(const CFX_Matrix &mtUser2Device, const CFX_FloatRect &rect, int32_t nTransparency, int32_t nStartGray, int32_t nEndGray)
bool SetDIBitsWithBlend(const RetainPtr< const CFX_DIBBase > &pBitmap, int left, int top, BlendMode blend_mode)
void DrawStrokeLine(const CFX_Matrix *pUser2Device, const CFX_PointF &ptMoveTo, const CFX_PointF &ptLineTo, const FX_COLORREF &color, float fWidth)
bool StartDIBitsWithBlend(RetainPtr< const CFX_DIBBase > bitmap, float alpha, uint32_t argb, const CFX_Matrix &matrix, const FXDIB_ResampleOptions &options, std::unique_ptr< CFX_ImageRenderer > *handle, BlendMode blend_mode)
bool DrawNormalText(pdfium::span< const TextCharPos > pCharPos, CFX_Font *pFont, float font_size, const CFX_Matrix &mtText2Device, uint32_t fill_color, const CFX_TextRenderOptions &options)
bool 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)
void DrawStrokeRect(const CFX_Matrix &mtUser2Device, const CFX_FloatRect &rect, const FX_COLORREF &color, float fWidth)
RetainPtr< CFX_DIBitmap > GetBitmap()
int GetDeviceCaps(int id) const
void RestoreState(bool bKeepSaved)
bool SetDIBits(const RetainPtr< const CFX_DIBBase > &pBitmap, int left, int top)
bool CreateCompatibleBitmap(const RetainPtr< CFX_DIBitmap > &pDIB, int width, int height) const
DeviceType GetDeviceType() const
bool SetBitMask(const RetainPtr< CFX_DIBBase > &pBitmap, int left, int top, uint32_t argb)
void DrawFillRect(const CFX_Matrix *pUser2Device, const CFX_FloatRect &rect, const CFX_Color &color, int32_t nTransparency)
CFX_Matrix GetEffectiveMatrix(const CFX_Matrix &matrix) const
constexpr FX_ARGB ArgbEncode(uint32_t a, uint32_t r, uint32_t g, uint32_t b)
#define FXARGB_SETDIB(p, argb)
#define FXDIB_ALPHA_MERGE(backdrop, source, source_alpha)
#define FXRC_FILLSTROKE_PATH
#define FXRC_ALPHA_OUTPUT
#define FXDC_PIXEL_HEIGHT
#define FXRC_BYTEMASK_OUTPUT
FX_COLORREF ToFXColor(int32_t nTransparency) const
static constexpr CFX_FillRenderOptions EvenOddOptions()
static constexpr CFX_FillRenderOptions WindingOptions()
AliasingType aliasing_type
constexpr CFX_TextRenderOptions(const CFX_TextRenderOptions &other)=default
void Intersect(const FX_RECT &src)
constexpr FX_RECT(int l, int t, int r, int b)