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