OLD | NEW |
| (Empty) |
1 // Copyright 2014 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/fpdf_render/render_int.h" | |
8 | |
9 #include <vector> | |
10 | |
11 #include "core/fpdfapi/font/cpdf_cidfont.h" | |
12 #include "core/fpdfapi/font/cpdf_font.h" | |
13 #include "core/fpdfapi/font/cpdf_type3char.h" | |
14 #include "core/fpdfapi/font/cpdf_type3font.h" | |
15 #include "core/fpdfapi/fpdf_render/cpdf_renderoptions.h" | |
16 #include "core/fpdfapi/fpdf_render/cpdf_textrenderer.h" | |
17 #include "core/fpdfapi/fpdf_render/cpdf_type3cache.h" | |
18 #include "core/fpdfapi/page/cpdf_form.h" | |
19 #include "core/fpdfapi/page/cpdf_imageobject.h" | |
20 #include "core/fpdfapi/page/cpdf_pageobject.h" | |
21 #include "core/fpdfapi/page/cpdf_pathobject.h" | |
22 #include "core/fpdfapi/page/cpdf_textobject.h" | |
23 #include "core/fpdfapi/page/pageint.h" | |
24 #include "core/fpdfapi/parser/cpdf_dictionary.h" | |
25 #include "core/fpdfapi/parser/cpdf_document.h" | |
26 #include "core/fxge/cfx_facecache.h" | |
27 #include "core/fxge/cfx_fxgedevice.h" | |
28 #include "core/fxge/cfx_gemodule.h" | |
29 #include "core/fxge/cfx_graphstatedata.h" | |
30 #include "core/fxge/cfx_pathdata.h" | |
31 #include "core/fxge/cfx_renderdevice.h" | |
32 | |
33 FX_BOOL CPDF_RenderStatus::ProcessText(CPDF_TextObject* textobj, | |
34 const CFX_Matrix* pObj2Device, | |
35 CFX_PathData* pClippingPath) { | |
36 if (textobj->m_nChars == 0) | |
37 return TRUE; | |
38 | |
39 const TextRenderingMode text_render_mode = textobj->m_TextState.GetTextMode(); | |
40 if (text_render_mode == TextRenderingMode::MODE_INVISIBLE) | |
41 return TRUE; | |
42 | |
43 CPDF_Font* pFont = textobj->m_TextState.GetFont(); | |
44 if (pFont->IsType3Font()) | |
45 return ProcessType3Text(textobj, pObj2Device); | |
46 | |
47 bool bFill = false; | |
48 bool bStroke = false; | |
49 bool bClip = false; | |
50 if (pClippingPath) { | |
51 bClip = true; | |
52 } else { | |
53 switch (text_render_mode) { | |
54 case TextRenderingMode::MODE_FILL: | |
55 case TextRenderingMode::MODE_FILL_CLIP: | |
56 bFill = true; | |
57 break; | |
58 case TextRenderingMode::MODE_STROKE: | |
59 case TextRenderingMode::MODE_STROKE_CLIP: | |
60 if (pFont->GetFace() || | |
61 (pFont->GetSubstFont()->m_SubstFlags & FXFONT_SUBST_GLYPHPATH)) { | |
62 bStroke = true; | |
63 } else { | |
64 bFill = true; | |
65 } | |
66 break; | |
67 case TextRenderingMode::MODE_FILL_STROKE: | |
68 case TextRenderingMode::MODE_FILL_STROKE_CLIP: | |
69 bFill = true; | |
70 if (pFont->GetFace() || | |
71 (pFont->GetSubstFont()->m_SubstFlags & FXFONT_SUBST_GLYPHPATH)) { | |
72 bStroke = true; | |
73 } | |
74 break; | |
75 case TextRenderingMode::MODE_INVISIBLE: | |
76 // Already handled above, but the compiler is not smart enough to | |
77 // realize it. Fall through. | |
78 ASSERT(false); | |
79 case TextRenderingMode::MODE_CLIP: | |
80 return TRUE; | |
81 } | |
82 } | |
83 FX_ARGB stroke_argb = 0; | |
84 FX_ARGB fill_argb = 0; | |
85 bool bPattern = false; | |
86 if (bStroke) { | |
87 if (textobj->m_ColorState.GetStrokeColor()->IsPattern()) { | |
88 bPattern = true; | |
89 } else { | |
90 stroke_argb = GetStrokeArgb(textobj); | |
91 } | |
92 } | |
93 if (bFill) { | |
94 if (textobj->m_ColorState.GetFillColor()->IsPattern()) { | |
95 bPattern = true; | |
96 } else { | |
97 fill_argb = GetFillArgb(textobj); | |
98 } | |
99 } | |
100 CFX_Matrix text_matrix; | |
101 textobj->GetTextMatrix(&text_matrix); | |
102 if (!IsAvailableMatrix(text_matrix)) | |
103 return TRUE; | |
104 | |
105 FX_FLOAT font_size = textobj->m_TextState.GetFontSize(); | |
106 if (bPattern) { | |
107 DrawTextPathWithPattern(textobj, pObj2Device, pFont, font_size, | |
108 &text_matrix, bFill, bStroke); | |
109 return TRUE; | |
110 } | |
111 if (bClip || bStroke) { | |
112 const CFX_Matrix* pDeviceMatrix = pObj2Device; | |
113 CFX_Matrix device_matrix; | |
114 if (bStroke) { | |
115 const FX_FLOAT* pCTM = textobj->m_TextState.GetCTM(); | |
116 if (pCTM[0] != 1.0f || pCTM[3] != 1.0f) { | |
117 CFX_Matrix ctm(pCTM[0], pCTM[1], pCTM[2], pCTM[3], 0, 0); | |
118 text_matrix.ConcatInverse(ctm); | |
119 device_matrix = ctm; | |
120 device_matrix.Concat(*pObj2Device); | |
121 pDeviceMatrix = &device_matrix; | |
122 } | |
123 } | |
124 int flag = 0; | |
125 if (bStroke && bFill) { | |
126 flag |= FX_FILL_STROKE; | |
127 flag |= FX_STROKE_TEXT_MODE; | |
128 } | |
129 if (textobj->m_GeneralState.GetStrokeAdjust()) | |
130 flag |= FX_STROKE_ADJUST; | |
131 if (m_Options.m_Flags & RENDER_NOTEXTSMOOTH) | |
132 flag |= FXFILL_NOPATHSMOOTH; | |
133 return CPDF_TextRenderer::DrawTextPath( | |
134 m_pDevice, textobj->m_nChars, textobj->m_pCharCodes, | |
135 textobj->m_pCharPos, pFont, font_size, &text_matrix, pDeviceMatrix, | |
136 textobj->m_GraphState.GetObject(), fill_argb, stroke_argb, | |
137 pClippingPath, flag); | |
138 } | |
139 text_matrix.Concat(*pObj2Device); | |
140 return CPDF_TextRenderer::DrawNormalText( | |
141 m_pDevice, textobj->m_nChars, textobj->m_pCharCodes, textobj->m_pCharPos, | |
142 pFont, font_size, &text_matrix, fill_argb, &m_Options); | |
143 } | |
144 | |
145 CPDF_Type3Cache* CPDF_RenderStatus::GetCachedType3(CPDF_Type3Font* pFont) { | |
146 if (!pFont->m_pDocument) { | |
147 return nullptr; | |
148 } | |
149 pFont->m_pDocument->GetPageData()->GetFont(pFont->GetFontDict(), FALSE); | |
150 return pFont->m_pDocument->GetRenderData()->GetCachedType3(pFont); | |
151 } | |
152 static void ReleaseCachedType3(CPDF_Type3Font* pFont) { | |
153 if (!pFont->m_pDocument) { | |
154 return; | |
155 } | |
156 pFont->m_pDocument->GetRenderData()->ReleaseCachedType3(pFont); | |
157 pFont->m_pDocument->GetPageData()->ReleaseFont(pFont->GetFontDict()); | |
158 } | |
159 | |
160 class CPDF_RefType3Cache { | |
161 public: | |
162 explicit CPDF_RefType3Cache(CPDF_Type3Font* pType3Font) | |
163 : m_dwCount(0), m_pType3Font(pType3Font) {} | |
164 ~CPDF_RefType3Cache() { | |
165 while (m_dwCount--) { | |
166 ReleaseCachedType3(m_pType3Font); | |
167 } | |
168 } | |
169 uint32_t m_dwCount; | |
170 CPDF_Type3Font* const m_pType3Font; | |
171 }; | |
172 | |
173 // TODO(npm): Font fallback for type 3 fonts? (Completely separate code!!) | |
174 FX_BOOL CPDF_RenderStatus::ProcessType3Text(CPDF_TextObject* textobj, | |
175 const CFX_Matrix* pObj2Device) { | |
176 CPDF_Type3Font* pType3Font = textobj->m_TextState.GetFont()->AsType3Font(); | |
177 for (int i = 0; i < m_Type3FontCache.GetSize(); ++i) { | |
178 if (m_Type3FontCache.GetAt(i) == pType3Font) | |
179 return TRUE; | |
180 } | |
181 | |
182 CFX_Matrix dCTM = m_pDevice->GetCTM(); | |
183 FX_FLOAT sa = FXSYS_fabs(dCTM.a); | |
184 FX_FLOAT sd = FXSYS_fabs(dCTM.d); | |
185 CFX_Matrix text_matrix; | |
186 textobj->GetTextMatrix(&text_matrix); | |
187 CFX_Matrix char_matrix = pType3Font->GetFontMatrix(); | |
188 FX_FLOAT font_size = textobj->m_TextState.GetFontSize(); | |
189 char_matrix.Scale(font_size, font_size); | |
190 FX_ARGB fill_argb = GetFillArgb(textobj, TRUE); | |
191 int fill_alpha = FXARGB_A(fill_argb); | |
192 int device_class = m_pDevice->GetDeviceClass(); | |
193 std::vector<FXTEXT_GLYPHPOS> glyphs; | |
194 if (device_class == FXDC_DISPLAY) | |
195 glyphs.resize(textobj->m_nChars); | |
196 else if (fill_alpha < 255) | |
197 return FALSE; | |
198 | |
199 CPDF_RefType3Cache refTypeCache(pType3Font); | |
200 uint32_t* pChars = textobj->m_pCharCodes; | |
201 if (textobj->m_nChars == 1) | |
202 pChars = (uint32_t*)(&textobj->m_pCharCodes); | |
203 | |
204 for (int iChar = 0; iChar < textobj->m_nChars; iChar++) { | |
205 uint32_t charcode = pChars[iChar]; | |
206 if (charcode == (uint32_t)-1) | |
207 continue; | |
208 | |
209 CPDF_Type3Char* pType3Char = pType3Font->LoadChar(charcode); | |
210 if (!pType3Char) | |
211 continue; | |
212 | |
213 CFX_Matrix matrix = char_matrix; | |
214 matrix.e += iChar ? textobj->m_pCharPos[iChar - 1] : 0; | |
215 matrix.Concat(text_matrix); | |
216 matrix.Concat(*pObj2Device); | |
217 if (!pType3Char->LoadBitmap(m_pContext)) { | |
218 if (!glyphs.empty()) { | |
219 for (int i = 0; i < iChar; i++) { | |
220 const FXTEXT_GLYPHPOS& glyph = glyphs[i]; | |
221 if (!glyph.m_pGlyph) | |
222 continue; | |
223 | |
224 m_pDevice->SetBitMask(&glyph.m_pGlyph->m_Bitmap, | |
225 glyph.m_OriginX + glyph.m_pGlyph->m_Left, | |
226 glyph.m_OriginY - glyph.m_pGlyph->m_Top, | |
227 fill_argb); | |
228 } | |
229 glyphs.clear(); | |
230 } | |
231 CPDF_GraphicStates* pStates = CloneObjStates(textobj, FALSE); | |
232 CPDF_RenderOptions Options = m_Options; | |
233 Options.m_Flags |= RENDER_FORCE_HALFTONE | RENDER_RECT_AA; | |
234 Options.m_Flags &= ~RENDER_FORCE_DOWNSAMPLE; | |
235 CPDF_Dictionary* pFormResource = nullptr; | |
236 if (pType3Char->m_pForm && pType3Char->m_pForm->m_pFormDict) { | |
237 pFormResource = | |
238 pType3Char->m_pForm->m_pFormDict->GetDictFor("Resources"); | |
239 } | |
240 if (fill_alpha == 255) { | |
241 CPDF_RenderStatus status; | |
242 status.Initialize(m_pContext, m_pDevice, nullptr, nullptr, this, | |
243 pStates, &Options, | |
244 pType3Char->m_pForm->m_Transparency, m_bDropObjects, | |
245 pFormResource, FALSE, pType3Char, fill_argb); | |
246 status.m_Type3FontCache.Append(m_Type3FontCache); | |
247 status.m_Type3FontCache.Add(pType3Font); | |
248 m_pDevice->SaveState(); | |
249 status.RenderObjectList(pType3Char->m_pForm.get(), &matrix); | |
250 m_pDevice->RestoreState(false); | |
251 } else { | |
252 CFX_FloatRect rect_f = pType3Char->m_pForm->CalcBoundingBox(); | |
253 rect_f.Transform(&matrix); | |
254 FX_RECT rect = rect_f.GetOuterRect(); | |
255 CFX_FxgeDevice bitmap_device; | |
256 if (!bitmap_device.Create((int)(rect.Width() * sa), | |
257 (int)(rect.Height() * sd), FXDIB_Argb, | |
258 nullptr)) { | |
259 return TRUE; | |
260 } | |
261 bitmap_device.GetBitmap()->Clear(0); | |
262 CPDF_RenderStatus status; | |
263 status.Initialize(m_pContext, &bitmap_device, nullptr, nullptr, this, | |
264 pStates, &Options, | |
265 pType3Char->m_pForm->m_Transparency, m_bDropObjects, | |
266 pFormResource, FALSE, pType3Char, fill_argb); | |
267 status.m_Type3FontCache.Append(m_Type3FontCache); | |
268 status.m_Type3FontCache.Add(pType3Font); | |
269 matrix.TranslateI(-rect.left, -rect.top); | |
270 matrix.Scale(sa, sd); | |
271 status.RenderObjectList(pType3Char->m_pForm.get(), &matrix); | |
272 m_pDevice->SetDIBits(bitmap_device.GetBitmap(), rect.left, rect.top); | |
273 } | |
274 delete pStates; | |
275 } else if (pType3Char->m_pBitmap) { | |
276 if (device_class == FXDC_DISPLAY) { | |
277 CPDF_Type3Cache* pCache = GetCachedType3(pType3Font); | |
278 refTypeCache.m_dwCount++; | |
279 CFX_GlyphBitmap* pBitmap = pCache->LoadGlyph(charcode, &matrix, sa, sd); | |
280 if (!pBitmap) | |
281 continue; | |
282 | |
283 int origin_x = FXSYS_round(matrix.e); | |
284 int origin_y = FXSYS_round(matrix.f); | |
285 if (glyphs.empty()) { | |
286 m_pDevice->SetBitMask(&pBitmap->m_Bitmap, origin_x + pBitmap->m_Left, | |
287 origin_y - pBitmap->m_Top, fill_argb); | |
288 } else { | |
289 glyphs[iChar].m_pGlyph = pBitmap; | |
290 glyphs[iChar].m_OriginX = origin_x; | |
291 glyphs[iChar].m_OriginY = origin_y; | |
292 } | |
293 } else { | |
294 CFX_Matrix image_matrix = pType3Char->m_ImageMatrix; | |
295 image_matrix.Concat(matrix); | |
296 CPDF_ImageRenderer renderer; | |
297 if (renderer.Start(this, pType3Char->m_pBitmap.get(), fill_argb, 255, | |
298 &image_matrix, 0, FALSE)) { | |
299 renderer.Continue(nullptr); | |
300 } | |
301 if (!renderer.m_Result) | |
302 return FALSE; | |
303 } | |
304 } | |
305 } | |
306 | |
307 if (glyphs.empty()) | |
308 return TRUE; | |
309 | |
310 FX_RECT rect = FXGE_GetGlyphsBBox(glyphs, 0, sa, sd); | |
311 CFX_DIBitmap bitmap; | |
312 if (!bitmap.Create(static_cast<int>(rect.Width() * sa), | |
313 static_cast<int>(rect.Height() * sd), FXDIB_8bppMask)) { | |
314 return TRUE; | |
315 } | |
316 bitmap.Clear(0); | |
317 for (const FXTEXT_GLYPHPOS& glyph : glyphs) { | |
318 if (!glyph.m_pGlyph) | |
319 continue; | |
320 | |
321 bitmap.TransferBitmap( | |
322 static_cast<int>( | |
323 (glyph.m_OriginX + glyph.m_pGlyph->m_Left - rect.left) * sa), | |
324 static_cast<int>((glyph.m_OriginY - glyph.m_pGlyph->m_Top - rect.top) * | |
325 sd), | |
326 glyph.m_pGlyph->m_Bitmap.GetWidth(), | |
327 glyph.m_pGlyph->m_Bitmap.GetHeight(), &glyph.m_pGlyph->m_Bitmap, 0, 0); | |
328 } | |
329 m_pDevice->SetBitMask(&bitmap, rect.left, rect.top, fill_argb); | |
330 return TRUE; | |
331 } | |
332 | |
333 class CPDF_CharPosList { | |
334 public: | |
335 CPDF_CharPosList(); | |
336 ~CPDF_CharPosList(); | |
337 void Load(int nChars, | |
338 uint32_t* pCharCodes, | |
339 FX_FLOAT* pCharPos, | |
340 CPDF_Font* pFont, | |
341 FX_FLOAT font_size); | |
342 FXTEXT_CHARPOS* m_pCharPos; | |
343 uint32_t m_nChars; | |
344 }; | |
345 | |
346 CPDF_CharPosList::CPDF_CharPosList() { | |
347 m_pCharPos = nullptr; | |
348 } | |
349 | |
350 CPDF_CharPosList::~CPDF_CharPosList() { | |
351 FX_Free(m_pCharPos); | |
352 } | |
353 | |
354 void CPDF_CharPosList::Load(int nChars, | |
355 uint32_t* pCharCodes, | |
356 FX_FLOAT* pCharPos, | |
357 CPDF_Font* pFont, | |
358 FX_FLOAT FontSize) { | |
359 m_pCharPos = FX_Alloc(FXTEXT_CHARPOS, nChars); | |
360 m_nChars = 0; | |
361 CPDF_CIDFont* pCIDFont = pFont->AsCIDFont(); | |
362 FX_BOOL bVertWriting = pCIDFont && pCIDFont->IsVertWriting(); | |
363 for (int iChar = 0; iChar < nChars; iChar++) { | |
364 uint32_t CharCode = | |
365 nChars == 1 ? (uint32_t)(uintptr_t)pCharCodes : pCharCodes[iChar]; | |
366 if (CharCode == (uint32_t)-1) { | |
367 continue; | |
368 } | |
369 bool bVert = false; | |
370 FXTEXT_CHARPOS& charpos = m_pCharPos[m_nChars++]; | |
371 if (pCIDFont) { | |
372 charpos.m_bFontStyle = true; | |
373 } | |
374 charpos.m_GlyphIndex = pFont->GlyphFromCharCode(CharCode, &bVert); | |
375 if (charpos.m_GlyphIndex != static_cast<uint32_t>(-1)) { | |
376 charpos.m_FallbackFontPosition = -1; | |
377 } else { | |
378 charpos.m_FallbackFontPosition = | |
379 pFont->FallbackFontFromCharcode(CharCode); | |
380 charpos.m_GlyphIndex = pFont->FallbackGlyphFromCharcode( | |
381 charpos.m_FallbackFontPosition, CharCode); | |
382 } | |
383 // TODO(npm): Figure out how this affects m_ExtGID | |
384 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ | |
385 charpos.m_ExtGID = pFont->GlyphFromCharCodeExt(CharCode); | |
386 #endif | |
387 if (!pFont->IsEmbedded() && !pFont->IsCIDFont()) { | |
388 charpos.m_FontCharWidth = pFont->GetCharWidthF(CharCode); | |
389 } else { | |
390 charpos.m_FontCharWidth = 0; | |
391 } | |
392 charpos.m_OriginX = iChar ? pCharPos[iChar - 1] : 0; | |
393 charpos.m_OriginY = 0; | |
394 charpos.m_bGlyphAdjust = FALSE; | |
395 if (!pCIDFont) { | |
396 continue; | |
397 } | |
398 uint16_t CID = pCIDFont->CIDFromCharCode(CharCode); | |
399 if (bVertWriting) { | |
400 charpos.m_OriginY = charpos.m_OriginX; | |
401 charpos.m_OriginX = 0; | |
402 short vx, vy; | |
403 pCIDFont->GetVertOrigin(CID, vx, vy); | |
404 charpos.m_OriginX -= FontSize * vx / 1000; | |
405 charpos.m_OriginY -= FontSize * vy / 1000; | |
406 } | |
407 const uint8_t* pTransform = pCIDFont->GetCIDTransform(CID); | |
408 if (pTransform && !bVert) { | |
409 charpos.m_AdjustMatrix[0] = pCIDFont->CIDTransformToFloat(pTransform[0]); | |
410 charpos.m_AdjustMatrix[2] = pCIDFont->CIDTransformToFloat(pTransform[2]); | |
411 charpos.m_AdjustMatrix[1] = pCIDFont->CIDTransformToFloat(pTransform[1]); | |
412 charpos.m_AdjustMatrix[3] = pCIDFont->CIDTransformToFloat(pTransform[3]); | |
413 charpos.m_OriginX += | |
414 pCIDFont->CIDTransformToFloat(pTransform[4]) * FontSize; | |
415 charpos.m_OriginY += | |
416 pCIDFont->CIDTransformToFloat(pTransform[5]) * FontSize; | |
417 charpos.m_bGlyphAdjust = TRUE; | |
418 } | |
419 } | |
420 } | |
421 | |
422 // static | |
423 FX_BOOL CPDF_TextRenderer::DrawTextPath(CFX_RenderDevice* pDevice, | |
424 int nChars, | |
425 uint32_t* pCharCodes, | |
426 FX_FLOAT* pCharPos, | |
427 CPDF_Font* pFont, | |
428 FX_FLOAT font_size, | |
429 const CFX_Matrix* pText2User, | |
430 const CFX_Matrix* pUser2Device, | |
431 const CFX_GraphStateData* pGraphState, | |
432 FX_ARGB fill_argb, | |
433 FX_ARGB stroke_argb, | |
434 CFX_PathData* pClippingPath, | |
435 int nFlag) { | |
436 CPDF_CharPosList CharPosList; | |
437 CharPosList.Load(nChars, pCharCodes, pCharPos, pFont, font_size); | |
438 if (CharPosList.m_nChars == 0) | |
439 return TRUE; | |
440 bool bDraw = true; | |
441 int32_t fontPosition = CharPosList.m_pCharPos[0].m_FallbackFontPosition; | |
442 uint32_t startIndex = 0; | |
443 for (uint32_t i = 0; i < CharPosList.m_nChars; i++) { | |
444 int32_t curFontPosition = CharPosList.m_pCharPos[i].m_FallbackFontPosition; | |
445 if (fontPosition == curFontPosition) | |
446 continue; | |
447 auto* font = fontPosition == -1 | |
448 ? &pFont->m_Font | |
449 : pFont->m_FontFallbacks[fontPosition].get(); | |
450 if (!pDevice->DrawTextPath(i - startIndex, | |
451 CharPosList.m_pCharPos + startIndex, font, | |
452 font_size, pText2User, pUser2Device, pGraphState, | |
453 fill_argb, stroke_argb, pClippingPath, nFlag)) { | |
454 bDraw = false; | |
455 } | |
456 fontPosition = curFontPosition; | |
457 startIndex = i; | |
458 } | |
459 auto* font = fontPosition == -1 ? &pFont->m_Font | |
460 : pFont->m_FontFallbacks[fontPosition].get(); | |
461 if (!pDevice->DrawTextPath(CharPosList.m_nChars - startIndex, | |
462 CharPosList.m_pCharPos + startIndex, font, | |
463 font_size, pText2User, pUser2Device, pGraphState, | |
464 fill_argb, stroke_argb, pClippingPath, nFlag)) { | |
465 bDraw = false; | |
466 } | |
467 return bDraw; | |
468 } | |
469 | |
470 // static | |
471 void CPDF_TextRenderer::DrawTextString(CFX_RenderDevice* pDevice, | |
472 FX_FLOAT origin_x, | |
473 FX_FLOAT origin_y, | |
474 CPDF_Font* pFont, | |
475 FX_FLOAT font_size, | |
476 const CFX_Matrix* pMatrix, | |
477 const CFX_ByteString& str, | |
478 FX_ARGB fill_argb, | |
479 FX_ARGB stroke_argb, | |
480 const CFX_GraphStateData* pGraphState, | |
481 const CPDF_RenderOptions* pOptions) { | |
482 if (pFont->IsType3Font()) | |
483 return; | |
484 | |
485 int nChars = pFont->CountChar(str.c_str(), str.GetLength()); | |
486 if (nChars <= 0) | |
487 return; | |
488 | |
489 int offset = 0; | |
490 uint32_t* pCharCodes; | |
491 FX_FLOAT* pCharPos; | |
492 std::vector<uint32_t> codes; | |
493 std::vector<FX_FLOAT> positions; | |
494 if (nChars == 1) { | |
495 pCharCodes = reinterpret_cast<uint32_t*>( | |
496 pFont->GetNextChar(str.c_str(), str.GetLength(), offset)); | |
497 pCharPos = nullptr; | |
498 } else { | |
499 codes.resize(nChars); | |
500 positions.resize(nChars - 1); | |
501 FX_FLOAT cur_pos = 0; | |
502 for (int i = 0; i < nChars; i++) { | |
503 codes[i] = pFont->GetNextChar(str.c_str(), str.GetLength(), offset); | |
504 if (i) | |
505 positions[i - 1] = cur_pos; | |
506 cur_pos += pFont->GetCharWidthF(codes[i]) * font_size / 1000; | |
507 } | |
508 pCharCodes = codes.data(); | |
509 pCharPos = positions.data(); | |
510 } | |
511 CFX_Matrix matrix; | |
512 if (pMatrix) | |
513 matrix = *pMatrix; | |
514 | |
515 matrix.e = origin_x; | |
516 matrix.f = origin_y; | |
517 | |
518 if (stroke_argb == 0) { | |
519 DrawNormalText(pDevice, nChars, pCharCodes, pCharPos, pFont, font_size, | |
520 &matrix, fill_argb, pOptions); | |
521 } else { | |
522 DrawTextPath(pDevice, nChars, pCharCodes, pCharPos, pFont, font_size, | |
523 &matrix, nullptr, pGraphState, fill_argb, stroke_argb, nullptr, | |
524 0); | |
525 } | |
526 } | |
527 | |
528 // static | |
529 FX_BOOL CPDF_TextRenderer::DrawNormalText(CFX_RenderDevice* pDevice, | |
530 int nChars, | |
531 uint32_t* pCharCodes, | |
532 FX_FLOAT* pCharPos, | |
533 CPDF_Font* pFont, | |
534 FX_FLOAT font_size, | |
535 const CFX_Matrix* pText2Device, | |
536 FX_ARGB fill_argb, | |
537 const CPDF_RenderOptions* pOptions) { | |
538 CPDF_CharPosList CharPosList; | |
539 CharPosList.Load(nChars, pCharCodes, pCharPos, pFont, font_size); | |
540 if (CharPosList.m_nChars == 0) | |
541 return TRUE; | |
542 int FXGE_flags = 0; | |
543 if (pOptions) { | |
544 uint32_t dwFlags = pOptions->m_Flags; | |
545 if (dwFlags & RENDER_CLEARTYPE) { | |
546 FXGE_flags |= FXTEXT_CLEARTYPE; | |
547 if (dwFlags & RENDER_BGR_STRIPE) { | |
548 FXGE_flags |= FXTEXT_BGR_STRIPE; | |
549 } | |
550 } | |
551 if (dwFlags & RENDER_NOTEXTSMOOTH) { | |
552 FXGE_flags |= FXTEXT_NOSMOOTH; | |
553 } | |
554 if (dwFlags & RENDER_PRINTGRAPHICTEXT) { | |
555 FXGE_flags |= FXTEXT_PRINTGRAPHICTEXT; | |
556 } | |
557 if (dwFlags & RENDER_NO_NATIVETEXT) { | |
558 FXGE_flags |= FXTEXT_NO_NATIVETEXT; | |
559 } | |
560 if (dwFlags & RENDER_PRINTIMAGETEXT) { | |
561 FXGE_flags |= FXTEXT_PRINTIMAGETEXT; | |
562 } | |
563 } else { | |
564 FXGE_flags = FXTEXT_CLEARTYPE; | |
565 } | |
566 if (pFont->IsCIDFont()) { | |
567 FXGE_flags |= FXFONT_CIDFONT; | |
568 } | |
569 bool bDraw = true; | |
570 int32_t fontPosition = CharPosList.m_pCharPos[0].m_FallbackFontPosition; | |
571 uint32_t startIndex = 0; | |
572 for (uint32_t i = 0; i < CharPosList.m_nChars; i++) { | |
573 int32_t curFontPosition = CharPosList.m_pCharPos[i].m_FallbackFontPosition; | |
574 if (fontPosition == curFontPosition) | |
575 continue; | |
576 auto* font = fontPosition == -1 | |
577 ? &pFont->m_Font | |
578 : pFont->m_FontFallbacks[fontPosition].get(); | |
579 if (!pDevice->DrawNormalText( | |
580 i - startIndex, CharPosList.m_pCharPos + startIndex, font, | |
581 font_size, pText2Device, fill_argb, FXGE_flags)) { | |
582 bDraw = false; | |
583 } | |
584 fontPosition = curFontPosition; | |
585 startIndex = i; | |
586 } | |
587 auto* font = fontPosition == -1 ? &pFont->m_Font | |
588 : pFont->m_FontFallbacks[fontPosition].get(); | |
589 if (!pDevice->DrawNormalText(CharPosList.m_nChars - startIndex, | |
590 CharPosList.m_pCharPos + startIndex, font, | |
591 font_size, pText2Device, fill_argb, | |
592 FXGE_flags)) { | |
593 bDraw = false; | |
594 } | |
595 return bDraw; | |
596 } | |
597 | |
598 void CPDF_RenderStatus::DrawTextPathWithPattern(const CPDF_TextObject* textobj, | |
599 const CFX_Matrix* pObj2Device, | |
600 CPDF_Font* pFont, | |
601 FX_FLOAT font_size, | |
602 const CFX_Matrix* pTextMatrix, | |
603 FX_BOOL bFill, | |
604 FX_BOOL bStroke) { | |
605 if (!bStroke) { | |
606 CPDF_PathObject path; | |
607 std::vector<std::unique_ptr<CPDF_TextObject>> pCopy; | |
608 pCopy.push_back(std::unique_ptr<CPDF_TextObject>(textobj->Clone())); | |
609 path.m_bStroke = FALSE; | |
610 path.m_FillType = FXFILL_WINDING; | |
611 path.m_ClipPath.AppendTexts(&pCopy); | |
612 path.m_ColorState = textobj->m_ColorState; | |
613 path.m_Path.AppendRect(textobj->m_Left, textobj->m_Bottom, textobj->m_Right, | |
614 textobj->m_Top); | |
615 path.m_Left = textobj->m_Left; | |
616 path.m_Bottom = textobj->m_Bottom; | |
617 path.m_Right = textobj->m_Right; | |
618 path.m_Top = textobj->m_Top; | |
619 RenderSingleObject(&path, pObj2Device); | |
620 return; | |
621 } | |
622 CPDF_CharPosList CharPosList; | |
623 CharPosList.Load(textobj->m_nChars, textobj->m_pCharCodes, | |
624 textobj->m_pCharPos, pFont, font_size); | |
625 for (uint32_t i = 0; i < CharPosList.m_nChars; i++) { | |
626 FXTEXT_CHARPOS& charpos = CharPosList.m_pCharPos[i]; | |
627 auto font = | |
628 charpos.m_FallbackFontPosition == -1 | |
629 ? &pFont->m_Font | |
630 : pFont->m_FontFallbacks[charpos.m_FallbackFontPosition].get(); | |
631 const CFX_PathData* pPath = | |
632 font->LoadGlyphPath(charpos.m_GlyphIndex, charpos.m_FontCharWidth); | |
633 if (!pPath) { | |
634 continue; | |
635 } | |
636 CPDF_PathObject path; | |
637 path.m_GraphState = textobj->m_GraphState; | |
638 path.m_ColorState = textobj->m_ColorState; | |
639 CFX_Matrix matrix; | |
640 if (charpos.m_bGlyphAdjust) | |
641 matrix.Set(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1], | |
642 charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0); | |
643 matrix.Concat(font_size, 0, 0, font_size, charpos.m_OriginX, | |
644 charpos.m_OriginY); | |
645 path.m_Path.Append(pPath, &matrix); | |
646 path.m_Matrix = *pTextMatrix; | |
647 path.m_bStroke = bStroke; | |
648 path.m_FillType = bFill ? FXFILL_WINDING : 0; | |
649 path.CalcBoundingBox(); | |
650 ProcessPath(&path, pObj2Device); | |
651 } | |
652 } | |
OLD | NEW |