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/fpdfapi/render/cpdf_textrenderer.h"
8 
9 #include <algorithm>
10 #include <vector>
11 
12 #include "core/fpdfapi/font/cpdf_font.h"
13 #include "core/fpdfapi/render/charposlist.h"
14 #include "core/fpdfapi/render/cpdf_renderoptions.h"
15 #include "core/fxge/cfx_graphstatedata.h"
16 #include "core/fxge/cfx_pathdata.h"
17 #include "core/fxge/cfx_renderdevice.h"
18 #include "core/fxge/cfx_textrenderoptions.h"
19 #include "core/fxge/fx_font.h"
20 #include "core/fxge/text_char_pos.h"
21 
22 namespace {
23 
GetFont(CPDF_Font * pFont,int32_t position)24 CFX_Font* GetFont(CPDF_Font* pFont, int32_t position) {
25   return position == -1 ? pFont->GetFont() : pFont->GetFontFallback(position);
26 }
27 
GetTextRenderOptionsHelper(const CPDF_Font * pFont,const CPDF_RenderOptions & options)28 CFX_TextRenderOptions GetTextRenderOptionsHelper(
29     const CPDF_Font* pFont,
30     const CPDF_RenderOptions& options) {
31   CFX_TextRenderOptions text_options;
32 
33   if (pFont->IsCIDFont())
34     text_options.font_is_cid = true;
35 
36   if (options.GetOptions().bNoTextSmooth)
37     text_options.aliasing_type = CFX_TextRenderOptions::kAliasing;
38   else if (options.GetOptions().bClearType)
39     text_options.aliasing_type = CFX_TextRenderOptions::kLcd;
40 
41   if (options.GetOptions().bNoNativeText)
42     text_options.native_text = false;
43 
44   return text_options;
45 }
46 
47 }  // namespace
48 
49 // static
DrawTextPath(CFX_RenderDevice * pDevice,pdfium::span<const uint32_t> char_codes,pdfium::span<const float> char_pos,CPDF_Font * pFont,float font_size,const CFX_Matrix & mtText2User,const CFX_Matrix * pUser2Device,const CFX_GraphStateData * pGraphState,FX_ARGB fill_argb,FX_ARGB stroke_argb,CFX_PathData * pClippingPath,const CFX_FillRenderOptions & fill_options)50 bool CPDF_TextRenderer::DrawTextPath(
51     CFX_RenderDevice* pDevice,
52     pdfium::span<const uint32_t> char_codes,
53     pdfium::span<const float> char_pos,
54     CPDF_Font* pFont,
55     float font_size,
56     const CFX_Matrix& mtText2User,
57     const CFX_Matrix* pUser2Device,
58     const CFX_GraphStateData* pGraphState,
59     FX_ARGB fill_argb,
60     FX_ARGB stroke_argb,
61     CFX_PathData* pClippingPath,
62     const CFX_FillRenderOptions& fill_options) {
63   std::vector<TextCharPos> pos =
64       GetCharPosList(char_codes, char_pos, pFont, font_size);
65   if (pos.empty())
66     return true;
67 
68   bool bDraw = true;
69   int32_t fontPosition = pos[0].m_FallbackFontPosition;
70   size_t startIndex = 0;
71   for (size_t i = 0; i < pos.size(); ++i) {
72     int32_t curFontPosition = pos[i].m_FallbackFontPosition;
73     if (fontPosition == curFontPosition)
74       continue;
75 
76     CFX_Font* font = GetFont(pFont, fontPosition);
77     if (!pDevice->DrawTextPath(i - startIndex, &pos[startIndex], font,
78                                font_size, mtText2User, pUser2Device,
79                                pGraphState, fill_argb, stroke_argb,
80                                pClippingPath, fill_options)) {
81       bDraw = false;
82     }
83     fontPosition = curFontPosition;
84     startIndex = i;
85   }
86   CFX_Font* font = GetFont(pFont, fontPosition);
87   if (!pDevice->DrawTextPath(pos.size() - startIndex, &pos[startIndex], font,
88                              font_size, mtText2User, pUser2Device, pGraphState,
89                              fill_argb, stroke_argb, pClippingPath,
90                              fill_options)) {
91     bDraw = false;
92   }
93   return bDraw;
94 }
95 
96 // static
DrawTextString(CFX_RenderDevice * pDevice,float origin_x,float origin_y,CPDF_Font * pFont,float font_size,const CFX_Matrix & matrix,const ByteString & str,FX_ARGB fill_argb,const CPDF_RenderOptions & options)97 void CPDF_TextRenderer::DrawTextString(CFX_RenderDevice* pDevice,
98                                        float origin_x,
99                                        float origin_y,
100                                        CPDF_Font* pFont,
101                                        float font_size,
102                                        const CFX_Matrix& matrix,
103                                        const ByteString& str,
104                                        FX_ARGB fill_argb,
105                                        const CPDF_RenderOptions& options) {
106   if (pFont->IsType3Font())
107     return;
108 
109   int nChars = pFont->CountChar(str.AsStringView());
110   if (nChars <= 0)
111     return;
112 
113   size_t offset = 0;
114   std::vector<uint32_t> codes;
115   std::vector<float> positions;
116   codes.resize(nChars);
117   positions.resize(nChars - 1);
118   float cur_pos = 0;
119   for (int i = 0; i < nChars; i++) {
120     codes[i] = pFont->GetNextChar(str.AsStringView(), &offset);
121     if (i)
122       positions[i - 1] = cur_pos;
123     cur_pos += pFont->GetCharWidthF(codes[i]) * font_size / 1000;
124   }
125   CFX_Matrix new_matrix = matrix;
126   new_matrix.e = origin_x;
127   new_matrix.f = origin_y;
128   DrawNormalText(pDevice, codes, positions, pFont, font_size, new_matrix,
129                  fill_argb, options);
130 }
131 
132 // static
DrawNormalText(CFX_RenderDevice * pDevice,pdfium::span<const uint32_t> char_codes,pdfium::span<const float> char_pos,CPDF_Font * pFont,float font_size,const CFX_Matrix & mtText2Device,FX_ARGB fill_argb,const CPDF_RenderOptions & options)133 bool CPDF_TextRenderer::DrawNormalText(CFX_RenderDevice* pDevice,
134                                        pdfium::span<const uint32_t> char_codes,
135                                        pdfium::span<const float> char_pos,
136                                        CPDF_Font* pFont,
137                                        float font_size,
138                                        const CFX_Matrix& mtText2Device,
139                                        FX_ARGB fill_argb,
140                                        const CPDF_RenderOptions& options) {
141   std::vector<TextCharPos> pos =
142       GetCharPosList(char_codes, char_pos, pFont, font_size);
143   if (pos.empty())
144     return true;
145 
146   CFX_TextRenderOptions text_options =
147       GetTextRenderOptionsHelper(pFont, options);
148   bool bDraw = true;
149   int32_t fontPosition = pos[0].m_FallbackFontPosition;
150   size_t startIndex = 0;
151   for (size_t i = 0; i < pos.size(); ++i) {
152     int32_t curFontPosition = pos[i].m_FallbackFontPosition;
153     if (fontPosition == curFontPosition)
154       continue;
155 
156     CFX_Font* font = GetFont(pFont, fontPosition);
157     if (!pDevice->DrawNormalText(i - startIndex, &pos[startIndex], font,
158                                  font_size, mtText2Device, fill_argb,
159                                  text_options)) {
160       bDraw = false;
161     }
162     fontPosition = curFontPosition;
163     startIndex = i;
164   }
165   CFX_Font* font = GetFont(pFont, fontPosition);
166   if (!pDevice->DrawNormalText(pos.size() - startIndex, &pos[startIndex], font,
167                                font_size, mtText2Device, fill_argb,
168                                text_options)) {
169     bDraw = false;
170   }
171   return bDraw;
172 }
173