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/src/fpdfapi/fpdf_render/render_int.h" | |
8 | |
9 #include "core/include/fpdfapi/cpdf_dictionary.h" | |
10 #include "core/include/fpdfapi/cpdf_document.h" | |
11 #include "core/include/fpdfapi/fpdf_pageobj.h" | |
12 #include "core/include/fpdfapi/fpdf_render.h" | |
13 #include "core/include/fxge/fx_ge.h" | |
14 #include "core/src/fpdfapi/fpdf_page/pageint.h" | |
15 | |
16 CPDF_Type3Cache::~CPDF_Type3Cache() { | |
17 for (const auto& pair : m_SizeMap) { | |
18 delete pair.second; | |
19 } | |
20 m_SizeMap.clear(); | |
21 } | |
22 CFX_GlyphBitmap* CPDF_Type3Cache::LoadGlyph(FX_DWORD charcode, | |
23 const CFX_Matrix* pMatrix, | |
24 FX_FLOAT retinaScaleX, | |
25 FX_FLOAT retinaScaleY) { | |
26 _CPDF_UniqueKeyGen keygen; | |
27 keygen.Generate( | |
28 4, FXSYS_round(pMatrix->a * 10000), FXSYS_round(pMatrix->b * 10000), | |
29 FXSYS_round(pMatrix->c * 10000), FXSYS_round(pMatrix->d * 10000)); | |
30 CFX_ByteStringC FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen); | |
31 CPDF_Type3Glyphs* pSizeCache; | |
32 auto it = m_SizeMap.find(FaceGlyphsKey); | |
33 if (it == m_SizeMap.end()) { | |
34 pSizeCache = new CPDF_Type3Glyphs; | |
35 m_SizeMap[FaceGlyphsKey] = pSizeCache; | |
36 } else { | |
37 pSizeCache = it->second; | |
38 } | |
39 auto it2 = pSizeCache->m_GlyphMap.find(charcode); | |
40 if (it2 != pSizeCache->m_GlyphMap.end()) | |
41 return it2->second; | |
42 | |
43 CFX_GlyphBitmap* pGlyphBitmap = | |
44 RenderGlyph(pSizeCache, charcode, pMatrix, retinaScaleX, retinaScaleY); | |
45 pSizeCache->m_GlyphMap[charcode] = pGlyphBitmap; | |
46 return pGlyphBitmap; | |
47 } | |
48 CPDF_Type3Glyphs::~CPDF_Type3Glyphs() { | |
49 for (const auto& pair : m_GlyphMap) | |
50 delete pair.second; | |
51 } | |
52 static int _AdjustBlue(FX_FLOAT pos, int& count, int blues[]) { | |
53 FX_FLOAT min_distance = 1000000.0f * 1.0f; | |
54 int closest_pos = -1; | |
55 for (int i = 0; i < count; i++) { | |
56 FX_FLOAT distance = (FX_FLOAT)FXSYS_fabs(pos - (FX_FLOAT)blues[i]); | |
57 if (distance < 1.0f * 80.0f / 100.0f && distance < min_distance) { | |
58 min_distance = distance; | |
59 closest_pos = i; | |
60 } | |
61 } | |
62 if (closest_pos >= 0) { | |
63 return blues[closest_pos]; | |
64 } | |
65 int new_pos = FXSYS_round(pos); | |
66 if (count == TYPE3_MAX_BLUES) { | |
67 return new_pos; | |
68 } | |
69 blues[count++] = new_pos; | |
70 return new_pos; | |
71 } | |
72 void CPDF_Type3Glyphs::AdjustBlue(FX_FLOAT top, | |
73 FX_FLOAT bottom, | |
74 int& top_line, | |
75 int& bottom_line) { | |
76 top_line = _AdjustBlue(top, m_TopBlueCount, m_TopBlue); | |
77 bottom_line = _AdjustBlue(bottom, m_BottomBlueCount, m_BottomBlue); | |
78 } | |
79 | |
80 static FX_BOOL _IsScanLine1bpp(uint8_t* pBuf, int width) { | |
81 int size = width / 8; | |
82 for (int i = 0; i < size; i++) { | |
83 if (pBuf[i]) | |
84 return TRUE; | |
85 } | |
86 return (width % 8) && (pBuf[width / 8] & (0xff << (8 - width % 8))); | |
87 } | |
88 | |
89 static FX_BOOL _IsScanLine8bpp(uint8_t* pBuf, int width) { | |
90 for (int i = 0; i < width; i++) { | |
91 if (pBuf[i] > 0x40) | |
92 return TRUE; | |
93 } | |
94 return FALSE; | |
95 } | |
96 | |
97 static int _DetectFirstLastScan(const CFX_DIBitmap* pBitmap, FX_BOOL bFirst) { | |
98 int height = pBitmap->GetHeight(), pitch = pBitmap->GetPitch(), | |
99 width = pBitmap->GetWidth(); | |
100 int bpp = pBitmap->GetBPP(); | |
101 if (bpp > 8) { | |
102 width *= bpp / 8; | |
103 } | |
104 uint8_t* pBuf = pBitmap->GetBuffer(); | |
105 int line = bFirst ? 0 : height - 1; | |
106 int line_step = bFirst ? 1 : -1; | |
107 int line_end = bFirst ? height : -1; | |
108 while (line != line_end) { | |
109 if (bpp == 1) { | |
110 if (_IsScanLine1bpp(pBuf + line * pitch, width)) { | |
111 return line; | |
112 } | |
113 } else { | |
114 if (_IsScanLine8bpp(pBuf + line * pitch, width)) { | |
115 return line; | |
116 } | |
117 } | |
118 line += line_step; | |
119 } | |
120 return -1; | |
121 } | |
122 CFX_GlyphBitmap* CPDF_Type3Cache::RenderGlyph(CPDF_Type3Glyphs* pSize, | |
123 FX_DWORD charcode, | |
124 const CFX_Matrix* pMatrix, | |
125 FX_FLOAT retinaScaleX, | |
126 FX_FLOAT retinaScaleY) { | |
127 const CPDF_Type3Char* pChar = m_pFont->LoadChar(charcode); | |
128 if (!pChar || !pChar->m_pBitmap) | |
129 return nullptr; | |
130 | |
131 CFX_DIBitmap* pBitmap = pChar->m_pBitmap; | |
132 CFX_Matrix image_matrix, text_matrix; | |
133 image_matrix = pChar->m_ImageMatrix; | |
134 text_matrix.Set(pMatrix->a, pMatrix->b, pMatrix->c, pMatrix->d, 0, 0); | |
135 image_matrix.Concat(text_matrix); | |
136 CFX_DIBitmap* pResBitmap = NULL; | |
137 int left, top; | |
138 if (FXSYS_fabs(image_matrix.b) < FXSYS_fabs(image_matrix.a) / 100 && | |
139 FXSYS_fabs(image_matrix.c) < FXSYS_fabs(image_matrix.d) / 100) { | |
140 int top_line, bottom_line; | |
141 top_line = _DetectFirstLastScan(pBitmap, TRUE); | |
142 bottom_line = _DetectFirstLastScan(pBitmap, FALSE); | |
143 if (top_line == 0 && bottom_line == pBitmap->GetHeight() - 1) { | |
144 FX_FLOAT top_y = image_matrix.d + image_matrix.f; | |
145 FX_FLOAT bottom_y = image_matrix.f; | |
146 FX_BOOL bFlipped = top_y > bottom_y; | |
147 if (bFlipped) { | |
148 FX_FLOAT temp = top_y; | |
149 top_y = bottom_y; | |
150 bottom_y = temp; | |
151 } | |
152 pSize->AdjustBlue(top_y, bottom_y, top_line, bottom_line); | |
153 pResBitmap = pBitmap->StretchTo( | |
154 (int)(FXSYS_round(image_matrix.a) * retinaScaleX), | |
155 (int)((bFlipped ? top_line - bottom_line : bottom_line - top_line) * | |
156 retinaScaleY)); | |
157 top = top_line; | |
158 if (image_matrix.a < 0) { | |
159 image_matrix.Scale(retinaScaleX, retinaScaleY); | |
160 left = FXSYS_round(image_matrix.e + image_matrix.a); | |
161 } else { | |
162 left = FXSYS_round(image_matrix.e); | |
163 } | |
164 } else { | |
165 } | |
166 } | |
167 if (!pResBitmap) { | |
168 image_matrix.Scale(retinaScaleX, retinaScaleY); | |
169 pResBitmap = pBitmap->TransformTo(&image_matrix, left, top); | |
170 } | |
171 if (!pResBitmap) { | |
172 return NULL; | |
173 } | |
174 CFX_GlyphBitmap* pGlyph = new CFX_GlyphBitmap; | |
175 pGlyph->m_Left = left; | |
176 pGlyph->m_Top = -top; | |
177 pGlyph->m_Bitmap.TakeOver(pResBitmap); | |
178 delete pResBitmap; | |
179 return pGlyph; | |
180 } | |
181 void _CPDF_UniqueKeyGen::Generate(int count, ...) { | |
182 va_list argList; | |
183 va_start(argList, count); | |
184 for (int i = 0; i < count; i++) { | |
185 int p = va_arg(argList, int); | |
186 ((FX_DWORD*)m_Key)[i] = p; | |
187 } | |
188 va_end(argList); | |
189 m_KeyLen = count * sizeof(FX_DWORD); | |
190 } | |
191 FX_BOOL CPDF_RenderStatus::ProcessText(const CPDF_TextObject* textobj, | |
192 const CFX_Matrix* pObj2Device, | |
193 CFX_PathData* pClippingPath) { | |
194 if (textobj->m_nChars == 0) { | |
195 return TRUE; | |
196 } | |
197 int text_render_mode = textobj->m_TextState.GetObject()->m_TextMode; | |
198 if (text_render_mode == 3) { | |
199 return TRUE; | |
200 } | |
201 CPDF_Font* pFont = textobj->m_TextState.GetFont(); | |
202 if (pFont->IsType3Font()) { | |
203 return ProcessType3Text(textobj, pObj2Device); | |
204 } | |
205 FX_BOOL bFill = FALSE, bStroke = FALSE, bClip = FALSE; | |
206 if (pClippingPath) { | |
207 bClip = TRUE; | |
208 } else { | |
209 switch (text_render_mode) { | |
210 case 0: | |
211 case 4: | |
212 bFill = TRUE; | |
213 break; | |
214 case 1: | |
215 case 5: | |
216 if (!pFont->GetFace() && | |
217 !(pFont->GetSubstFont()->m_SubstFlags & FXFONT_SUBST_GLYPHPATH)) { | |
218 bFill = TRUE; | |
219 } else { | |
220 bStroke = TRUE; | |
221 } | |
222 break; | |
223 case 2: | |
224 case 6: | |
225 if (!pFont->GetFace() && | |
226 !(pFont->GetSubstFont()->m_SubstFlags & FXFONT_SUBST_GLYPHPATH)) { | |
227 bFill = TRUE; | |
228 } else { | |
229 bFill = bStroke = TRUE; | |
230 } | |
231 break; | |
232 case 3: | |
233 case 7: | |
234 return TRUE; | |
235 default: | |
236 bFill = TRUE; | |
237 } | |
238 } | |
239 FX_ARGB stroke_argb = 0, fill_argb = 0; | |
240 FX_BOOL bPattern = FALSE; | |
241 if (bStroke) { | |
242 if (textobj->m_ColorState.GetStrokeColor()->IsPattern()) { | |
243 bPattern = TRUE; | |
244 } else { | |
245 stroke_argb = GetStrokeArgb(textobj); | |
246 } | |
247 } | |
248 if (bFill) { | |
249 if (textobj->m_ColorState.GetFillColor()->IsPattern()) { | |
250 bPattern = TRUE; | |
251 } else { | |
252 fill_argb = GetFillArgb(textobj); | |
253 } | |
254 } | |
255 CFX_Matrix text_matrix; | |
256 textobj->GetTextMatrix(&text_matrix); | |
257 if (IsAvailableMatrix(text_matrix) == FALSE) { | |
258 return TRUE; | |
259 } | |
260 FX_FLOAT font_size = textobj->m_TextState.GetFontSize(); | |
261 if (bPattern) { | |
262 DrawTextPathWithPattern(textobj, pObj2Device, pFont, font_size, | |
263 &text_matrix, bFill, bStroke); | |
264 return TRUE; | |
265 } | |
266 if (bClip || bStroke) { | |
267 const CFX_Matrix* pDeviceMatrix = pObj2Device; | |
268 CFX_Matrix device_matrix; | |
269 if (bStroke) { | |
270 const FX_FLOAT* pCTM = textobj->m_TextState.GetObject()->m_CTM; | |
271 if (pCTM[0] != 1.0f || pCTM[3] != 1.0f) { | |
272 CFX_Matrix ctm(pCTM[0], pCTM[1], pCTM[2], pCTM[3], 0, 0); | |
273 text_matrix.ConcatInverse(ctm); | |
274 device_matrix.Copy(ctm); | |
275 device_matrix.Concat(*pObj2Device); | |
276 pDeviceMatrix = &device_matrix; | |
277 } | |
278 } | |
279 int flag = 0; | |
280 if (bStroke && bFill) { | |
281 flag |= FX_FILL_STROKE; | |
282 flag |= FX_STROKE_TEXT_MODE; | |
283 } | |
284 const CPDF_GeneralStateData* pGeneralData = | |
285 ((CPDF_PageObject*)textobj)->m_GeneralState; | |
286 if (pGeneralData && pGeneralData->m_StrokeAdjust) { | |
287 flag |= FX_STROKE_ADJUST; | |
288 } | |
289 if (m_Options.m_Flags & RENDER_NOTEXTSMOOTH) { | |
290 flag |= FXFILL_NOPATHSMOOTH; | |
291 } | |
292 return CPDF_TextRenderer::DrawTextPath( | |
293 m_pDevice, textobj->m_nChars, textobj->m_pCharCodes, | |
294 textobj->m_pCharPos, pFont, font_size, &text_matrix, pDeviceMatrix, | |
295 textobj->m_GraphState, fill_argb, stroke_argb, pClippingPath, flag); | |
296 } | |
297 text_matrix.Concat(*pObj2Device); | |
298 return CPDF_TextRenderer::DrawNormalText( | |
299 m_pDevice, textobj->m_nChars, textobj->m_pCharCodes, textobj->m_pCharPos, | |
300 pFont, font_size, &text_matrix, fill_argb, &m_Options); | |
301 } | |
302 CPDF_Type3Cache* CPDF_RenderStatus::GetCachedType3(CPDF_Type3Font* pFont) { | |
303 if (!pFont->m_pDocument) { | |
304 return NULL; | |
305 } | |
306 pFont->m_pDocument->GetPageData()->GetFont(pFont->GetFontDict(), FALSE); | |
307 return pFont->m_pDocument->GetRenderData()->GetCachedType3(pFont); | |
308 } | |
309 static void ReleaseCachedType3(CPDF_Type3Font* pFont) { | |
310 if (!pFont->m_pDocument) { | |
311 return; | |
312 } | |
313 pFont->m_pDocument->GetRenderData()->ReleaseCachedType3(pFont); | |
314 pFont->m_pDocument->GetPageData()->ReleaseFont(pFont->GetFontDict()); | |
315 } | |
316 FX_BOOL CPDF_Type3Char::LoadBitmap(CPDF_RenderContext* pContext) { | |
317 if (m_pBitmap || !m_pForm) { | |
318 return TRUE; | |
319 } | |
320 if (m_pForm->GetPageObjectList()->size() == 1 && !m_bColored) { | |
321 auto& pPageObj = m_pForm->GetPageObjectList()->front(); | |
322 if (pPageObj->IsImage()) { | |
323 m_ImageMatrix = pPageObj->AsImage()->m_Matrix; | |
324 const CFX_DIBSource* pSource = | |
325 pPageObj->AsImage()->m_pImage->LoadDIBSource(); | |
326 if (pSource) { | |
327 m_pBitmap = pSource->Clone(); | |
328 delete pSource; | |
329 } | |
330 delete m_pForm; | |
331 m_pForm = NULL; | |
332 return TRUE; | |
333 } | |
334 } | |
335 return FALSE; | |
336 } | |
337 class CPDF_RefType3Cache { | |
338 public: | |
339 CPDF_RefType3Cache(CPDF_Type3Font* pType3Font) { | |
340 m_dwCount = 0; | |
341 m_pType3Font = pType3Font; | |
342 } | |
343 ~CPDF_RefType3Cache() { | |
344 while (m_dwCount--) { | |
345 ReleaseCachedType3(m_pType3Font); | |
346 } | |
347 } | |
348 FX_DWORD m_dwCount; | |
349 CPDF_Type3Font* m_pType3Font; | |
350 }; | |
351 FX_BOOL CPDF_RenderStatus::ProcessType3Text(const CPDF_TextObject* textobj, | |
352 const CFX_Matrix* pObj2Device) { | |
353 CPDF_Type3Font* pType3Font = textobj->m_TextState.GetFont()->AsType3Font(); | |
354 for (int j = 0; j < m_Type3FontCache.GetSize(); j++) { | |
355 if (m_Type3FontCache.GetAt(j) == pType3Font) | |
356 return TRUE; | |
357 } | |
358 CFX_Matrix dCTM = m_pDevice->GetCTM(); | |
359 FX_FLOAT sa = FXSYS_fabs(dCTM.a); | |
360 FX_FLOAT sd = FXSYS_fabs(dCTM.d); | |
361 CFX_Matrix text_matrix; | |
362 textobj->GetTextMatrix(&text_matrix); | |
363 CFX_Matrix char_matrix = pType3Font->GetFontMatrix(); | |
364 FX_FLOAT font_size = textobj->m_TextState.GetFontSize(); | |
365 char_matrix.Scale(font_size, font_size); | |
366 FX_ARGB fill_argb = GetFillArgb(textobj, TRUE); | |
367 int fill_alpha = FXARGB_A(fill_argb); | |
368 int device_class = m_pDevice->GetDeviceClass(); | |
369 FXTEXT_GLYPHPOS* pGlyphAndPos = NULL; | |
370 if (device_class == FXDC_DISPLAY) { | |
371 pGlyphAndPos = FX_Alloc(FXTEXT_GLYPHPOS, textobj->m_nChars); | |
372 } else if (fill_alpha < 255) { | |
373 return FALSE; | |
374 } | |
375 CPDF_RefType3Cache refTypeCache(pType3Font); | |
376 FX_DWORD* pChars = textobj->m_pCharCodes; | |
377 if (textobj->m_nChars == 1) { | |
378 pChars = (FX_DWORD*)(&textobj->m_pCharCodes); | |
379 } | |
380 for (int iChar = 0; iChar < textobj->m_nChars; iChar++) { | |
381 FX_DWORD charcode = pChars[iChar]; | |
382 if (charcode == (FX_DWORD)-1) { | |
383 continue; | |
384 } | |
385 CPDF_Type3Char* pType3Char = pType3Font->LoadChar(charcode); | |
386 if (!pType3Char) { | |
387 continue; | |
388 } | |
389 CFX_Matrix matrix = char_matrix; | |
390 matrix.e += iChar ? textobj->m_pCharPos[iChar - 1] : 0; | |
391 matrix.Concat(text_matrix); | |
392 matrix.Concat(*pObj2Device); | |
393 if (!pType3Char->LoadBitmap(m_pContext)) { | |
394 if (pGlyphAndPos) { | |
395 for (int i = 0; i < iChar; i++) { | |
396 FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[i]; | |
397 if (!glyph.m_pGlyph) { | |
398 continue; | |
399 } | |
400 m_pDevice->SetBitMask(&glyph.m_pGlyph->m_Bitmap, | |
401 glyph.m_OriginX + glyph.m_pGlyph->m_Left, | |
402 glyph.m_OriginY - glyph.m_pGlyph->m_Top, | |
403 fill_argb); | |
404 } | |
405 FX_Free(pGlyphAndPos); | |
406 pGlyphAndPos = NULL; | |
407 } | |
408 CPDF_GraphicStates* pStates = CloneObjStates(textobj, FALSE); | |
409 CPDF_RenderOptions Options = m_Options; | |
410 Options.m_Flags |= RENDER_FORCE_HALFTONE | RENDER_RECT_AA; | |
411 Options.m_Flags &= ~RENDER_FORCE_DOWNSAMPLE; | |
412 CPDF_Dictionary* pFormResource = NULL; | |
413 if (pType3Char->m_pForm && pType3Char->m_pForm->m_pFormDict) { | |
414 pFormResource = | |
415 pType3Char->m_pForm->m_pFormDict->GetDictBy("Resources"); | |
416 } | |
417 if (fill_alpha == 255) { | |
418 CPDF_RenderStatus status; | |
419 status.Initialize(m_pContext, m_pDevice, NULL, NULL, this, pStates, | |
420 &Options, pType3Char->m_pForm->m_Transparency, | |
421 m_bDropObjects, pFormResource, FALSE, pType3Char, | |
422 fill_argb); | |
423 status.m_Type3FontCache.Append(m_Type3FontCache); | |
424 status.m_Type3FontCache.Add(pType3Font); | |
425 m_pDevice->SaveState(); | |
426 status.RenderObjectList(pType3Char->m_pForm, &matrix); | |
427 m_pDevice->RestoreState(); | |
428 } else { | |
429 CFX_FloatRect rect_f = pType3Char->m_pForm->CalcBoundingBox(); | |
430 rect_f.Transform(&matrix); | |
431 FX_RECT rect = rect_f.GetOutterRect(); | |
432 CFX_FxgeDevice bitmap_device; | |
433 if (!bitmap_device.Create((int)(rect.Width() * sa), | |
434 (int)(rect.Height() * sd), FXDIB_Argb)) { | |
435 return TRUE; | |
436 } | |
437 bitmap_device.GetBitmap()->Clear(0); | |
438 CPDF_RenderStatus status; | |
439 status.Initialize(m_pContext, &bitmap_device, NULL, NULL, this, pStates, | |
440 &Options, pType3Char->m_pForm->m_Transparency, | |
441 m_bDropObjects, pFormResource, FALSE, pType3Char, | |
442 fill_argb); | |
443 status.m_Type3FontCache.Append(m_Type3FontCache); | |
444 status.m_Type3FontCache.Add(pType3Font); | |
445 matrix.TranslateI(-rect.left, -rect.top); | |
446 matrix.Scale(sa, sd); | |
447 status.RenderObjectList(pType3Char->m_pForm, &matrix); | |
448 m_pDevice->SetDIBits(bitmap_device.GetBitmap(), rect.left, rect.top); | |
449 } | |
450 delete pStates; | |
451 } else if (pType3Char->m_pBitmap) { | |
452 if (device_class == FXDC_DISPLAY) { | |
453 CPDF_Type3Cache* pCache = GetCachedType3(pType3Font); | |
454 refTypeCache.m_dwCount++; | |
455 CFX_GlyphBitmap* pBitmap = pCache->LoadGlyph(charcode, &matrix, sa, sd); | |
456 if (!pBitmap) { | |
457 continue; | |
458 } | |
459 int origin_x = FXSYS_round(matrix.e); | |
460 int origin_y = FXSYS_round(matrix.f); | |
461 if (pGlyphAndPos) { | |
462 pGlyphAndPos[iChar].m_pGlyph = pBitmap; | |
463 pGlyphAndPos[iChar].m_OriginX = origin_x; | |
464 pGlyphAndPos[iChar].m_OriginY = origin_y; | |
465 } else { | |
466 m_pDevice->SetBitMask(&pBitmap->m_Bitmap, origin_x + pBitmap->m_Left, | |
467 origin_y - pBitmap->m_Top, fill_argb); | |
468 } | |
469 } else { | |
470 CFX_Matrix image_matrix = pType3Char->m_ImageMatrix; | |
471 image_matrix.Concat(matrix); | |
472 CPDF_ImageRenderer renderer; | |
473 if (renderer.Start(this, pType3Char->m_pBitmap, fill_argb, 255, | |
474 &image_matrix, 0, FALSE)) { | |
475 renderer.Continue(NULL); | |
476 } | |
477 if (!renderer.m_Result) { | |
478 return FALSE; | |
479 } | |
480 } | |
481 } | |
482 } | |
483 if (pGlyphAndPos) { | |
484 FX_RECT rect = | |
485 FXGE_GetGlyphsBBox(pGlyphAndPos, textobj->m_nChars, 0, sa, sd); | |
486 CFX_DIBitmap bitmap; | |
487 if (!bitmap.Create((int)(rect.Width() * sa), (int)(rect.Height() * sd), | |
488 FXDIB_8bppMask)) { | |
489 FX_Free(pGlyphAndPos); | |
490 return TRUE; | |
491 } | |
492 bitmap.Clear(0); | |
493 for (int iChar = 0; iChar < textobj->m_nChars; iChar++) { | |
494 FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar]; | |
495 if (!glyph.m_pGlyph) { | |
496 continue; | |
497 } | |
498 bitmap.TransferBitmap( | |
499 (int)((glyph.m_OriginX + glyph.m_pGlyph->m_Left - rect.left) * sa), | |
500 (int)((glyph.m_OriginY - glyph.m_pGlyph->m_Top - rect.top) * sd), | |
501 glyph.m_pGlyph->m_Bitmap.GetWidth(), | |
502 glyph.m_pGlyph->m_Bitmap.GetHeight(), &glyph.m_pGlyph->m_Bitmap, 0, | |
503 0); | |
504 } | |
505 m_pDevice->SetBitMask(&bitmap, rect.left, rect.top, fill_argb); | |
506 FX_Free(pGlyphAndPos); | |
507 } | |
508 return TRUE; | |
509 } | |
510 class CPDF_CharPosList { | |
511 public: | |
512 CPDF_CharPosList(); | |
513 ~CPDF_CharPosList(); | |
514 void Load(int nChars, | |
515 FX_DWORD* pCharCodes, | |
516 FX_FLOAT* pCharPos, | |
517 CPDF_Font* pFont, | |
518 FX_FLOAT font_size); | |
519 FXTEXT_CHARPOS* m_pCharPos; | |
520 FX_DWORD m_nChars; | |
521 }; | |
522 | |
523 CPDF_CharPosList::CPDF_CharPosList() { | |
524 m_pCharPos = NULL; | |
525 } | |
526 CPDF_CharPosList::~CPDF_CharPosList() { | |
527 FX_Free(m_pCharPos); | |
528 } | |
529 void CPDF_CharPosList::Load(int nChars, | |
530 FX_DWORD* pCharCodes, | |
531 FX_FLOAT* pCharPos, | |
532 CPDF_Font* pFont, | |
533 FX_FLOAT FontSize) { | |
534 m_pCharPos = FX_Alloc(FXTEXT_CHARPOS, nChars); | |
535 m_nChars = 0; | |
536 CPDF_CIDFont* pCIDFont = pFont->AsCIDFont(); | |
537 FX_BOOL bVertWriting = pCIDFont && pCIDFont->IsVertWriting(); | |
538 for (int iChar = 0; iChar < nChars; iChar++) { | |
539 FX_DWORD CharCode = | |
540 nChars == 1 ? (FX_DWORD)(uintptr_t)pCharCodes : pCharCodes[iChar]; | |
541 if (CharCode == (FX_DWORD)-1) { | |
542 continue; | |
543 } | |
544 FX_BOOL bVert = FALSE; | |
545 FXTEXT_CHARPOS& charpos = m_pCharPos[m_nChars++]; | |
546 if (pCIDFont) { | |
547 charpos.m_bFontStyle = pCIDFont->IsFontStyleFromCharCode(CharCode); | |
548 } | |
549 charpos.m_GlyphIndex = pFont->GlyphFromCharCode(CharCode, &bVert); | |
550 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ | |
551 charpos.m_ExtGID = pFont->GlyphFromCharCodeExt(CharCode); | |
552 #endif | |
553 if (!pFont->IsEmbedded() && !pFont->IsCIDFont()) { | |
554 charpos.m_FontCharWidth = pFont->GetCharWidthF(CharCode); | |
555 } else { | |
556 charpos.m_FontCharWidth = 0; | |
557 } | |
558 charpos.m_OriginX = iChar ? pCharPos[iChar - 1] : 0; | |
559 charpos.m_OriginY = 0; | |
560 charpos.m_bGlyphAdjust = FALSE; | |
561 if (!pCIDFont) { | |
562 continue; | |
563 } | |
564 FX_WORD CID = pCIDFont->CIDFromCharCode(CharCode); | |
565 if (bVertWriting) { | |
566 charpos.m_OriginY = charpos.m_OriginX; | |
567 charpos.m_OriginX = 0; | |
568 short vx, vy; | |
569 pCIDFont->GetVertOrigin(CID, vx, vy); | |
570 charpos.m_OriginX -= FontSize * vx / 1000; | |
571 charpos.m_OriginY -= FontSize * vy / 1000; | |
572 } | |
573 const uint8_t* pTransform = pCIDFont->GetCIDTransform(CID); | |
574 if (pTransform && !bVert) { | |
575 charpos.m_AdjustMatrix[0] = pCIDFont->CIDTransformToFloat(pTransform[0]); | |
576 charpos.m_AdjustMatrix[2] = pCIDFont->CIDTransformToFloat(pTransform[2]); | |
577 charpos.m_AdjustMatrix[1] = pCIDFont->CIDTransformToFloat(pTransform[1]); | |
578 charpos.m_AdjustMatrix[3] = pCIDFont->CIDTransformToFloat(pTransform[3]); | |
579 charpos.m_OriginX += | |
580 pCIDFont->CIDTransformToFloat(pTransform[4]) * FontSize; | |
581 charpos.m_OriginY += | |
582 pCIDFont->CIDTransformToFloat(pTransform[5]) * FontSize; | |
583 charpos.m_bGlyphAdjust = TRUE; | |
584 } | |
585 } | |
586 } | |
587 FX_BOOL CPDF_TextRenderer::DrawTextPath(CFX_RenderDevice* pDevice, | |
588 int nChars, | |
589 FX_DWORD* pCharCodes, | |
590 FX_FLOAT* pCharPos, | |
591 CPDF_Font* pFont, | |
592 FX_FLOAT font_size, | |
593 const CFX_Matrix* pText2User, | |
594 const CFX_Matrix* pUser2Device, | |
595 const CFX_GraphStateData* pGraphState, | |
596 FX_ARGB fill_argb, | |
597 FX_ARGB stroke_argb, | |
598 CFX_PathData* pClippingPath, | |
599 int nFlag) { | |
600 CFX_FontCache* pCache = | |
601 pFont->m_pDocument ? pFont->m_pDocument->GetRenderData()->GetFontCache() | |
602 : NULL; | |
603 CPDF_CharPosList CharPosList; | |
604 CharPosList.Load(nChars, pCharCodes, pCharPos, pFont, font_size); | |
605 return pDevice->DrawTextPath(CharPosList.m_nChars, CharPosList.m_pCharPos, | |
606 &pFont->m_Font, pCache, font_size, pText2User, | |
607 pUser2Device, pGraphState, fill_argb, | |
608 stroke_argb, pClippingPath, nFlag); | |
609 } | |
610 void CPDF_TextRenderer::DrawTextString(CFX_RenderDevice* pDevice, | |
611 int left, | |
612 int top, | |
613 CPDF_Font* pFont, | |
614 int height, | |
615 const CFX_ByteString& str, | |
616 FX_ARGB argb) { | |
617 FX_RECT font_bbox; | |
618 pFont->GetFontBBox(font_bbox); | |
619 FX_FLOAT font_size = | |
620 (FX_FLOAT)height * 1000.0f / (FX_FLOAT)(font_bbox.top - font_bbox.bottom); | |
621 FX_FLOAT origin_x = (FX_FLOAT)left; | |
622 FX_FLOAT origin_y = | |
623 (FX_FLOAT)top + font_size * (FX_FLOAT)font_bbox.top / 1000.0f; | |
624 CFX_Matrix matrix(1.0f, 0, 0, -1.0f, 0, 0); | |
625 DrawTextString(pDevice, origin_x, origin_y, pFont, font_size, &matrix, str, | |
626 argb); | |
627 } | |
628 void CPDF_TextRenderer::DrawTextString(CFX_RenderDevice* pDevice, | |
629 FX_FLOAT origin_x, | |
630 FX_FLOAT origin_y, | |
631 CPDF_Font* pFont, | |
632 FX_FLOAT font_size, | |
633 const CFX_Matrix* pMatrix, | |
634 const CFX_ByteString& str, | |
635 FX_ARGB fill_argb, | |
636 FX_ARGB stroke_argb, | |
637 const CFX_GraphStateData* pGraphState, | |
638 const CPDF_RenderOptions* pOptions) { | |
639 int nChars = pFont->CountChar(str, str.GetLength()); | |
640 if (nChars == 0) { | |
641 return; | |
642 } | |
643 FX_DWORD charcode; | |
644 int offset = 0; | |
645 FX_DWORD* pCharCodes; | |
646 FX_FLOAT* pCharPos; | |
647 if (nChars == 1) { | |
648 charcode = pFont->GetNextChar(str, str.GetLength(), offset); | |
649 pCharCodes = (FX_DWORD*)(uintptr_t)charcode; | |
650 pCharPos = NULL; | |
651 } else { | |
652 pCharCodes = FX_Alloc(FX_DWORD, nChars); | |
653 pCharPos = FX_Alloc(FX_FLOAT, nChars - 1); | |
654 FX_FLOAT cur_pos = 0; | |
655 for (int i = 0; i < nChars; i++) { | |
656 pCharCodes[i] = pFont->GetNextChar(str, str.GetLength(), offset); | |
657 if (i) { | |
658 pCharPos[i - 1] = cur_pos; | |
659 } | |
660 cur_pos += pFont->GetCharWidthF(pCharCodes[i]) * font_size / 1000; | |
661 } | |
662 } | |
663 CFX_Matrix matrix; | |
664 if (pMatrix) | |
665 matrix = *pMatrix; | |
666 | |
667 matrix.e = origin_x; | |
668 matrix.f = origin_y; | |
669 | |
670 if (!pFont->IsType3Font()) { | |
671 if (stroke_argb == 0) { | |
672 DrawNormalText(pDevice, nChars, pCharCodes, pCharPos, pFont, font_size, | |
673 &matrix, fill_argb, pOptions); | |
674 } else { | |
675 DrawTextPath(pDevice, nChars, pCharCodes, pCharPos, pFont, font_size, | |
676 &matrix, NULL, pGraphState, fill_argb, stroke_argb, NULL); | |
677 } | |
678 } | |
679 | |
680 if (nChars > 1) { | |
681 FX_Free(pCharCodes); | |
682 FX_Free(pCharPos); | |
683 } | |
684 } | |
685 FX_BOOL CPDF_TextRenderer::DrawNormalText(CFX_RenderDevice* pDevice, | |
686 int nChars, | |
687 FX_DWORD* pCharCodes, | |
688 FX_FLOAT* pCharPos, | |
689 CPDF_Font* pFont, | |
690 FX_FLOAT font_size, | |
691 const CFX_Matrix* pText2Device, | |
692 FX_ARGB fill_argb, | |
693 const CPDF_RenderOptions* pOptions) { | |
694 CFX_FontCache* pCache = | |
695 pFont->m_pDocument ? pFont->m_pDocument->GetRenderData()->GetFontCache() | |
696 : NULL; | |
697 CPDF_CharPosList CharPosList; | |
698 CharPosList.Load(nChars, pCharCodes, pCharPos, pFont, font_size); | |
699 int FXGE_flags = 0; | |
700 if (pOptions) { | |
701 FX_DWORD dwFlags = pOptions->m_Flags; | |
702 if (dwFlags & RENDER_CLEARTYPE) { | |
703 FXGE_flags |= FXTEXT_CLEARTYPE; | |
704 if (dwFlags & RENDER_BGR_STRIPE) { | |
705 FXGE_flags |= FXTEXT_BGR_STRIPE; | |
706 } | |
707 } | |
708 if (dwFlags & RENDER_NOTEXTSMOOTH) { | |
709 FXGE_flags |= FXTEXT_NOSMOOTH; | |
710 } | |
711 if (dwFlags & RENDER_PRINTGRAPHICTEXT) { | |
712 FXGE_flags |= FXTEXT_PRINTGRAPHICTEXT; | |
713 } | |
714 if (dwFlags & RENDER_NO_NATIVETEXT) { | |
715 FXGE_flags |= FXTEXT_NO_NATIVETEXT; | |
716 } | |
717 if (dwFlags & RENDER_PRINTIMAGETEXT) { | |
718 FXGE_flags |= FXTEXT_PRINTIMAGETEXT; | |
719 } | |
720 } else { | |
721 FXGE_flags = FXTEXT_CLEARTYPE; | |
722 } | |
723 if (pFont->IsCIDFont()) { | |
724 FXGE_flags |= FXFONT_CIDFONT; | |
725 } | |
726 return pDevice->DrawNormalText(CharPosList.m_nChars, CharPosList.m_pCharPos, | |
727 &pFont->m_Font, pCache, font_size, | |
728 pText2Device, fill_argb, FXGE_flags); | |
729 } | |
730 void CPDF_RenderStatus::DrawTextPathWithPattern(const CPDF_TextObject* textobj, | |
731 const CFX_Matrix* pObj2Device, | |
732 CPDF_Font* pFont, | |
733 FX_FLOAT font_size, | |
734 const CFX_Matrix* pTextMatrix, | |
735 FX_BOOL bFill, | |
736 FX_BOOL bStroke) { | |
737 if (!bStroke) { | |
738 CPDF_PathObject path; | |
739 CPDF_TextObject* pCopy = textobj->Clone(); | |
740 path.m_bStroke = FALSE; | |
741 path.m_FillType = FXFILL_WINDING; | |
742 path.m_ClipPath.AppendTexts(&pCopy, 1); | |
743 path.m_ColorState = textobj->m_ColorState; | |
744 path.m_Path.New()->AppendRect(textobj->m_Left, textobj->m_Bottom, | |
745 textobj->m_Right, textobj->m_Top); | |
746 path.m_Left = textobj->m_Left; | |
747 path.m_Bottom = textobj->m_Bottom; | |
748 path.m_Right = textobj->m_Right; | |
749 path.m_Top = textobj->m_Top; | |
750 RenderSingleObject(&path, pObj2Device); | |
751 return; | |
752 } | |
753 CFX_FontCache* pCache; | |
754 if (pFont->m_pDocument) { | |
755 pCache = pFont->m_pDocument->GetRenderData()->GetFontCache(); | |
756 } else { | |
757 pCache = CFX_GEModule::Get()->GetFontCache(); | |
758 } | |
759 CFX_FaceCache* pFaceCache = pCache->GetCachedFace(&pFont->m_Font); | |
760 FX_FONTCACHE_DEFINE(pCache, &pFont->m_Font); | |
761 CPDF_CharPosList CharPosList; | |
762 CharPosList.Load(textobj->m_nChars, textobj->m_pCharCodes, | |
763 textobj->m_pCharPos, pFont, font_size); | |
764 for (FX_DWORD i = 0; i < CharPosList.m_nChars; i++) { | |
765 FXTEXT_CHARPOS& charpos = CharPosList.m_pCharPos[i]; | |
766 const CFX_PathData* pPath = pFaceCache->LoadGlyphPath( | |
767 &pFont->m_Font, charpos.m_GlyphIndex, charpos.m_FontCharWidth); | |
768 if (!pPath) { | |
769 continue; | |
770 } | |
771 CPDF_PathObject path; | |
772 path.m_GraphState = textobj->m_GraphState; | |
773 path.m_ColorState = textobj->m_ColorState; | |
774 CFX_Matrix matrix; | |
775 if (charpos.m_bGlyphAdjust) | |
776 matrix.Set(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1], | |
777 charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0); | |
778 matrix.Concat(font_size, 0, 0, font_size, charpos.m_OriginX, | |
779 charpos.m_OriginY); | |
780 path.m_Path.New()->Append(pPath, &matrix); | |
781 path.m_Matrix = *pTextMatrix; | |
782 path.m_bStroke = bStroke; | |
783 path.m_FillType = bFill ? FXFILL_WINDING : 0; | |
784 path.CalcBoundingBox(); | |
785 ProcessPath(&path, pObj2Device); | |
786 } | |
787 } | |
788 | |
OLD | NEW |