7#include "core/fxge/cfx_renderdevice.h"
15#include "build/build_config.h"
16#include "core/fxcrt/check.h"
17#include "core/fxcrt/check_op.h"
18#include "core/fxcrt/compiler_specific.h"
19#include "core/fxcrt/fx_safe_types.h"
20#include "core/fxcrt/span.h"
21#include "core/fxge/cfx_color.h"
22#include "core/fxge/cfx_defaultrenderdevice.h"
23#include "core/fxge/cfx_fillrenderoptions.h"
24#include "core/fxge/cfx_font.h"
25#include "core/fxge/cfx_fontmgr.h"
26#include "core/fxge/cfx_gemodule.h"
27#include "core/fxge/cfx_glyphbitmap.h"
28#include "core/fxge/cfx_glyphcache.h"
29#include "core/fxge/cfx_graphstatedata.h"
30#include "core/fxge/cfx_path.h"
31#include "core/fxge/cfx_textrenderoptions.h"
32#include "core/fxge/dib/cfx_dibitmap.h"
33#include "core/fxge/fx_font.h"
34#include "core/fxge/renderdevicedriver_iface.h"
35#include "core/fxge/text_char_pos.h"
36#include "core/fxge/text_glyph_pos.h"
38#if defined(PDF_USE_SKIA)
39#include "third_party/skia/include/core/SkTypes.h"
44void AdjustGlyphSpace(std::vector<TextGlyphPos>* pGlyphAndPos) {
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;
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));
74 safe_origin += space > 0 ? -1 : 1;
75 if (!safe_origin.IsValid())
78 current_origin = safe_origin.ValueOrDie();
82constexpr std::array<
const uint8_t, 256> kTextGammaAdjust = {{
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) {
104 return kTextGammaAdjust[value];
107int CalcAlpha(
int src,
int alpha) {
108 return src * alpha / 255;
111void MergeGammaAdjust(uint8_t src,
int channel,
int alpha, uint8_t* dest) {
116void MergeGammaAdjustRgb(
const uint8_t* src,
120 MergeGammaAdjust(src[2], bgra.blue, bgra.alpha, &dest[0]);
121 MergeGammaAdjust(src[1], bgra.green, bgra.alpha, &dest[1]);
122 MergeGammaAdjust(src[0], bgra.red, bgra.alpha, &dest[2]);
126int AverageRgb(
const uint8_t* src) {
127 return UNSAFE_TODO((src[0] + src[1] + src[2]) / 3);
130uint8_t CalculateDestAlpha(uint8_t back_alpha,
int src_alpha) {
131 return back_alpha + src_alpha - back_alpha * src_alpha / 255;
134void ApplyAlpha(uint8_t* dest,
const FX_BGRA_STRUCT<uint8_t>& bgra,
int alpha) {
142void ApplyDestAlpha(uint8_t back_alpha,
146 uint8_t dest_alpha = CalculateDestAlpha(back_alpha, src_alpha);
147 ApplyAlpha(dest, bgra, src_alpha * 255 / dest_alpha);
151void NormalizeArgb(
int src_value,
156 uint8_t back_alpha = dest[3];
157 if (back_alpha == 0) {
159 ArgbEncode(src_alpha, bgra.red, bgra.green, bgra.blue));
160 }
else if (src_alpha != 0) {
161 ApplyDestAlpha(back_alpha, src_alpha, bgra, dest);
166void NormalizeDest(
bool has_alpha,
171 NormalizeArgb(src_value, bgra, dest,
172 CalcAlpha(TextGammaAdjust(src_value), bgra.alpha));
175 int src_alpha = CalcAlpha(TextGammaAdjust(src_value), bgra.alpha);
179 ApplyAlpha(dest, bgra, src_alpha);
182void NormalizeSrc(
bool has_alpha,
187 ApplyAlpha(dest, bgra, CalcAlpha(TextGammaAdjust(src_value), bgra.alpha));
190 int src_alpha = CalcAlpha(TextGammaAdjust(src_value), bgra.alpha);
192 NormalizeArgb(src_value, bgra, dest, src_alpha);
195void NextPixel(
const uint8_t** src_scan, uint8_t** dst_scan,
int bpp) {
202void SetAlpha(
bool has_alpha, uint8_t* alpha) {
208void DrawNormalTextHelper(
const RetainPtr<CFX_DIBitmap>& bitmap,
219 CHECK(!bitmap->IsPremultiplied());
220 const bool has_alpha = bitmap->IsAlphaFormat();
221 const int bytes_per_pixel = 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())
227 const uint8_t* src_scan =
228 pGlyph->GetScanline(row).subspan((start_col - left) * 3).data();
229 uint8_t* dest_scan = bitmap->GetWritableScanline(dest_row)
230 .subspan(start_col * bytes_per_pixel)
232 if (x_subpixel == 0) {
233 for (
int col = start_col; col < end_col; ++col) {
235 int src_value = AverageRgb(&src_scan[0]);
236 NormalizeDest(has_alpha, src_value, bgra, dest_scan);
238 MergeGammaAdjustRgb(&src_scan[0], bgra, &dest_scan[0]);
239 SetAlpha(has_alpha, dest_scan);
241 NextPixel(&src_scan, &dest_scan, bytes_per_pixel);
246 if (x_subpixel == 1) {
248 int src_value = start_col > left ? AverageRgb(&src_scan[-1])
249 : (src_scan[0] + src_scan[1]) / 3;
250 NormalizeSrc(has_alpha, src_value, bgra, dest_scan);
252 if (start_col > left) {
253 MergeGammaAdjust(src_scan[-1], bgra.red, bgra.alpha, &dest_scan[2]);
255 MergeGammaAdjust(src_scan[0], bgra.green, bgra.alpha, &dest_scan[1]);
256 MergeGammaAdjust(src_scan[1], bgra.blue, bgra.alpha, &dest_scan[0]);
257 SetAlpha(has_alpha, dest_scan);
259 NextPixel(&src_scan, &dest_scan, bytes_per_pixel);
260 for (
int col = start_col + 1; col < end_col; ++col) {
262 int src_value = AverageRgb(&src_scan[-1]);
263 NormalizeDest(has_alpha, src_value, bgra, dest_scan);
265 MergeGammaAdjustRgb(&src_scan[-1], bgra, &dest_scan[0]);
266 SetAlpha(has_alpha, dest_scan);
268 NextPixel(&src_scan, &dest_scan, bytes_per_pixel);
274 start_col > left ? AverageRgb(&src_scan[-2]) : src_scan[0] / 3;
275 NormalizeSrc(has_alpha, src_value, bgra, dest_scan);
277 if (start_col > left) {
278 MergeGammaAdjust(src_scan[-2], bgra.red, bgra.alpha, &dest_scan[2]);
279 MergeGammaAdjust(src_scan[-1], bgra.green, bgra.alpha, &dest_scan[1]);
281 MergeGammaAdjust(src_scan[0], bgra.blue, bgra.alpha, &dest_scan[0]);
282 SetAlpha(has_alpha, dest_scan);
284 NextPixel(&src_scan, &dest_scan, bytes_per_pixel);
285 for (
int col = start_col + 1; col < end_col; ++col) {
287 int src_value = AverageRgb(&src_scan[-2]);
288 NormalizeDest(has_alpha, src_value, bgra, dest_scan);
290 MergeGammaAdjustRgb(&src_scan[-2], bgra, &dest_scan[0]);
291 SetAlpha(has_alpha, dest_scan);
293 NextPixel(&src_scan, &dest_scan, bytes_per_pixel);
299bool ShouldDrawDeviceText(
const CFX_Font* pFont,
301#if BUILDFLAG(IS_APPLE)
302 if (options.font_is_cid)
305 const ByteString bsPsName = pFont->GetPsName();
306 if (bsPsName.Contains(
"+ZJHL"))
309 if (bsPsName ==
"CNAAJI+cmex10")
317bool CheckSimpleLinePath(pdfium::span<
const CFX_Path::Point> points,
322 bool* set_identity) {
323 if (points.size() != 2 && points.size() != 3)
328 (points.size() == 3 &&
330 points[0].m_Point != points[2].m_Point))) {
336 if (points[0].m_Point == points[1].m_Point)
339 for (size_t i = 0; i < 2; i++) {
345 point = CFX_PointF(
static_cast<
int>(point.x) + 0.5f,
346 static_cast<
int>(point.y) + 0.5f);
350 if (adjust && matrix)
351 *set_identity =
true;
359bool CheckPalindromicPath(pdfium::span<
const CFX_Path::Point> points,
362 if (points.size() <= 3 || !(points.size() % 2))
365 const size_t mid = points.size() / 2;
367 for (size_t i = 0; i < mid; i++) {
370 bool zero_area = left.m_Point == right.m_Point &&
386bool IsFoldingVerticalLine(
const CFX_PointF& a,
389 return a.x == b.x && b.x == c.x && (b.y - a.y) * (b.y - c.y) > 0;
392bool IsFoldingHorizontalLine(
const CFX_PointF& a,
395 return a.y == b.y && b.y == c.y && (b.x - a.x) * (b.x - c.x) > 0;
398bool IsFoldingDiagonalLine(
const CFX_PointF& a,
401 return a.x != b.x && c.x != b.x && a.y != b.y && c.y != b.y &&
402 (a.y - b.y) * (c.x - b.x) == (c.y - b.y) * (a.x - b.x);
405bool GetZeroAreaPath(pdfium::span<
const CFX_Path::Point> points,
410 bool* set_identity) {
411 *set_identity =
false;
413 if (points.size() < 2)
416 if (CheckSimpleLinePath(points, matrix, adjust, new_path, thin,
421 if (CheckPalindromicPath(points, new_path, thin))
424 for (size_t i = 0; i < points.size(); i++) {
438 size_t next_index = (i + 1) % (points.size());
445 if (IsFoldingVerticalLine(prev.m_Point, cur.m_Point, next.m_Point)) {
446 bool use_prev = fabs(cur.m_Point.y - prev.m_Point.y) <
447 fabs(cur.m_Point.y - next.m_Point.y);
455 if (IsFoldingHorizontalLine(prev.m_Point, cur.m_Point, next.m_Point) ||
456 IsFoldingDiagonalLine(prev.m_Point, cur.m_Point, next.m_Point)) {
457 bool use_prev = fabs(cur.m_Point.x - prev.m_Point.x) <
458 fabs(cur.m_Point.x - next.m_Point.x);
467 size_t new_path_size = new_path->GetPoints().size();
468 if (points.size() > 3 && new_path_size > 0)
470 return new_path_size != 0;
473FXDIB_Format GetCreateCompatibleBitmapFormat(
int render_caps,
474 bool use_argb_premul) {
478#if defined(PDF_USE_SKIA)
479 if (use_argb_premul && (render_caps & FXRC_PREMULTIPLIED_ALPHA)) {
480 return FXDIB_Format::kBgraPremul;
506 std::unique_ptr<RenderDeviceDriverIface> pDriver) {
509 m_pDeviceDriver = std::move(pDriver);
518 m_DeviceType = m_pDeviceDriver->GetDeviceType();
519 m_ClipBox = m_pDeviceDriver->GetClipBox();
523 m_pDeviceDriver->SaveState();
527 if (m_pDeviceDriver) {
528 m_pDeviceDriver->RestoreState(bKeepSaved);
534 return m_pDeviceDriver->GetDeviceCaps(caps_id);
546 m_pBitmap = std::move(bitmap);
555 GetCreateCompatibleBitmapFormat(m_RenderCaps,
true));
559 m_pDeviceDriver->SetBaseClip(rect);
566 if (!m_pDeviceDriver->SetClip_PathFill(path, pObject2Device, fill_options))
577 if (!m_pDeviceDriver->SetClip_PathStroke(path, pObject2Device, pGraphState))
597 m_ClipBox = m_pDeviceDriver->GetClipBox();
604 uint32_t stroke_color,
608 uint8_t fill_alpha = fill ?
FXARGB_A(fill_color) : 0;
609 uint8_t stroke_alpha = pGraphState ?
FXARGB_A(stroke_color) : 0;
610 pdfium::span<
const CFX_Path::Point> points = path.GetPoints();
611 if (stroke_alpha == 0 && points.size() == 2) {
614 if (pObject2Device) {
618 DrawCosmeticLine(pos1, pos2, fill_color, fill_options);
622 if (stroke_alpha == 0 && !fill_options
.rect_aa) {
624 if (maybe_rect_f.has_value()) {
635 int width =
static_cast<
int>(ceil(rect_f
.right - rect_f
.left));
644 int height =
static_cast<
int>(ceil(rect_f
.top - rect_f
.bottom));
649 .AssignIfValid(&rect_i
.bottom)) {
655 if (rect_f
.left -
static_cast<
float>(rect_i
.left) >
667 if (rect_f
.top -
static_cast<
float>(rect_i
.top) >
669 if (!
pdfium::CheckAdd(rect_i
.top, 1).AssignIfValid(&rect_i
.top)) {
674 .AssignIfValid(&rect_i
.bottom)) {
685 if (fill && stroke_alpha == 0 && !fill_options
.stroke &&
687 bool adjust = !!m_pDeviceDriver->GetDriverType();
688 std::vector<CFX_Path::Point> sub_path;
689 for (size_t i = 0; i < points.size(); i++) {
693 DrawZeroAreaPath(sub_path, pObject2Device, adjust,
694 fill_options.aliased_path, fill_color, fill_alpha);
698 sub_path.push_back(points[i]);
703 sub_path.push_back(points[i]);
704 sub_path.push_back(points[i + 1]);
705 sub_path.push_back(points[i + 2]);
711 sub_path.push_back(points[i]);
714 DrawZeroAreaPath(sub_path, pObject2Device, adjust,
715 fill_options.aliased_path, fill_color, fill_alpha);
718 if (fill && fill_alpha && stroke_alpha < 0xff && fill_options
.stroke) {
719#if defined(PDF_USE_SKIA)
720 if (m_RenderCaps & FXRC_FILLSTROKE_PATH) {
721 const bool using_skia = CFX_DefaultRenderDevice::UseSkiaRenderer();
723 m_pDeviceDriver->SetGroupKnockout(
true);
725 bool draw_fillstroke_path_result =
726 m_pDeviceDriver->DrawPath(path, pObject2Device, pGraphState,
727 fill_color, stroke_color, fill_options);
732 m_pDeviceDriver->SetGroupKnockout(
false);
734 return draw_fillstroke_path_result;
737 return DrawFillStrokePath(path, pObject2Device, pGraphState, fill_color,
738 stroke_color, fill_options);
740 return m_pDeviceDriver->DrawPath(path, pObject2Device, pGraphState,
741 fill_color, stroke_color, fill_options);
750 uint32_t stroke_color,
768 auto bitmap =
pdfium::MakeRetain<CFX_DIBitmap>();
769 auto backdrop =
pdfium::MakeRetain<CFX_DIBitmap>();
773 if (bitmap->IsAlphaFormat()) {
774 backdrop->Copy(bitmap);
776 if (!m_pDeviceDriver->GetDIBits(bitmap, rect.left, rect.top))
778 backdrop->Copy(bitmap);
780 CFX_DefaultRenderDevice bitmap_device;
786 matrix
= *pObject2Device;
789 path, &matrix, pGraphState, fill_color, stroke_color, fill_options)) {
793 return m_pDeviceDriver->SetDIBits(std::move(bitmap), 0, src_rect,
794 rect.left, rect.top, BlendMode::kNormal);
798 if (m_pDeviceDriver->FillRect(rect, fill_color)) {
806 auto bitmap =
pdfium::MakeRetain<CFX_DIBitmap>();
811 if (!m_pDeviceDriver->GetDIBits(bitmap, rect.left, rect.top)) {
820 m_pDeviceDriver->SetDIBits(std::move(bitmap), 0, src_rect,
821 rect.left, rect.top, BlendMode::kNormal);
830 if ((color >= 0xff000000) &&
831 m_pDeviceDriver->DrawCosmeticLine(ptMoveTo, ptLineTo, color)) {
838 return m_pDeviceDriver->DrawPath(path,
nullptr, &graph_state, 0, color,
843 const std::vector<CFX_Path::Point>& path,
848 uint8_t fill_alpha) {
854 bool set_identity =
false;
856 if (!GetZeroAreaPath(path, matrix, adjust, &new_path, &thin, &set_identity))
862 uint32_t stroke_color = fill_color;
864 stroke_color = (((fill_alpha >> 2) << 24) | (stroke_color & 0x00ffffff));
874 m_pDeviceDriver->DrawPath(new_path, new_matrix, &graph_state, 0, stroke_color,
882 m_pDeviceDriver->GetDIBits(std::move(bitmap), left, top);
892 return m_pDeviceDriver->GetBackDrop();
899 DCHECK(!bitmap->IsMaskFormat());
900 FX_RECT dest_rect(left, top, left + bitmap->GetWidth(),
901 top + bitmap->GetHeight());
911 return m_pDeviceDriver->SetDIBits(std::move(bitmap), 0, src_rect,
912 dest_rect.left, dest_rect.top,
918 int bg_pixel_width = dest_rect
.Width();
919 int bg_pixel_height = dest_rect
.Height();
920 auto background =
pdfium::MakeRetain<CFX_DIBitmap>();
921 if (!background->Create(bg_pixel_width, bg_pixel_height,
925 if (!m_pDeviceDriver->GetDIBits(background, dest_rect.left, dest_rect.top))
928 if (!background->CompositeBitmap(0, 0, bg_pixel_width, bg_pixel_height,
930 src_rect
.top, blend_mode,
nullptr,
false)) {
934 return m_pDeviceDriver->SetDIBits(std::move(background), 0, rect,
935 dest_rect.left, dest_rect.top,
945 std::move(bitmap)
, left
, top
, dest_width
, dest_height
,
957 FX_RECT dest_rect
(left
, top
, left + dest_width
, top + dest_height
);
960 return clip_box.IsEmpty() || m_pDeviceDriver->StretchDIBits(
961 std::move(bitmap), 0, left, top, dest_width,
962 dest_height, &clip_box, options, blend_mode);
969 FX_RECT src_rect(0, 0, bitmap->GetWidth(), bitmap->GetHeight());
970 return m_pDeviceDriver->SetDIBits(std::move(bitmap), argb, src_rect, left,
971 top, BlendMode::kNormal);
992 FX_RECT dest_rect
(left
, top
, left + dest_width
, top + dest_height
);
995 return m_pDeviceDriver->StretchDIBits(std::move(bitmap), argb, left, top,
996 dest_width, dest_height, &clip_box,
997 options, BlendMode::kNormal);
1017 return m_pDeviceDriver->StartDIBits(std::move(bitmap), alpha, argb, matrix,
1018 options, blend_mode);
1023 return m_pDeviceDriver->ContinueDIBits(handle, pPause);
1026#if defined(PDF_USE_SKIA)
1027bool CFX_RenderDevice::DrawShading(
const CPDF_ShadingPattern& pattern,
1028 const CFX_Matrix& matrix,
1029 const FX_RECT& clip_rect,
1031 return m_pDeviceDriver->DrawShading(pattern, matrix, clip_rect, alpha);
1034bool CFX_RenderDevice::SetBitsWithMask(RetainPtr<
const CFX_DIBBase> bitmap,
1035 RetainPtr<
const CFX_DIBBase> mask,
1039 BlendMode blend_type) {
1040 return m_pDeviceDriver->SetBitsWithMask(std::move(bitmap), std::move(mask),
1041 left, top, alpha, blend_type);
1044void CFX_RenderDevice::SyncInternalBitmaps() {
1045 m_pDeviceDriver->SyncInternalBitmaps();
1053 uint32_t fill_color,
1056 int anti_alias = FT_RENDER_MODE_MONO;
1057 bool normalize =
false;
1062 if (is_text_smooth) {
1070 anti_alias = FT_RENDER_MODE_NORMAL;
1082 anti_alias = FT_RENDER_MODE_LCD;
1084 }
else if (m_bpp < 16) {
1086 anti_alias = FT_RENDER_MODE_NORMAL;
1091 anti_alias = FT_RENDER_MODE_LCD;
1098#if BUILDFLAG(IS_WIN)
1099 const bool is_printer = GetDeviceType() == DeviceType::kPrinter;
1100 bool try_native_text =
true;
1102 constexpr bool is_printer =
false;
1103 constexpr bool try_native_text =
true;
1106#if BUILDFLAG(IS_WIN)
1107 if (GetDeviceType() == DeviceType::kPrinter) {
1108 if (ShouldDrawDeviceText(pFont, options) &&
1109 m_pDeviceDriver->DrawDeviceText(pCharPos, pFont, mtText2Device,
1110 font_size, fill_color, text_options)) {
1113 if (FXARGB_A(fill_color) < 255) {
1117 try_native_text =
false;
1122 if (ShouldDrawDeviceText(pFont, options) &&
1123 m_pDeviceDriver->DrawDeviceText(pCharPos, pFont, mtText2Device,
1124 font_size, fill_color, text_options)) {
1131 char2device
.Scale(font_size
, -font_size
);
1132 if (fabs(char2device
.a) + fabs(char2device
.b) > 50 * 1.0f || is_printer) {
1136 return DrawTextPath(pCharPos, pFont, font_size, mtText2Device,
nullptr,
1137 nullptr, fill_color, 0,
nullptr, path_options);
1140 std::vector<TextGlyphPos> glyphs(pCharPos.size());
1141 for (size_t i = 0; i < glyphs.size(); ++i) {
1145 glyph.m_fDeviceOrigin = text2Device
.Transform(charpos.m_Origin
);
1146 if (anti_alias < FT_RENDER_MODE_LCD)
1147 glyph.m_Origin.x = FXSYS_roundf(glyph.m_fDeviceOrigin.x);
1149 glyph.m_Origin.x =
static_cast<
int>(floor(glyph.m_fDeviceOrigin.x));
1150 glyph.m_Origin.y = FXSYS_roundf(glyph.m_fDeviceOrigin.y);
1157 if (anti_alias < FT_RENDER_MODE_LCD && glyphs.size() > 1)
1158 AdjustGlyphSpace(&glyphs);
1160 FX_RECT bmp_rect = GetGlyphsBBox(glyphs, anti_alias);
1165 int pixel_width = bmp_rect
.Width();
1167 int pixel_left = bmp_rect
.left;
1168 int pixel_top = bmp_rect
.top;
1169 if (anti_alias == FT_RENDER_MODE_MONO) {
1170 auto bitmap =
pdfium::MakeRetain<CFX_DIBitmap>();
1173 for (
const TextGlyphPos& glyph : glyphs) {
1174 if (!glyph.m_pGlyph)
1177 std::optional<CFX_Point> point = glyph.GetOrigin({pixel_left, pixel_top});
1178 if (!point.has_value())
1181 const RetainPtr<CFX_DIBitmap>& pGlyph = glyph.m_pGlyph->GetBitmap();
1182 bitmap->CompositeOneBPPMask(point.value().x, point.value().y,
1183 pGlyph->GetWidth(), pGlyph->GetHeight(),
1189 auto bitmap =
pdfium::MakeRetain<CFX_DIBitmap>();
1196 if (!bitmap->Create(pixel_width, pixel_height,
1197 GetCreateCompatibleBitmapFormat(
1198 m_RenderCaps,
false))) {
1202 if (!bitmap->IsAlphaFormat() && !bitmap->IsMaskFormat()) {
1203 bitmap->Clear(0xFFFFFFFF);
1207 int dest_width = pixel_width;
1209 if (anti_alias == FT_RENDER_MODE_LCD) {
1210 bgra = ArgbToBGRAStruct(fill_color);
1213 for (
const TextGlyphPos& glyph : glyphs) {
1214 if (!glyph.m_pGlyph)
1217 std::optional<CFX_Point> point = glyph.GetOrigin({pixel_left, pixel_top});
1218 if (!point.has_value())
1221 const RetainPtr<CFX_DIBitmap>& pGlyph = glyph.m_pGlyph->GetBitmap();
1222 int ncols = pGlyph->GetWidth();
1223 int nrows = pGlyph->GetHeight();
1224 if (anti_alias == FT_RENDER_MODE_NORMAL) {
1225 if (!bitmap->CompositeMask(point.value().x, point.value().y, ncols, nrows,
1226 pGlyph, fill_color, 0, 0, BlendMode::kNormal,
1233 int x_subpixel =
static_cast<
int>(glyph.m_fDeviceOrigin.x * 3) % 3;
1234 int start_col = std::max(point->x, 0);
1235 FX_SAFE_INT32 end_col_safe = point->x;
1236 end_col_safe += ncols;
1237 if (!end_col_safe.IsValid())
1240 int end_col = std::min<
int>(end_col_safe.ValueOrDie(), dest_width);
1241 if (start_col >= end_col)
1244 DrawNormalTextHelper(bitmap, pGlyph, nrows, point->x, point->y, start_col,
1245 end_col, normalize, x_subpixel, bgra);
1248 if (bitmap->IsMaskFormat()) {
1262 uint32_t fill_color,
1266 for (
const auto& charpos : pCharPos) {
1267 const CFX_Path* pPath =
1268 pFont->LoadGlyphPath(charpos.m_GlyphIndex, charpos.m_FontCharWidth);
1272 CFX_Matrix matrix(font_size, 0, 0, font_size, charpos.m_Origin.x,
1273 charpos.m_Origin.y);
1274 matrix = charpos.GetEffectiveMatrix(matrix);
1275 matrix.Concat(mtText2User);
1277 CFX_Path transformed_path(*pPath);
1278 transformed_path.Transform(matrix);
1279 if (fill_color || stroke_color) {
1280 CFX_FillRenderOptions options(fill_options);
1282 options.fill_type = CFX_FillRenderOptions::FillType::kWinding;
1284 options.text_mode =
true;
1285 if (!DrawPath(transformed_path, pUser2Device, pGraphState, fill_color,
1286 stroke_color, options)) {
1290 if (pClippingPath) {
1291 pClippingPath->Append(transformed_path, pUser2Device);
1307 const std::vector<CFX_PointF>& points,
1312 for (size_t i = 1; i < points.size(); ++i)
1351 int32_t nTransparency) {
1357 int32_t nTransparency,
1360 constexpr float kBorder = 0.5f;
1361 constexpr float kSegmentWidth = 1.0f;
1362 constexpr float kLineWidth = 1.5f;
1364 float fStepGray = (nEndGray - nStartGray) / rect
.Height();
1368 for (
float fy = rect
.bottom + kBorder; fy <= rect
.top - kBorder;
1369 fy += kSegmentWidth) {
1372 int nGray = nStartGray +
static_cast<
int>(fStepGray * (fy - rect
.bottom));
1385 int32_t nTransparency) {
1389 const float fLeft = rect
.left;
1390 const float fRight = rect
.right;
1391 const float fTop = rect
.top;
1392 const float fBottom = rect
.bottom;
1393 const float fHalfWidth = fWidth / 2.0f;
1407 gsd.m_DashArray = {3.0f, 3.0f};
1412 path
.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth)
,
1414 path
.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fTop - fHalfWidth)
,
1416 path
.AppendPoint(CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth)
,
1418 path
.AppendPoint(CFX_PointF(fRight - fHalfWidth, fBottom + fHalfWidth)
,
1420 path
.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth)
,
1433 CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth)
,
1436 CFX_PointF(fLeft + fHalfWidth, fTop - fHalfWidth)
,
1439 CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth)
,
1441 path_left_top
.AppendPoint(CFX_PointF(fRight - fWidth, fTop - fWidth)
,
1443 path_left_top
.AppendPoint(CFX_PointF(fLeft + fWidth, fTop - fWidth)
,
1445 path_left_top
.AppendPoint(CFX_PointF(fLeft + fWidth, fBottom + fWidth)
,
1448 CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth)
,
1456 CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth)
,
1459 CFX_PointF(fRight - fHalfWidth, fBottom + fHalfWidth)
,
1462 CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth)
,
1465 CFX_PointF(fLeft + fWidth, fBottom + fWidth)
,
1468 CFX_PointF(fRight - fWidth, fBottom + fWidth)
,
1470 path_right_bottom
.AppendPoint(CFX_PointF(fRight - fWidth, fTop - fWidth)
,
1473 CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth)
,
1482 fRight - fHalfWidth
, fTop - fHalfWidth
);
1504 return m_pDeviceDriver->MultiplyAlpha(alpha);
1508 return m_pDeviceDriver->MultiplyAlphaMask(std::move(mask));
1513 m_pDevice->SaveState();
1517 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_PointF Transform(const CFX_PointF &point) const
void Translate(int32_t x, int32_t y)
constexpr CFX_Matrix(float a1, float b1, float c1, float d1, float e1, float f1)
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
RetainPtr< const CFX_DIBitmap > GetBackDrop() const
void SetBaseClip(const FX_RECT &rect)
bool FillRect(const FX_RECT &rect, uint32_t color)
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(RetainPtr< const CFX_DIBitmap > mask)
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 SetDIBits(RetainPtr< const CFX_DIBBase > bitmap, int left, int top)
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 SetDIBitsWithBlend(RetainPtr< const CFX_DIBBase > bitmap, int left, int top, BlendMode blend_mode)
bool SetBitMask(RetainPtr< const CFX_DIBBase > bitmap, int left, int top, uint32_t argb)
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)
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)
RenderDeviceDriverIface::StartResult StartDIBits(RetainPtr< const CFX_DIBBase > bitmap, float alpha, uint32_t argb, const CFX_Matrix &matrix, const FXDIB_ResampleOptions &options)
void DrawStrokeLine(const CFX_Matrix *pUser2Device, const CFX_PointF &ptMoveTo, const CFX_PointF &ptLineTo, const FX_COLORREF &color, float fWidth)
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)
RenderDeviceDriverIface::StartResult StartDIBitsWithBlend(RetainPtr< const CFX_DIBBase > bitmap, float alpha, uint32_t argb, const CFX_Matrix &matrix, const FXDIB_ResampleOptions &options, BlendMode blend_mode)
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 CreateCompatibleBitmap(const RetainPtr< CFX_DIBitmap > &pDIB, int width, int height) const
DeviceType GetDeviceType() const
bool ContinueDIBits(CFX_AggImageRenderer *handle, PauseIndicatorIface *pPause)
void DrawFillRect(const CFX_Matrix *pUser2Device, const CFX_FloatRect &rect, const CFX_Color &color, int32_t nTransparency)
bool GetDIBits(RetainPtr< CFX_DIBitmap > bitmap, int left, int top) const
CFX_Matrix GetEffectiveMatrix(const CFX_Matrix &matrix) const
CFX_PTemplate< float > CFX_PointF
constexpr FX_ARGB ArgbEncode(uint32_t a, uint32_t r, uint32_t g, uint32_t b)
#define FXDIB_ALPHA_MERGE(backdrop, source, source_alpha)
pdfium::CheckedNumeric< int32_t > FX_SAFE_INT32
#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)