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 
11 #include "core/fpdfapi/font/cpdf_font.h"
12 #include "core/fpdfapi/render/cpdf_charposlist.h"
13 #include "core/fpdfapi/render/cpdf_renderoptions.h"
14 #include "core/fxge/cfx_graphstatedata.h"
15 #include "core/fxge/cfx_pathdata.h"
16 #include "core/fxge/cfx_renderdevice.h"
17 
18 namespace {
19 
GetFont(CPDF_Font * pFont,int32_t position)20 CFX_Font* GetFont(CPDF_Font* pFont, int32_t position) {
21   return position == -1 ? pFont->GetFont() : pFont->GetFontFallback(position);
22 }
23 
24 }  // namespace
25 
26 // static
DrawTextPath(CFX_RenderDevice * pDevice,const std::vector<uint32_t> & charCodes,const std::vector<float> & charPos,CPDF_Font * pFont,float font_size,const CFX_Matrix * pText2User,const CFX_Matrix * pUser2Device,const CFX_GraphStateData * pGraphState,FX_ARGB fill_argb,FX_ARGB stroke_argb,CFX_PathData * pClippingPath,int nFlag)27 bool CPDF_TextRenderer::DrawTextPath(CFX_RenderDevice* pDevice,
28                                      const std::vector<uint32_t>& charCodes,
29                                      const std::vector<float>& charPos,
30                                      CPDF_Font* pFont,
31                                      float font_size,
32                                      const CFX_Matrix* pText2User,
33                                      const CFX_Matrix* pUser2Device,
34                                      const CFX_GraphStateData* pGraphState,
35                                      FX_ARGB fill_argb,
36                                      FX_ARGB stroke_argb,
37                                      CFX_PathData* pClippingPath,
38                                      int nFlag) {
39   CPDF_CharPosList CharPosList;
40   CharPosList.Load(charCodes, charPos, pFont, font_size);
41   if (CharPosList.m_nChars == 0)
42     return true;
43 
44   bool bDraw = true;
45   int32_t fontPosition = CharPosList.m_pCharPos[0].m_FallbackFontPosition;
46   uint32_t startIndex = 0;
47   for (uint32_t i = 0; i < CharPosList.m_nChars; i++) {
48     int32_t curFontPosition = CharPosList.m_pCharPos[i].m_FallbackFontPosition;
49     if (fontPosition == curFontPosition)
50       continue;
51 
52     CFX_Font* font = GetFont(pFont, fontPosition);
53     if (!pDevice->DrawTextPath(i - startIndex,
54                                CharPosList.m_pCharPos + startIndex, font,
55                                font_size, pText2User, pUser2Device, pGraphState,
56                                fill_argb, stroke_argb, pClippingPath, nFlag)) {
57       bDraw = false;
58     }
59     fontPosition = curFontPosition;
60     startIndex = i;
61   }
62   CFX_Font* font = GetFont(pFont, fontPosition);
63   if (!pDevice->DrawTextPath(CharPosList.m_nChars - startIndex,
64                              CharPosList.m_pCharPos + startIndex, font,
65                              font_size, pText2User, pUser2Device, pGraphState,
66                              fill_argb, stroke_argb, pClippingPath, nFlag)) {
67     bDraw = false;
68   }
69   return bDraw;
70 }
71 
72 // static
DrawTextString(CFX_RenderDevice * pDevice,float origin_x,float origin_y,CPDF_Font * pFont,float font_size,const CFX_Matrix * pMatrix,const ByteString & str,FX_ARGB fill_argb,const CFX_GraphStateData * pGraphState,const CPDF_RenderOptions * pOptions)73 void CPDF_TextRenderer::DrawTextString(CFX_RenderDevice* pDevice,
74                                        float origin_x,
75                                        float origin_y,
76                                        CPDF_Font* pFont,
77                                        float font_size,
78                                        const CFX_Matrix* pMatrix,
79                                        const ByteString& str,
80                                        FX_ARGB fill_argb,
81                                        const CFX_GraphStateData* pGraphState,
82                                        const CPDF_RenderOptions* pOptions) {
83   if (pFont->IsType3Font())
84     return;
85 
86   int nChars = pFont->CountChar(str.c_str(), str.GetLength());
87   if (nChars <= 0)
88     return;
89 
90   int offset = 0;
91   std::vector<uint32_t> codes;
92   std::vector<float> positions;
93   codes.resize(nChars);
94   positions.resize(nChars - 1);
95   float cur_pos = 0;
96   for (int i = 0; i < nChars; i++) {
97     codes[i] = pFont->GetNextChar(str.c_str(), str.GetLength(), offset);
98     if (i)
99       positions[i - 1] = cur_pos;
100     cur_pos += pFont->GetCharWidthF(codes[i]) * font_size / 1000;
101   }
102   CFX_Matrix matrix;
103   if (pMatrix)
104     matrix = *pMatrix;
105 
106   matrix.e = origin_x;
107   matrix.f = origin_y;
108 
109   DrawNormalText(pDevice, codes, positions, pFont, font_size, &matrix,
110                  fill_argb, pOptions);
111 }
112 
113 // static
DrawNormalText(CFX_RenderDevice * pDevice,const std::vector<uint32_t> & charCodes,const std::vector<float> & charPos,CPDF_Font * pFont,float font_size,const CFX_Matrix * pText2Device,FX_ARGB fill_argb,const CPDF_RenderOptions * pOptions)114 bool CPDF_TextRenderer::DrawNormalText(CFX_RenderDevice* pDevice,
115                                        const std::vector<uint32_t>& charCodes,
116                                        const std::vector<float>& charPos,
117                                        CPDF_Font* pFont,
118                                        float font_size,
119                                        const CFX_Matrix* pText2Device,
120                                        FX_ARGB fill_argb,
121                                        const CPDF_RenderOptions* pOptions) {
122   CPDF_CharPosList CharPosList;
123   CharPosList.Load(charCodes, charPos, pFont, font_size);
124   if (CharPosList.m_nChars == 0)
125     return true;
126   int FXGE_flags = 0;
127   if (pOptions) {
128     if (pOptions->HasFlag(RENDER_CLEARTYPE)) {
129       FXGE_flags |= FXTEXT_CLEARTYPE;
130       if (pOptions->HasFlag(RENDER_BGR_STRIPE))
131         FXGE_flags |= FXTEXT_BGR_STRIPE;
132     }
133     if (pOptions->HasFlag(RENDER_NOTEXTSMOOTH))
134       FXGE_flags |= FXTEXT_NOSMOOTH;
135     if (pOptions->HasFlag(RENDER_PRINTGRAPHICTEXT))
136       FXGE_flags |= FXTEXT_PRINTGRAPHICTEXT;
137     if (pOptions->HasFlag(RENDER_NO_NATIVETEXT))
138       FXGE_flags |= FXTEXT_NO_NATIVETEXT;
139     if (pOptions->HasFlag(RENDER_PRINTIMAGETEXT))
140       FXGE_flags |= FXTEXT_PRINTIMAGETEXT;
141   } else {
142     FXGE_flags = FXTEXT_CLEARTYPE;
143   }
144   if (pFont->IsCIDFont())
145     FXGE_flags |= FXFONT_CIDFONT;
146   bool bDraw = true;
147   int32_t fontPosition = CharPosList.m_pCharPos[0].m_FallbackFontPosition;
148   uint32_t startIndex = 0;
149   for (uint32_t i = 0; i < CharPosList.m_nChars; i++) {
150     int32_t curFontPosition = CharPosList.m_pCharPos[i].m_FallbackFontPosition;
151     if (fontPosition == curFontPosition)
152       continue;
153 
154     CFX_Font* font = GetFont(pFont, fontPosition);
155     if (!pDevice->DrawNormalText(
156             i - startIndex, CharPosList.m_pCharPos + startIndex, font,
157             font_size, pText2Device, fill_argb, FXGE_flags)) {
158       bDraw = false;
159     }
160     fontPosition = curFontPosition;
161     startIndex = i;
162   }
163   CFX_Font* font = GetFont(pFont, fontPosition);
164   if (!pDevice->DrawNormalText(CharPosList.m_nChars - startIndex,
165                                CharPosList.m_pCharPos + startIndex, font,
166                                font_size, pText2Device, fill_argb,
167                                FXGE_flags)) {
168     bDraw = false;
169   }
170   return bDraw;
171 }
172