OLD | NEW |
1 // Copyright 2014 PDFium Authors. All rights reserved. | 1 // Copyright 2014 PDFium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
6 | 6 |
7 #include "core/fpdfapi/fpdf_render/render_int.h" | 7 #include "core/fpdfapi/fpdf_render/render_int.h" |
8 | 8 |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
11 #include "core/fpdfapi/fpdf_font/cpdf_cidfont.h" | 11 #include "core/fpdfapi/fpdf_font/cpdf_cidfont.h" |
12 #include "core/fpdfapi/fpdf_font/cpdf_type3char.h" | 12 #include "core/fpdfapi/fpdf_font/cpdf_type3char.h" |
13 #include "core/fpdfapi/fpdf_font/cpdf_type3font.h" | 13 #include "core/fpdfapi/fpdf_font/cpdf_type3font.h" |
14 #include "core/fpdfapi/fpdf_font/include/cpdf_font.h" | 14 #include "core/fpdfapi/fpdf_font/include/cpdf_font.h" |
15 #include "core/fpdfapi/fpdf_page/include/cpdf_form.h" | 15 #include "core/fpdfapi/fpdf_page/include/cpdf_form.h" |
16 #include "core/fpdfapi/fpdf_page/include/cpdf_imageobject.h" | 16 #include "core/fpdfapi/fpdf_page/include/cpdf_imageobject.h" |
17 #include "core/fpdfapi/fpdf_page/include/cpdf_pageobject.h" | 17 #include "core/fpdfapi/fpdf_page/include/cpdf_pageobject.h" |
18 #include "core/fpdfapi/fpdf_page/include/cpdf_pathobject.h" | 18 #include "core/fpdfapi/fpdf_page/include/cpdf_pathobject.h" |
19 #include "core/fpdfapi/fpdf_page/include/cpdf_textobject.h" | 19 #include "core/fpdfapi/fpdf_page/include/cpdf_textobject.h" |
20 #include "core/fpdfapi/fpdf_page/pageint.h" | 20 #include "core/fpdfapi/fpdf_page/pageint.h" |
21 #include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h" | 21 #include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h" |
22 #include "core/fpdfapi/fpdf_parser/include/cpdf_document.h" | 22 #include "core/fpdfapi/fpdf_parser/include/cpdf_document.h" |
| 23 #include "core/fpdfapi/fpdf_render/cpdf_type3cache.h" |
23 #include "core/fpdfapi/fpdf_render/include/cpdf_renderoptions.h" | 24 #include "core/fpdfapi/fpdf_render/include/cpdf_renderoptions.h" |
24 #include "core/fpdfapi/fpdf_render/include/cpdf_textrenderer.h" | 25 #include "core/fpdfapi/fpdf_render/include/cpdf_textrenderer.h" |
25 #include "core/fxge/include/cfx_autofontcache.h" | 26 #include "core/fxge/include/cfx_autofontcache.h" |
26 #include "core/fxge/include/cfx_facecache.h" | 27 #include "core/fxge/include/cfx_facecache.h" |
27 #include "core/fxge/include/cfx_fontcache.h" | 28 #include "core/fxge/include/cfx_fontcache.h" |
28 #include "core/fxge/include/cfx_fxgedevice.h" | 29 #include "core/fxge/include/cfx_fxgedevice.h" |
29 #include "core/fxge/include/cfx_gemodule.h" | 30 #include "core/fxge/include/cfx_gemodule.h" |
30 #include "core/fxge/include/cfx_graphstatedata.h" | 31 #include "core/fxge/include/cfx_graphstatedata.h" |
31 #include "core/fxge/include/cfx_pathdata.h" | 32 #include "core/fxge/include/cfx_pathdata.h" |
32 #include "core/fxge/include/cfx_renderdevice.h" | 33 #include "core/fxge/include/cfx_renderdevice.h" |
33 | 34 |
34 namespace { | |
35 | |
36 struct CPDF_UniqueKeyGen { | |
37 void Generate(int count, ...); | |
38 FX_CHAR m_Key[128]; | |
39 int m_KeyLen; | |
40 }; | |
41 | |
42 void CPDF_UniqueKeyGen::Generate(int count, ...) { | |
43 va_list argList; | |
44 va_start(argList, count); | |
45 for (int i = 0; i < count; i++) { | |
46 int p = va_arg(argList, int); | |
47 ((uint32_t*)m_Key)[i] = p; | |
48 } | |
49 va_end(argList); | |
50 m_KeyLen = count * sizeof(uint32_t); | |
51 } | |
52 | |
53 } // namespace | |
54 | |
55 CPDF_Type3Cache::CPDF_Type3Cache(CPDF_Type3Font* pFont) : m_pFont(pFont) {} | |
56 | |
57 CPDF_Type3Cache::~CPDF_Type3Cache() { | |
58 for (const auto& pair : m_SizeMap) { | |
59 delete pair.second; | |
60 } | |
61 m_SizeMap.clear(); | |
62 } | |
63 | |
64 CFX_GlyphBitmap* CPDF_Type3Cache::LoadGlyph(uint32_t charcode, | |
65 const CFX_Matrix* pMatrix, | |
66 FX_FLOAT retinaScaleX, | |
67 FX_FLOAT retinaScaleY) { | |
68 CPDF_UniqueKeyGen keygen; | |
69 keygen.Generate( | |
70 4, FXSYS_round(pMatrix->a * 10000), FXSYS_round(pMatrix->b * 10000), | |
71 FXSYS_round(pMatrix->c * 10000), FXSYS_round(pMatrix->d * 10000)); | |
72 CFX_ByteString FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen); | |
73 CPDF_Type3Glyphs* pSizeCache; | |
74 auto it = m_SizeMap.find(FaceGlyphsKey); | |
75 if (it == m_SizeMap.end()) { | |
76 pSizeCache = new CPDF_Type3Glyphs; | |
77 m_SizeMap[FaceGlyphsKey] = pSizeCache; | |
78 } else { | |
79 pSizeCache = it->second; | |
80 } | |
81 auto it2 = pSizeCache->m_GlyphMap.find(charcode); | |
82 if (it2 != pSizeCache->m_GlyphMap.end()) | |
83 return it2->second; | |
84 | |
85 CFX_GlyphBitmap* pGlyphBitmap = | |
86 RenderGlyph(pSizeCache, charcode, pMatrix, retinaScaleX, retinaScaleY); | |
87 pSizeCache->m_GlyphMap[charcode] = pGlyphBitmap; | |
88 return pGlyphBitmap; | |
89 } | |
90 | |
91 CPDF_Type3Glyphs::CPDF_Type3Glyphs() | |
92 : m_TopBlueCount(0), m_BottomBlueCount(0) {} | |
93 | |
94 CPDF_Type3Glyphs::~CPDF_Type3Glyphs() { | |
95 for (const auto& pair : m_GlyphMap) | |
96 delete pair.second; | |
97 } | |
98 | |
99 static int _AdjustBlue(FX_FLOAT pos, int& count, int blues[]) { | |
100 FX_FLOAT min_distance = 1000000.0f * 1.0f; | |
101 int closest_pos = -1; | |
102 for (int i = 0; i < count; i++) { | |
103 FX_FLOAT distance = (FX_FLOAT)FXSYS_fabs(pos - (FX_FLOAT)blues[i]); | |
104 if (distance < 1.0f * 80.0f / 100.0f && distance < min_distance) { | |
105 min_distance = distance; | |
106 closest_pos = i; | |
107 } | |
108 } | |
109 if (closest_pos >= 0) { | |
110 return blues[closest_pos]; | |
111 } | |
112 int new_pos = FXSYS_round(pos); | |
113 if (count == TYPE3_MAX_BLUES) { | |
114 return new_pos; | |
115 } | |
116 blues[count++] = new_pos; | |
117 return new_pos; | |
118 } | |
119 void CPDF_Type3Glyphs::AdjustBlue(FX_FLOAT top, | |
120 FX_FLOAT bottom, | |
121 int& top_line, | |
122 int& bottom_line) { | |
123 top_line = _AdjustBlue(top, m_TopBlueCount, m_TopBlue); | |
124 bottom_line = _AdjustBlue(bottom, m_BottomBlueCount, m_BottomBlue); | |
125 } | |
126 | |
127 static FX_BOOL _IsScanLine1bpp(uint8_t* pBuf, int width) { | |
128 int size = width / 8; | |
129 for (int i = 0; i < size; i++) { | |
130 if (pBuf[i]) | |
131 return TRUE; | |
132 } | |
133 return (width % 8) && (pBuf[width / 8] & (0xff << (8 - width % 8))); | |
134 } | |
135 | |
136 static FX_BOOL _IsScanLine8bpp(uint8_t* pBuf, int width) { | |
137 for (int i = 0; i < width; i++) { | |
138 if (pBuf[i] > 0x40) | |
139 return TRUE; | |
140 } | |
141 return FALSE; | |
142 } | |
143 | |
144 static int _DetectFirstLastScan(const CFX_DIBitmap* pBitmap, FX_BOOL bFirst) { | |
145 int height = pBitmap->GetHeight(), pitch = pBitmap->GetPitch(), | |
146 width = pBitmap->GetWidth(); | |
147 int bpp = pBitmap->GetBPP(); | |
148 if (bpp > 8) { | |
149 width *= bpp / 8; | |
150 } | |
151 uint8_t* pBuf = pBitmap->GetBuffer(); | |
152 int line = bFirst ? 0 : height - 1; | |
153 int line_step = bFirst ? 1 : -1; | |
154 int line_end = bFirst ? height : -1; | |
155 while (line != line_end) { | |
156 if (bpp == 1) { | |
157 if (_IsScanLine1bpp(pBuf + line * pitch, width)) { | |
158 return line; | |
159 } | |
160 } else { | |
161 if (_IsScanLine8bpp(pBuf + line * pitch, width)) { | |
162 return line; | |
163 } | |
164 } | |
165 line += line_step; | |
166 } | |
167 return -1; | |
168 } | |
169 | |
170 CFX_GlyphBitmap* CPDF_Type3Cache::RenderGlyph(CPDF_Type3Glyphs* pSize, | |
171 uint32_t charcode, | |
172 const CFX_Matrix* pMatrix, | |
173 FX_FLOAT retinaScaleX, | |
174 FX_FLOAT retinaScaleY) { | |
175 const CPDF_Type3Char* pChar = m_pFont->LoadChar(charcode); | |
176 if (!pChar || !pChar->m_pBitmap) | |
177 return nullptr; | |
178 | |
179 CFX_DIBitmap* pBitmap = pChar->m_pBitmap.get(); | |
180 CFX_Matrix image_matrix, text_matrix; | |
181 image_matrix = pChar->m_ImageMatrix; | |
182 text_matrix.Set(pMatrix->a, pMatrix->b, pMatrix->c, pMatrix->d, 0, 0); | |
183 image_matrix.Concat(text_matrix); | |
184 std::unique_ptr<CFX_DIBitmap> pResBitmap; | |
185 int left = 0; | |
186 int top = 0; | |
187 if (FXSYS_fabs(image_matrix.b) < FXSYS_fabs(image_matrix.a) / 100 && | |
188 FXSYS_fabs(image_matrix.c) < FXSYS_fabs(image_matrix.d) / 100) { | |
189 int top_line = _DetectFirstLastScan(pBitmap, TRUE); | |
190 int bottom_line = _DetectFirstLastScan(pBitmap, FALSE); | |
191 if (top_line == 0 && bottom_line == pBitmap->GetHeight() - 1) { | |
192 FX_FLOAT top_y = image_matrix.d + image_matrix.f; | |
193 FX_FLOAT bottom_y = image_matrix.f; | |
194 FX_BOOL bFlipped = top_y > bottom_y; | |
195 if (bFlipped) { | |
196 FX_FLOAT temp = top_y; | |
197 top_y = bottom_y; | |
198 bottom_y = temp; | |
199 } | |
200 pSize->AdjustBlue(top_y, bottom_y, top_line, bottom_line); | |
201 pResBitmap.reset(pBitmap->StretchTo( | |
202 (int)(FXSYS_round(image_matrix.a) * retinaScaleX), | |
203 (int)((bFlipped ? top_line - bottom_line : bottom_line - top_line) * | |
204 retinaScaleY))); | |
205 top = top_line; | |
206 if (image_matrix.a < 0) { | |
207 image_matrix.Scale(retinaScaleX, retinaScaleY); | |
208 left = FXSYS_round(image_matrix.e + image_matrix.a); | |
209 } else { | |
210 left = FXSYS_round(image_matrix.e); | |
211 } | |
212 } | |
213 } | |
214 if (!pResBitmap) { | |
215 image_matrix.Scale(retinaScaleX, retinaScaleY); | |
216 pResBitmap.reset(pBitmap->TransformTo(&image_matrix, left, top)); | |
217 } | |
218 if (!pResBitmap) | |
219 return nullptr; | |
220 | |
221 CFX_GlyphBitmap* pGlyph = new CFX_GlyphBitmap; | |
222 pGlyph->m_Left = left; | |
223 pGlyph->m_Top = -top; | |
224 pGlyph->m_Bitmap.TakeOver(pResBitmap.get()); | |
225 return pGlyph; | |
226 } | |
227 | |
228 FX_BOOL CPDF_RenderStatus::ProcessText(const CPDF_TextObject* textobj, | 35 FX_BOOL CPDF_RenderStatus::ProcessText(const CPDF_TextObject* textobj, |
229 const CFX_Matrix* pObj2Device, | 36 const CFX_Matrix* pObj2Device, |
230 CFX_PathData* pClippingPath) { | 37 CFX_PathData* pClippingPath) { |
231 if (textobj->m_nChars == 0) | 38 if (textobj->m_nChars == 0) |
232 return TRUE; | 39 return TRUE; |
233 | 40 |
234 const TextRenderingMode text_render_mode = textobj->m_TextState.GetTextMode(); | 41 const TextRenderingMode text_render_mode = textobj->m_TextState.GetTextMode(); |
235 if (text_render_mode == TextRenderingMode::MODE_INVISIBLE) | 42 if (text_render_mode == TextRenderingMode::MODE_INVISIBLE) |
236 return TRUE; | 43 return TRUE; |
237 | 44 |
(...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
864 matrix.Concat(font_size, 0, 0, font_size, charpos.m_OriginX, | 671 matrix.Concat(font_size, 0, 0, font_size, charpos.m_OriginX, |
865 charpos.m_OriginY); | 672 charpos.m_OriginY); |
866 path.m_Path.Emplace()->Append(pPath, &matrix); | 673 path.m_Path.Emplace()->Append(pPath, &matrix); |
867 path.m_Matrix = *pTextMatrix; | 674 path.m_Matrix = *pTextMatrix; |
868 path.m_bStroke = bStroke; | 675 path.m_bStroke = bStroke; |
869 path.m_FillType = bFill ? FXFILL_WINDING : 0; | 676 path.m_FillType = bFill ? FXFILL_WINDING : 0; |
870 path.CalcBoundingBox(); | 677 path.CalcBoundingBox(); |
871 ProcessPath(&path, pObj2Device); | 678 ProcessPath(&path, pObj2Device); |
872 } | 679 } |
873 } | 680 } |
OLD | NEW |