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_type3cache.h" 8 9#include <map> 10#include <memory> 11#include <utility> 12 13#include "core/fpdfapi/font/cpdf_type3char.h" 14#include "core/fpdfapi/font/cpdf_type3font.h" 15#include "core/fpdfapi/render/cpdf_type3glyphs.h" 16#include "core/fxge/fx_dib.h" 17#include "core/fxge/fx_font.h" 18#include "third_party/base/ptr_util.h" 19 20namespace { 21 22struct CPDF_UniqueKeyGen { 23 void Generate(int count, ...); 24 char m_Key[128]; 25 int m_KeyLen; 26}; 27 28void CPDF_UniqueKeyGen::Generate(int count, ...) { 29 va_list argList; 30 va_start(argList, count); 31 for (int i = 0; i < count; i++) { 32 int p = va_arg(argList, int); 33 (reinterpret_cast<uint32_t*>(m_Key))[i] = p; 34 } 35 va_end(argList); 36 m_KeyLen = count * sizeof(uint32_t); 37} 38 39bool IsScanLine1bpp(uint8_t* pBuf, int width) { 40 int size = width / 8; 41 for (int i = 0; i < size; i++) { 42 if (pBuf[i]) 43 return true; 44 } 45 return (width % 8) && (pBuf[width / 8] & (0xff << (8 - width % 8))); 46} 47 48bool IsScanLine8bpp(uint8_t* pBuf, int width) { 49 for (int i = 0; i < width; i++) { 50 if (pBuf[i] > 0x40) 51 return true; 52 } 53 return false; 54} 55 56int DetectFirstLastScan(const RetainPtr<CFX_DIBitmap>& pBitmap, bool bFirst) { 57 int height = pBitmap->GetHeight(); 58 int pitch = pBitmap->GetPitch(); 59 int width = pBitmap->GetWidth(); 60 int bpp = pBitmap->GetBPP(); 61 if (bpp > 8) 62 width *= bpp / 8; 63 uint8_t* pBuf = pBitmap->GetBuffer(); 64 int line = bFirst ? 0 : height - 1; 65 int line_step = bFirst ? 1 : -1; 66 int line_end = bFirst ? height : -1; 67 while (line != line_end) { 68 if (bpp == 1) { 69 if (IsScanLine1bpp(pBuf + line * pitch, width)) 70 return line; 71 } else { 72 if (IsScanLine8bpp(pBuf + line * pitch, width)) 73 return line; 74 } 75 line += line_step; 76 } 77 return -1; 78} 79 80} // namespace 81 82CPDF_Type3Cache::CPDF_Type3Cache(CPDF_Type3Font* pFont) : m_pFont(pFont) {} 83 84CPDF_Type3Cache::~CPDF_Type3Cache() {} 85 86CFX_GlyphBitmap* CPDF_Type3Cache::LoadGlyph(uint32_t charcode, 87 const CFX_Matrix* pMatrix, 88 float retinaScaleX, 89 float retinaScaleY) { 90 CPDF_UniqueKeyGen keygen; 91 keygen.Generate( 92 4, FXSYS_round(pMatrix->a * 10000), FXSYS_round(pMatrix->b * 10000), 93 FXSYS_round(pMatrix->c * 10000), FXSYS_round(pMatrix->d * 10000)); 94 ByteString FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen); 95 CPDF_Type3Glyphs* pSizeCache; 96 auto it = m_SizeMap.find(FaceGlyphsKey); 97 if (it == m_SizeMap.end()) { 98 auto pNew = pdfium::MakeUnique<CPDF_Type3Glyphs>(); 99 pSizeCache = pNew.get(); 100 m_SizeMap[FaceGlyphsKey] = std::move(pNew); 101 } else { 102 pSizeCache = it->second.get(); 103 } 104 auto it2 = pSizeCache->m_GlyphMap.find(charcode); 105 if (it2 != pSizeCache->m_GlyphMap.end()) 106 return it2->second.get(); 107 108 std::unique_ptr<CFX_GlyphBitmap> pNewBitmap = 109 RenderGlyph(pSizeCache, charcode, pMatrix, retinaScaleX, retinaScaleY); 110 CFX_GlyphBitmap* pGlyphBitmap = pNewBitmap.get(); 111 pSizeCache->m_GlyphMap[charcode] = std::move(pNewBitmap); 112 return pGlyphBitmap; 113} 114 115std::unique_ptr<CFX_GlyphBitmap> CPDF_Type3Cache::RenderGlyph( 116 CPDF_Type3Glyphs* pSize, 117 uint32_t charcode, 118 const CFX_Matrix* pMatrix, 119 float retinaScaleX, 120 float retinaScaleY) { 121 const CPDF_Type3Char* pChar = m_pFont->LoadChar(charcode); 122 if (!pChar || !pChar->GetBitmap()) 123 return nullptr; 124 125 CFX_Matrix text_matrix(pMatrix->a, pMatrix->b, pMatrix->c, pMatrix->d, 0, 0); 126 CFX_Matrix image_matrix = pChar->matrix(); 127 image_matrix.Concat(text_matrix); 128 129 RetainPtr<CFX_DIBitmap> pBitmap = pChar->GetBitmap(); 130 RetainPtr<CFX_DIBitmap> pResBitmap; 131 int left = 0; 132 int top = 0; 133 if (fabs(image_matrix.b) < fabs(image_matrix.a) / 100 && 134 fabs(image_matrix.c) < fabs(image_matrix.d) / 100) { 135 int top_line = DetectFirstLastScan(pBitmap, true); 136 int bottom_line = DetectFirstLastScan(pBitmap, false); 137 if (top_line == 0 && bottom_line == pBitmap->GetHeight() - 1) { 138 float top_y = image_matrix.d + image_matrix.f; 139 float bottom_y = image_matrix.f; 140 bool bFlipped = top_y > bottom_y; 141 if (bFlipped) { 142 float temp = top_y; 143 top_y = bottom_y; 144 bottom_y = temp; 145 } 146 pSize->AdjustBlue(top_y, bottom_y, top_line, bottom_line); 147 pResBitmap = pBitmap->StretchTo( 148 static_cast<int>(FXSYS_round(image_matrix.a) * retinaScaleX), 149 static_cast<int>( 150 (bFlipped ? top_line - bottom_line : bottom_line - top_line) * 151 retinaScaleY), 152 0, nullptr); 153 top = top_line; 154 if (image_matrix.a < 0) { 155 image_matrix.Scale(retinaScaleX, retinaScaleY); 156 left = FXSYS_round(image_matrix.e + image_matrix.a); 157 } else { 158 left = FXSYS_round(image_matrix.e); 159 } 160 } 161 } 162 if (!pResBitmap) { 163 image_matrix.Scale(retinaScaleX, retinaScaleY); 164 pResBitmap = pBitmap->TransformTo(&image_matrix, &left, &top); 165 } 166 if (!pResBitmap) 167 return nullptr; 168 169 auto pGlyph = pdfium::MakeUnique<CFX_GlyphBitmap>(); 170 pGlyph->m_Left = left; 171 pGlyph->m_Top = -top; 172 pGlyph->m_pBitmap->TakeOver(std::move(pResBitmap)); 173 return pGlyph; 174} 175