| 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 |