void CPDF_TextObject::CalcCharPos(FX_FLOAT* pPosArray) const { CPDF_Font* pFont = m_TextState.GetFont(); FX_BOOL bVertWriting = FALSE; CPDF_CIDFont* pCIDFont = pFont->GetCIDFont(); if (pCIDFont) { bVertWriting = pCIDFont->IsVertWriting(); } FX_FLOAT fontsize = m_TextState.GetFontSize(); for (int i = 0, index = 0; i < m_nChars; ++i) { FX_DWORD charcode = m_nChars == 1 ? (FX_DWORD)(uintptr_t)m_pCharCodes : m_pCharCodes[i]; if (charcode == (FX_DWORD) - 1) { continue; } pPosArray[index++] = i ? m_pCharPos[i - 1] : 0; FX_FLOAT charwidth; if (bVertWriting) { FX_WORD CID = pCIDFont->CIDFromCharCode(charcode); charwidth = pCIDFont->GetVertWidth(CID) * fontsize / 1000; } else { charwidth = pFont->GetCharWidthF(charcode) * fontsize / 1000; } pPosArray[index] = pPosArray[index - 1] + charwidth; index++; } }
int Document::CountWords(CPDF_TextObject* pTextObj) { if (!pTextObj) return 0; int nWords = 0; CPDF_Font* pFont = pTextObj->GetFont(); if (!pFont) return 0; FX_BOOL bIsLatin = FALSE; for (int i=0, sz=pTextObj->CountChars(); i<sz; i++) { FX_DWORD charcode = -1; FX_FLOAT kerning; pTextObj->GetCharInfo(i, charcode, kerning); CFX_WideString swUnicode = pFont->UnicodeFromCharCode(charcode); FX_WORD unicode = 0; if (swUnicode.GetLength() > 0) unicode = swUnicode[0]; if (ISLATINWORD(unicode) && bIsLatin) continue; bIsLatin = ISLATINWORD(unicode); if (unicode != 0x20) nWords++; } return nWords; }
void CPDF_TextObject::GetItemInfo(int index, CPDF_TextObjectItem* pInfo) const { pInfo->m_CharCode = m_nChars == 1 ? (FX_DWORD)(uintptr_t)m_pCharCodes : m_pCharCodes[index]; pInfo->m_OriginX = index ? m_pCharPos[index - 1] : 0; pInfo->m_OriginY = 0; if (pInfo->m_CharCode == -1) { return; } CPDF_Font* pFont = m_TextState.GetFont(); if (pFont->GetFontType() != PDFFONT_CIDFONT) { return; } if (!((CPDF_CIDFont*)pFont)->IsVertWriting()) { return; } FX_WORD CID = ((CPDF_CIDFont*)pFont)->CIDFromCharCode(pInfo->m_CharCode); pInfo->m_OriginY = pInfo->m_OriginX; pInfo->m_OriginX = 0; short vx, vy; ((CPDF_CIDFont*)pFont)->GetVertOrigin(CID, vx, vy); FX_FLOAT fontsize = m_TextState.GetFontSize(); pInfo->m_OriginX -= fontsize * vx / 1000; pInfo->m_OriginY -= fontsize * vy / 1000; }
FPDFText_MarkedContent CPDF_TextPage::PreMarkedContent(PDFTEXT_Obj Obj) { CPDF_TextObject* pTextObj = Obj.m_pTextObj.Get(); size_t nContentMarks = pTextObj->m_ContentMarks.CountItems(); if (nContentMarks == 0) return FPDFText_MarkedContent::Pass; WideString actText; bool bExist = false; const CPDF_Dictionary* pDict = nullptr; for (size_t i = 0; i < nContentMarks; ++i) { const CPDF_ContentMarkItem* item = pTextObj->m_ContentMarks.GetItem(i); pDict = item->GetParam(); if (!pDict) continue; const CPDF_String* temp = ToString(pDict->GetObjectFor("ActualText")); if (temp) { bExist = true; actText = temp->GetUnicodeText(); } } if (!bExist) return FPDFText_MarkedContent::Pass; if (m_pPreTextObj) { const CPDF_ContentMarks& marks = m_pPreTextObj->m_ContentMarks; if (marks.CountItems() == nContentMarks && marks.GetItem(nContentMarks - 1)->GetParam() == pDict) { return FPDFText_MarkedContent::Done; } } if (actText.IsEmpty()) return FPDFText_MarkedContent::Pass; CPDF_Font* pFont = pTextObj->GetFont(); bExist = false; for (size_t i = 0; i < actText.GetLength(); ++i) { if (pFont->CharCodeFromUnicode(actText[i]) != CPDF_Font::kInvalidCharCode) { bExist = true; break; } } if (!bExist) return FPDFText_MarkedContent::Pass; bExist = false; for (size_t i = 0; i < actText.GetLength(); ++i) { wchar_t wChar = actText[i]; if ((wChar > 0x80 && wChar < 0xFFFD) || (wChar <= 0x80 && isprint(wChar))) { bExist = true; break; } } if (!bExist) return FPDFText_MarkedContent::Done; return FPDFText_MarkedContent::Delay; }
FX_FLOAT CPDF_TextObject::GetCharWidth(FX_DWORD charcode) const { FX_FLOAT fontsize = m_TextState.GetFontSize() / 1000; CPDF_Font* pFont = m_TextState.GetFont(); FX_BOOL bVertWriting = FALSE; CPDF_CIDFont* pCIDFont = pFont->GetCIDFont(); if (pCIDFont) { bVertWriting = pCIDFont->IsVertWriting(); } if (!bVertWriting) return pFont->GetCharWidthF(charcode, 0) * fontsize; FX_WORD CID = pCIDFont->CIDFromCharCode(charcode); return pCIDFont->GetVertWidth(CID) * fontsize; }
CPDF_Font* CPDF_StreamContentParser::FindFont(const CFX_ByteString& name) { CPDF_Dictionary* pFontDict = ToDictionary(FindResourceObj("Font", name)); if (!pFontDict) { m_bResourceMissing = TRUE; return CPDF_Font::GetStockFont(m_pDocument, "Helvetica"); } CPDF_Font* pFont = m_pDocument->LoadFont(pFontDict); if (pFont && pFont->GetType3Font()) { pFont->GetType3Font()->SetPageResources(m_pResources); pFont->GetType3Font()->CheckType3FontMetrics(); } return pFont; }
CPDF_Font* GetNativeInterFormFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, CFX_ByteString& csNameTag) { csNameTag.clear(); uint8_t charSet = CPDF_InterForm::GetNativeCharSet(); CPDF_Font* pFont = GetDefaultInterFormFont(pFormDict, pDocument); if (pFont) { CFX_SubstFont* pSubst = pFont->GetSubstFont(); if (pSubst && pSubst->m_Charset == (int)charSet) { FindInterFormFont(pFormDict, pFont, csNameTag); return pFont; } } return GetNativeInterFormFont(pFormDict, pDocument, charSet, csNameTag); }
CPDF_Font* GetNativeInterFormFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, CFX_ByteString& csNameTag) { csNameTag = ""; FX_BYTE charSet = CPDF_InterForm::GetNativeCharSet(); CFX_SubstFont* pSubst; CPDF_Font* pFont = GetDefaultInterFormFont(pFormDict, pDocument); if (pFont != NULL) { pSubst = (CFX_SubstFont*)pFont->GetSubstFont(); if (pSubst != NULL && pSubst->m_Charset == (int)charSet) { FindInterFormFont(pFormDict, pFont, csNameTag); return pFont; } } return GetNativeInterFormFont(pFormDict, pDocument, charSet, csNameTag); }
FX_FLOAT CPDF_TextObject::GetSpaceCharWidth() const { CPDF_Font* pFont = m_TextState.GetFont(); FX_DWORD charCode = m_TextState.GetFont()->CharCodeFromUnicode(32); if (charCode != (FX_DWORD)-1) { return GetCharWidth(charCode); } FX_FLOAT fontSize = m_TextState.GetFontSize() / 4000.0f; FX_BOOL bVertWriting = FALSE; CPDF_CIDFont* pCIDFont = pFont->GetCIDFont(); if (pCIDFont) { bVertWriting = pCIDFont->IsVertWriting(); } FX_RECT fontRect; pFont->GetFontBBox(fontRect); fontSize *= bVertWriting ? (FX_FLOAT)fontRect.Height() : (FX_FLOAT)fontRect.Width(); return fontSize; }
void CPDF_TextObject::GetCharRect(int index, CFX_FloatRect& rect) const { CPDF_Font* pFont = m_TextState.GetFont(); FX_BOOL bVertWriting = FALSE; CPDF_CIDFont* pCIDFont = pFont->GetCIDFont(); if (pCIDFont) { bVertWriting = pCIDFont->IsVertWriting(); } FX_FLOAT fontsize = m_TextState.GetFontSize() / 1000; int count = 0; for (int i = 0; i < m_nChars; ++i) { FX_DWORD charcode = m_nChars == 1 ? (FX_DWORD)(uintptr_t)m_pCharCodes : m_pCharCodes[i]; if (charcode == (FX_DWORD) - 1) { continue; } if (count != index) { ++count; continue; } FX_FLOAT curpos = i > 0 ? m_pCharPos[i - 1] : 0; FX_RECT char_rect; pFont->GetCharBBox(charcode, char_rect, 0); if (!bVertWriting) { rect.left = curpos + char_rect.left * fontsize; rect.right = curpos + char_rect.right * fontsize; rect.top = char_rect.top * fontsize; rect.bottom = char_rect.bottom * fontsize; } else { FX_WORD CID = pCIDFont->CIDFromCharCode(charcode); short vx, vy; pCIDFont->GetVertOrigin(CID, vx, vy); char_rect.left -= vx; char_rect.right -= vx; char_rect.top -= vy; char_rect.bottom -= vy; rect.left = char_rect.left * fontsize; rect.right = char_rect.right * fontsize; rect.top = curpos + char_rect.top * fontsize; rect.bottom = curpos + char_rect.bottom * fontsize; } return; } }
CPDF_Font* GetNativeInterFormFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, FX_BYTE charSet, CFX_ByteString& csNameTag) { if (pFormDict == NULL) { return NULL; } CPDF_Dictionary* pDR = pFormDict->GetDict("DR"); if (pDR == NULL) { return NULL; } CPDF_Dictionary* pFonts = pDR->GetDict("Font"); if (pFonts == NULL) { return NULL; } FX_POSITION pos = pFonts->GetStartPos(); while (pos) { CPDF_Object* pObj = NULL; CFX_ByteString csKey; pObj = pFonts->GetNextElement(pos, csKey); if (pObj == NULL) { continue; } CPDF_Object* pDirect = pObj->GetDirect(); if (pDirect == NULL || pDirect->GetType() != PDFOBJ_DICTIONARY) { continue; } CPDF_Dictionary* pElement = (CPDF_Dictionary*)pDirect; if (pElement->GetString("Type") != "Font") { continue; } CPDF_Font* pFind = pDocument->LoadFont(pElement); if (pFind == NULL) { continue; } CFX_SubstFont* pSubst = (CFX_SubstFont*)pFind->GetSubstFont(); if (pSubst == NULL) { continue; } if (pSubst->m_Charset == (int)charSet) { csNameTag = csKey; return pFind; } } return NULL; }
CPDF_Font* CBA_FontMap::FindResFontSameCharset(CPDF_Dictionary* pResDict, CFX_ByteString& sFontAlias, int32_t nCharset) { if (!pResDict) return NULL; CPDF_Document* pDocument = GetDocument(); ASSERT(pDocument != NULL); CPDF_Dictionary* pFonts = pResDict->GetDict("Font"); if (pFonts == NULL) return NULL; CPDF_Font* pFind = NULL; FX_POSITION pos = pFonts->GetStartPos(); while (pos) { CPDF_Object* pObj = NULL; CFX_ByteString csKey; pObj = pFonts->GetNextElement(pos, csKey); if (pObj == NULL) continue; CPDF_Object* pDirect = pObj->GetDirect(); if (pDirect == NULL || pDirect->GetType() != PDFOBJ_DICTIONARY) continue; CPDF_Dictionary* pElement = (CPDF_Dictionary*)pDirect; if (pElement->GetString("Type") != "Font") continue; CPDF_Font* pFont = pDocument->LoadFont(pElement); if (pFont == NULL) continue; const CFX_SubstFont* pSubst = pFont->GetSubstFont(); if (pSubst == NULL) continue; if (pSubst->m_Charset == nCharset) { sFontAlias = csKey; pFind = pFont; } } return pFind; }
void CPVT_FontMap::GetAnnotSysPDFFont(CPDF_Document* pDoc, const CPDF_Dictionary* pResDict, CPDF_Font*& pSysFont, CFX_ByteString& sSysFontAlias) { if (!pDoc || !pResDict) return; CFX_ByteString sFontAlias; CPDF_Dictionary* pFormDict = pDoc->GetRoot()->GetDictBy("AcroForm"); CPDF_Font* pPDFFont = AddNativeInterFormFont(pFormDict, pDoc, sSysFontAlias); if (!pPDFFont) return; if (CPDF_Dictionary* pFontList = pResDict->GetDictBy("Font")) { if (!pFontList->KeyExist(sSysFontAlias)) pFontList->SetAtReference(sSysFontAlias, pDoc, pPDFFont->GetFontDict()); } pSysFont = pPDFFont; }
CPDF_Font* GetInterFormFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, CFX_ByteString csFontName, CFX_ByteString& csNameTag) { if (pFormDict == NULL || csFontName.IsEmpty()) { return NULL; } CPDF_Dictionary* pDR = pFormDict->GetDict("DR"); if (pDR == NULL) { return NULL; } CPDF_Dictionary* pFonts = pDR->GetDict("Font"); if (pFonts == NULL) { return NULL; } FX_POSITION pos = pFonts->GetStartPos(); while (pos) { CPDF_Object* pObj = NULL; CFX_ByteString csKey; pObj = pFonts->GetNextElement(pos, csKey); if (pObj == NULL) { continue; } CPDF_Object* pDirect = pObj->GetDirect(); if (pDirect == NULL || pDirect->GetType() != PDFOBJ_DICTIONARY) { continue; } CPDF_Dictionary* pElement = (CPDF_Dictionary*)pDirect; if (pElement->GetString("Type") != "Font") { continue; } CPDF_Font* pFind = pDocument->LoadFont(pElement); if (pFind == NULL) { continue; } CFX_ByteString csBaseFont; csBaseFont = pFind->GetBaseFont(); csBaseFont.Remove(' '); if (csBaseFont == csFontName) { csNameTag = csKey; return pFind; } } return NULL; }
void CPDF_TextObject::SetSegments(const CFX_ByteString* pStrs, FX_FLOAT* pKerning, int nsegs) { if (m_nChars > 1 && m_pCharCodes) { FX_Free(m_pCharCodes); m_pCharCodes = nullptr; } if (m_pCharPos) { FX_Free(m_pCharPos); m_pCharPos = nullptr; } CPDF_Font* pFont = m_TextState.GetFont(); m_nChars = 0; for (int i = 0; i < nsegs; ++i) { m_nChars += pFont->CountChar(pStrs[i], pStrs[i].GetLength()); } m_nChars += nsegs - 1; if (m_nChars > 1) { m_pCharCodes = FX_Alloc(FX_DWORD, m_nChars); m_pCharPos = FX_Alloc(FX_FLOAT, m_nChars - 1); int index = 0; for (int i = 0; i < nsegs; ++i) { const FX_CHAR* segment = pStrs[i]; int offset = 0, len = pStrs[i].GetLength(); while (offset < len) { m_pCharCodes[index++] = pFont->GetNextChar(segment, len, offset); } if (i != nsegs - 1) { m_pCharPos[index - 1] = pKerning[i]; m_pCharCodes[index++] = (FX_DWORD) - 1; } } } else { int offset = 0; m_pCharCodes = (FX_DWORD*)(uintptr_t)pFont->GetNextChar(pStrs[0], pStrs[0].GetLength(), offset); } }
CPDF_Font* GetNativeInterFormFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, uint8_t charSet, CFX_ByteString& csNameTag) { if (!pFormDict) { return NULL; } CPDF_Dictionary* pDR = pFormDict->GetDict("DR"); if (!pDR) { return NULL; } CPDF_Dictionary* pFonts = pDR->GetDict("Font"); if (!pFonts) { return NULL; } for (const auto& it : *pFonts) { const CFX_ByteString& csKey = it.first; CPDF_Object* pObj = it.second; if (!pObj) { continue; } CPDF_Dictionary* pElement = ToDictionary(pObj->GetDirect()); if (!pElement) continue; if (pElement->GetString("Type") != "Font") continue; CPDF_Font* pFind = pDocument->LoadFont(pElement); if (!pFind) { continue; } CFX_SubstFont* pSubst = (CFX_SubstFont*)pFind->GetSubstFont(); if (!pSubst) { continue; } if (pSubst->m_Charset == (int)charSet) { csNameTag = csKey; return pFind; } } return NULL; }
CPDF_Font* GetInterFormFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, CFX_ByteString csFontName, CFX_ByteString& csNameTag) { if (!pFormDict || csFontName.IsEmpty()) { return NULL; } CPDF_Dictionary* pDR = pFormDict->GetDict("DR"); if (!pDR) { return NULL; } CPDF_Dictionary* pFonts = pDR->GetDict("Font"); if (!pFonts) { return NULL; } for (const auto& it : *pFonts) { const CFX_ByteString& csKey = it.first; CPDF_Object* pObj = it.second; if (!pObj) { continue; } CPDF_Dictionary* pElement = ToDictionary(pObj->GetDirect()); if (!pElement) continue; if (pElement->GetString("Type") != "Font") continue; CPDF_Font* pFind = pDocument->LoadFont(pElement); if (!pFind) continue; CFX_ByteString csBaseFont; csBaseFont = pFind->GetBaseFont(); csBaseFont.Remove(' '); if (csBaseFont == csFontName) { csNameTag = csKey; return pFind; } } return NULL; }
CFX_WideString Document::GetObjWordStr(CPDF_TextObject* pTextObj, int nWordIndex) { ASSERT(pTextObj != NULL); CFX_WideString swRet; CPDF_Font* pFont = pTextObj->GetFont(); if (!pFont) return L""; int nWords = 0; FX_BOOL bIsLatin = FALSE; for (int i=0, sz=pTextObj->CountChars(); i<sz; i++) { FX_DWORD charcode = -1; FX_FLOAT kerning; pTextObj->GetCharInfo(i, charcode, kerning); CFX_WideString swUnicode = pFont->UnicodeFromCharCode(charcode); FX_WORD unicode = 0; if (swUnicode.GetLength() > 0) unicode = swUnicode[0]; if (ISLATINWORD(unicode) && bIsLatin) { } else { bIsLatin = ISLATINWORD(unicode); if (unicode != 0x20) nWords++; } if (nWords-1 == nWordIndex) swRet += unicode; } return swRet; }
void CPDF_TextPage::ProcessMarkedContent(PDFTEXT_Obj Obj) { CPDF_TextObject* pTextObj = Obj.m_pTextObj.Get(); size_t nContentMarks = pTextObj->m_ContentMarks.CountItems(); if (nContentMarks == 0) return; WideString actText; for (size_t n = 0; n < nContentMarks; ++n) { const CPDF_ContentMarkItem* item = pTextObj->m_ContentMarks.GetItem(n); const CPDF_Dictionary* pDict = item->GetParam(); if (pDict) actText = pDict->GetUnicodeTextFor("ActualText"); } if (actText.IsEmpty()) return; CPDF_Font* pFont = pTextObj->GetFont(); CFX_Matrix matrix = pTextObj->GetTextMatrix() * Obj.m_formMatrix; for (size_t k = 0; k < actText.GetLength(); ++k) { wchar_t wChar = actText[k]; if (wChar <= 0x80 && !isprint(wChar)) wChar = 0x20; if (wChar >= 0xFFFD) continue; PAGECHAR_INFO charinfo; charinfo.m_Origin = pTextObj->GetPos(); charinfo.m_Index = m_TextBuf.GetLength(); charinfo.m_Unicode = wChar; charinfo.m_CharCode = pFont->CharCodeFromUnicode(wChar); charinfo.m_Flag = FPDFTEXT_CHAR_PIECE; charinfo.m_pTextObj = pTextObj; charinfo.m_CharBox = pTextObj->GetRect(); charinfo.m_Matrix = matrix; m_TempTextBuf.AppendChar(wChar); m_TempCharList.push_back(charinfo); } }
CPDF_Font* CBA_FontMap::FindResFontSameCharset(CPDF_Dictionary* pResDict, CFX_ByteString& sFontAlias, int32_t nCharset) { if (!pResDict) return nullptr; CPDF_Dictionary* pFonts = pResDict->GetDictBy("Font"); if (!pFonts) return nullptr; CPDF_Document* pDocument = GetDocument(); CPDF_Font* pFind = nullptr; for (const auto& it : *pFonts) { const CFX_ByteString& csKey = it.first; CPDF_Object* pObj = it.second; if (!pObj) continue; CPDF_Dictionary* pElement = ToDictionary(pObj->GetDirect()); if (!pElement) continue; if (pElement->GetStringBy("Type") != "Font") continue; CPDF_Font* pFont = pDocument->LoadFont(pElement); if (!pFont) continue; const CFX_SubstFont* pSubst = pFont->GetSubstFont(); if (!pSubst) continue; if (pSubst->m_Charset == nCharset) { sFontAlias = csKey; pFind = pFont; } } return pFind; }
CPDF_Font* CPDF_DocPageData::GetStandardFont(FX_BSTR fontName, CPDF_FontEncoding* pEncoding) { if (fontName.IsEmpty()) { return NULL; } FX_POSITION pos = m_FontMap.GetStartPosition(); while (pos) { CPDF_Dictionary* fontDict; CPDF_CountedObject<CPDF_Font*>* fontData; m_FontMap.GetNextAssoc(pos, fontDict, fontData); CPDF_Font* pFont = fontData->m_Obj; if (!pFont) { continue; } if (pFont->GetBaseFont() != fontName) { continue; } if (pFont->IsEmbedded()) { continue; } if (pFont->GetFontType() != PDFFONT_TYPE1) { continue; } if (pFont->GetFontDict()->KeyExist(FX_BSTRC("Widths"))) { continue; } CPDF_Type1Font* pT1Font = pFont->GetType1Font(); if (pEncoding && !pT1Font->GetEncoding()->IsIdentical(pEncoding)) { continue; } fontData->m_nCount ++; return pFont; } CPDF_Dictionary* pDict = FX_NEW CPDF_Dictionary; pDict->SetAtName(FX_BSTRC("Type"), FX_BSTRC("Font")); pDict->SetAtName(FX_BSTRC("Subtype"), FX_BSTRC("Type1")); pDict->SetAtName(FX_BSTRC("BaseFont"), fontName); if (pEncoding) { pDict->SetAt(FX_BSTRC("Encoding"), pEncoding->Realize()); } m_pPDFDoc->AddIndirectObject(pDict); CPDF_CountedObject<CPDF_Font*>* fontData = FX_NEW CPDF_CountedObject<CPDF_Font*>; if (!fontData) { return NULL; } CPDF_Font* pFont = CPDF_Font::CreateFontF(m_pPDFDoc, pDict); if (!pFont) { delete fontData; return NULL; } fontData->m_nCount = 2; fontData->m_Obj = pFont; m_FontMap.SetAt(pDict, fontData); return pFont; }
CPDF_Font* CPDF_DocPageData::GetStandardFont(const CFX_ByteStringC& fontName, CPDF_FontEncoding* pEncoding) { if (fontName.IsEmpty()) return nullptr; for (auto& it : m_FontMap) { CPDF_CountedFont* fontData = it.second; CPDF_Font* pFont = fontData->get(); if (!pFont) continue; if (pFont->GetBaseFont() != fontName) continue; if (pFont->IsEmbedded()) continue; if (!pFont->IsType1Font()) continue; if (pFont->GetFontDict()->KeyExist("Widths")) continue; CPDF_Type1Font* pT1Font = pFont->AsType1Font(); if (pEncoding && !pT1Font->GetEncoding()->IsIdentical(pEncoding)) continue; return fontData->AddRef(); } CPDF_Dictionary* pDict = new CPDF_Dictionary; pDict->SetAtName("Type", "Font"); pDict->SetAtName("Subtype", "Type1"); pDict->SetAtName("BaseFont", fontName); if (pEncoding) { pDict->SetAt("Encoding", pEncoding->Realize()); } m_pPDFDoc->AddIndirectObject(pDict); CPDF_Font* pFont = CPDF_Font::CreateFontF(m_pPDFDoc, pDict); if (!pFont) { return nullptr; } CPDF_CountedFont* fontData = new CPDF_CountedFont(pFont); m_FontMap[pDict] = fontData; return fontData->AddRef(); }
FX_BOOL CPDF_RenderStatus::ProcessText(const CPDF_TextObject* textobj, const CFX_AffineMatrix* pObj2Device, CFX_PathData* pClippingPath) { if(textobj->m_nChars == 0) { return TRUE; } int text_render_mode = textobj->m_TextState.GetObject()->m_TextMode; if (text_render_mode == 3) { return TRUE; } CPDF_Font* pFont = textobj->m_TextState.GetFont(); if (pFont->GetFontType() == PDFFONT_TYPE3) { return ProcessType3Text(textobj, pObj2Device); } FX_BOOL bFill = FALSE, bStroke = FALSE, bClip = FALSE; if (pClippingPath) { bClip = TRUE; } else { switch (text_render_mode) { case 0: case 4: bFill = TRUE; break; case 1: case 5: if (pFont->GetFace() == NULL && !(pFont->GetSubstFont()->m_SubstFlags & FXFONT_SUBST_GLYPHPATH)) { bFill = TRUE; } else { bStroke = TRUE; } break; case 2: case 6: if (pFont->GetFace() == NULL && !(pFont->GetSubstFont()->m_SubstFlags & FXFONT_SUBST_GLYPHPATH)) { bFill = TRUE; } else { bFill = bStroke = TRUE; } break; case 3: case 7: return TRUE; default: bFill = TRUE; } } FX_ARGB stroke_argb = 0, fill_argb = 0; FX_BOOL bPattern = FALSE; if (bStroke) { if (textobj->m_ColorState.GetStrokeColor()->IsPattern()) { bPattern = TRUE; } else { stroke_argb = GetStrokeArgb(textobj); } } if (bFill) { if (textobj->m_ColorState.GetFillColor()->IsPattern()) { bPattern = TRUE; } else { fill_argb = GetFillArgb(textobj); } } CFX_AffineMatrix text_matrix; textobj->GetTextMatrix(&text_matrix); if(IsAvailableMatrix(text_matrix) == FALSE) { return TRUE; } FX_FLOAT font_size = textobj->m_TextState.GetFontSize(); if (bPattern) { DrawTextPathWithPattern(textobj, pObj2Device, pFont, font_size, &text_matrix, bFill, bStroke); return TRUE; } #if defined(_FPDFAPI_MINI_) if (bFill) { bStroke = FALSE; } if (bStroke) { if (font_size * text_matrix.GetXUnit() * pObj2Device->GetXUnit() < 6) { bStroke = FALSE; } } #endif if (bClip || bStroke) { const CFX_AffineMatrix* pDeviceMatrix = pObj2Device; CFX_AffineMatrix device_matrix; if (bStroke) { const FX_FLOAT* pCTM = textobj->m_TextState.GetObject()->m_CTM; if (pCTM[0] != 1.0f || pCTM[3] != 1.0f) { CFX_AffineMatrix ctm(pCTM[0], pCTM[1], pCTM[2], pCTM[3], 0, 0); text_matrix.ConcatInverse(ctm); device_matrix.Copy(ctm); device_matrix.Concat(*pObj2Device); pDeviceMatrix = &device_matrix; } } int flag = 0; if (bStroke && bFill) { flag |= FX_FILL_STROKE; flag |= FX_STROKE_TEXT_MODE; } #if !defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) const CPDF_GeneralStateData* pGeneralData = ((CPDF_PageObject*)textobj)->m_GeneralState; if (pGeneralData && pGeneralData->m_StrokeAdjust) { flag |= FX_STROKE_ADJUST; } #endif if (m_Options.m_Flags & RENDER_NOTEXTSMOOTH) { flag |= FXFILL_NOPATHSMOOTH; } return CPDF_TextRenderer::DrawTextPath(m_pDevice, textobj->m_nChars, textobj->m_pCharCodes, textobj->m_pCharPos, pFont, font_size, &text_matrix, pDeviceMatrix, textobj->m_GraphState, fill_argb, stroke_argb, pClippingPath, flag); } text_matrix.Concat(*pObj2Device); return CPDF_TextRenderer::DrawNormalText(m_pDevice, textobj->m_nChars, textobj->m_pCharCodes, textobj->m_pCharPos, pFont, font_size, &text_matrix, fill_argb, &m_Options); }
FX_BOOL CPDF_TextStream::ProcessObject(const CPDF_TextObject* pObj, FX_BOOL bFirstLine) { CPDF_Font* pFont = pObj->GetFont(); CFX_AffineMatrix matrix; pObj->GetTextMatrix(&matrix); int item_index = 0; if (m_pLastObj) { int result = FPDFText_ProcessInterObj(m_pLastObj, pObj); if (result == 2) { int len = m_Buffer.GetLength(); if (len && m_bUseLF && m_Buffer.GetBuffer()[len - 1] == L'-') { m_Buffer.Delete(len - 1, 1); if (m_pObjArray) { m_pObjArray->RemoveAt((len - 1) * 2, 2); } } else { if (bFirstLine) { return TRUE; } if (m_bUseLF) { m_Buffer.AppendChar(L'\r'); m_Buffer.AppendChar(L'\n'); if (m_pObjArray) { for (int i = 0; i < 4; i ++) { m_pObjArray->Add(NULL); } } } else { m_Buffer.AppendChar(' '); if (m_pObjArray) { m_pObjArray->Add(NULL); m_pObjArray->Add(NULL); } } } } else if (result == 1) { m_Buffer.AppendChar(L' '); if (m_pObjArray) { m_pObjArray->Add(NULL); m_pObjArray->Add(NULL); } } else if (result == -1) { m_pLastObj = pObj; return FALSE; } else if (result == 3) { item_index = 1; } } m_pLastObj = pObj; int nItems = pObj->CountItems(); FX_FLOAT Ignorekerning = 0; for(int i = 1; i < nItems - 1; i += 2) { CPDF_TextObjectItem item; pObj->GetItemInfo(i, &item); if (item.m_CharCode == (FX_DWORD) - 1) { if(i == 1) { Ignorekerning = item.m_OriginX; } else if(Ignorekerning > item.m_OriginX) { Ignorekerning = item.m_OriginX; } } else { Ignorekerning = 0; break; } } FX_FLOAT spacing = 0; for (; item_index < nItems; item_index ++) { CPDF_TextObjectItem item; pObj->GetItemInfo(item_index, &item); if (item.m_CharCode == (FX_DWORD) - 1) { CFX_WideString wstr = m_Buffer.GetWideString(); if (wstr.IsEmpty() || wstr.GetAt(wstr.GetLength() - 1) == L' ') { continue; } FX_FLOAT fontsize_h = pObj->m_TextState.GetFontSizeH(); spacing = -fontsize_h * (item.m_OriginX - Ignorekerning) / 1000; continue; } FX_FLOAT charSpace = pObj->m_TextState.GetObject()->m_CharSpace; if(nItems > 3 && !spacing) { charSpace = 0; } if((spacing || charSpace) && item_index > 0) { int last_width = 0; FX_FLOAT fontsize_h = pObj->m_TextState.GetFontSizeH(); FX_DWORD space_charcode = pFont->CharCodeFromUnicode(' '); FX_FLOAT threshold = 0; if (space_charcode != -1) { threshold = fontsize_h * pFont->GetCharWidthF(space_charcode) / 1000 ; } if(threshold > fontsize_h / 3) { threshold = 0; } else { threshold /= 2; } if (threshold == 0) { threshold = fontsize_h; int this_width = FXSYS_abs(GetCharWidth(item.m_CharCode, pFont)); threshold = this_width > last_width ? (FX_FLOAT)this_width : (FX_FLOAT)last_width; int nDivide = 6; if (threshold < 300) { nDivide = 2; } else if (threshold < 500) { nDivide = 4; } else if (threshold < 700) { nDivide = 5; } threshold = threshold / nDivide; threshold = fontsize_h * threshold / 1000; } if(charSpace > 0.001) { spacing += matrix.TransformDistance(charSpace); } else if(charSpace < -0.001) { spacing -= matrix.TransformDistance(FXSYS_fabs(charSpace)); } if (threshold && (spacing && spacing >= threshold) ) { m_Buffer.AppendChar(L' '); if (m_pObjArray) { m_pObjArray->Add(NULL); m_pObjArray->Add(NULL); } } if (item.m_CharCode == (FX_DWORD) - 1) { continue; } spacing = 0; } CFX_WideString unicode_str = pFont->UnicodeFromCharCode(item.m_CharCode); if (unicode_str.IsEmpty()) { m_Buffer.AppendChar((FX_WCHAR)item.m_CharCode); if (m_pObjArray) { m_pObjArray->Add((void*)pObj); m_pObjArray->Add((void*)(FX_INTPTR)item_index); } } else { m_Buffer << unicode_str; if (m_pObjArray) { for (int i = 0; i < unicode_str.GetLength(); i ++) { m_pObjArray->Add((void*)pObj); m_pObjArray->Add((void*)(FX_INTPTR)item_index); } } } } return FALSE; }
void CPDF_ProgressiveReflowPageRender::Display(IFX_Pause* pPause) { if (NULL == m_pReflowPage) { m_Status = Done; return; } FX_RECT clipBox = m_pFXDevice->GetClipBox(); int size = m_pReflowPage->m_pReflowed->GetSize(); if (size < 1 || NULL == m_pDisplayMatrix) { m_Status = Done; return; } for(int i = m_CurrNum; i < size; i++) { CRF_Data* pData = (*m_pReflowPage->m_pReflowed)[i]; if(!pData) { continue; } CFX_FloatRect rect (pData->m_PosX, pData->m_PosY + pData->m_Height, pData->m_PosX + pData->m_Width, pData->m_PosY); m_pDisplayMatrix->TransformRect(rect); if(rect.left > clipBox.right || rect.right < clipBox.left || rect.bottom > clipBox.bottom || rect.top < clipBox.top) { continue; } if(pData->GetType() == CRF_Data::Text) { CRF_CharData* pCharData = (CRF_CharData*)pData; CPDF_Font* pPDFFont = pCharData->m_pCharState->m_pFont; if(pPDFFont->GetFontType() == PDFFONT_TYPE3) { continue; } FX_FLOAT x = pData->m_PosX, y = pData->m_PosY - pCharData->m_pCharState->m_fDescent; FXTEXT_CHARPOS charpos ; charpos.m_GlyphIndex = pPDFFont->GlyphFromCharCode(pCharData->m_CharCode); charpos.m_FontCharWidth = pPDFFont->m_Font.GetGlyphWidth(charpos.m_GlyphIndex); charpos.m_OriginX = x; charpos.m_OriginY = y; FX_FLOAT charW = pData->m_Width * 1000 / pData->m_Height; if(charW != charpos.m_FontCharWidth) { charpos.m_bGlyphAdjust = TRUE; charpos.m_AdjustMatrix[0] = charW / charpos.m_FontCharWidth; charpos.m_AdjustMatrix[1] = 0; charpos.m_AdjustMatrix[2] = 0; charpos.m_AdjustMatrix[3] = 1; } else { charpos.m_bGlyphAdjust = FALSE; } FX_BOOL bRet = FALSE; if(m_DisplayColor == -1) bRet = m_pFXDevice->DrawNormalText(1, &charpos, &(pPDFFont->m_Font), NULL, pCharData->m_pCharState->m_fFontSize, m_pDisplayMatrix, pCharData->m_pCharState->m_Color + 0xff000000, FXTEXT_CLEARTYPE); else bRet = m_pFXDevice->DrawNormalText(1, &charpos, &(pPDFFont->m_Font), NULL, pCharData->m_pCharState->m_fFontSize, m_pDisplayMatrix, m_DisplayColor, FXTEXT_CLEARTYPE); } else if(pData->GetType() == CRF_Data::Image) { CRF_ImageData* pImageData = (CRF_ImageData*)pData; if(!pImageData->m_pBitmap) { continue; } int left = 0, top = 0; CFX_DIBitmap* pDiBmp = NULL; CFX_DIBSource* pDispSource = pImageData->m_pBitmap; if(pImageData->m_Matrix.d < 0) { CFX_AffineMatrix matrix(pImageData->m_Matrix.a, 0, 0, -pImageData->m_Matrix.d, 0, 0); int left, top; pDiBmp = pImageData->m_pBitmap->TransformTo(&matrix, left, top); pDispSource = pDiBmp; } if (NULL == pDispSource) { continue; } if (pDispSource->GetFormat() == FXDIB_1bppMask || pDispSource->GetFormat() == FXDIB_8bppMask) { m_pFXDevice->StretchBitMask(pDispSource, (int)(rect.left + 0.5), (int)(rect.bottom + 0.5), (int)(rect.Width() + 0.5), (int)(rect.Height() + 0.5), 0xff000000); } else { m_pFXDevice->StretchDIBits(pDispSource, (int)(rect.left + 0.5), (int)(rect.bottom + 0.5), (int)(rect.Width() + 0.5), (int)(rect.Height() + 0.5)); } if(m_pFXDevice->GetBitmap() && m_pFXDevice->GetBitmap()->GetFormat() == FXDIB_8bppRgb && m_pFXDevice->GetBitmap()->GetPalette() == NULL) { int nPalette = 0; switch(m_DitherBits) { case 0: nPalette = 0; break; case 1: nPalette = 2; break; case 2: nPalette = 4; break; case 3: nPalette = 8; break; case 4: nPalette = 16; break; case 5: nPalette = 32; break; case 6: nPalette = 64; break; case 7: nPalette = 128; break; default: nPalette = 256; break; } if(nPalette >= 2) { FX_ARGB * palette = FX_Alloc(FX_ARGB, nPalette); nPalette --; palette[0] = 0; palette[nPalette] = 255; FX_FLOAT Dither = (FX_FLOAT)255 / (nPalette); for(int i = 1; i < nPalette; i++) { palette[i] = (FX_ARGB)(Dither * i + 0.5); } FX_RECT tmpRect = rect.GetOutterRect(); m_pFXDevice->GetBitmap()->DitherFS(palette, nPalette + 1, &tmpRect); FX_Free (palette); } } if(pDiBmp) { delete pDiBmp; } } else if(pData->GetType() == CRF_Data::Path) { } if(!(i % 10)) { if(pPause && pPause->NeedToPauseNow()) { i++; m_CurrNum = i; m_Status = ToBeContinued; return; } } } m_CurrNum = size; m_Status = Done; }
void CPDF_StreamContentParser::AddTextObject(CFX_ByteString* pStrs, FX_FLOAT fInitKerning, FX_FLOAT* pKerning, int nsegs) { CPDF_Font* pFont = m_pCurStates->m_TextState.GetFont(); if (!pFont) { return; } if (fInitKerning != 0) { if (!pFont->IsVertWriting()) { m_pCurStates->m_TextX -= FXSYS_Mul(fInitKerning, m_pCurStates->m_TextState.GetFontSize()) / 1000; } else { m_pCurStates->m_TextY -= FXSYS_Mul(fInitKerning, m_pCurStates->m_TextState.GetFontSize()) / 1000; } } if (nsegs == 0) { return; } int textmode; if (pFont->GetFontType() == PDFFONT_TYPE3) { textmode = 0; } else { textmode = m_pCurStates->m_TextState.GetObject()->m_TextMode; } CPDF_TextObject* pText = new CPDF_TextObject; m_pLastTextObject = pText; SetGraphicStates(pText, TRUE, TRUE, TRUE); if (textmode && textmode != 3 && textmode != 4 && textmode != 7) { FX_FLOAT* pCTM = pText->m_TextState.GetModify()->m_CTM; pCTM[0] = m_pCurStates->m_CTM.a; pCTM[1] = m_pCurStates->m_CTM.c; pCTM[2] = m_pCurStates->m_CTM.b; pCTM[3] = m_pCurStates->m_CTM.d; } pText->SetSegments(pStrs, pKerning, nsegs); pText->m_PosX = m_pCurStates->m_TextX; pText->m_PosY = m_pCurStates->m_TextY + m_pCurStates->m_TextRise; ConvertTextSpace(pText->m_PosX, pText->m_PosY); FX_FLOAT x_advance, y_advance; pText->CalcPositionData(&x_advance, &y_advance, m_pCurStates->m_TextHorzScale, m_Level); m_pCurStates->m_TextX += x_advance; m_pCurStates->m_TextY += y_advance; if (textmode > 3) { CPDF_TextObject* pCopy = new CPDF_TextObject; pCopy->Copy(pText); m_ClipTextList.Add(pCopy); } m_pObjectList->m_ObjectList.AddTail(pText); if (pKerning && pKerning[nsegs - 1] != 0) { if (!pFont->IsVertWriting()) { m_pCurStates->m_TextX -= FXSYS_Mul(pKerning[nsegs - 1], m_pCurStates->m_TextState.GetFontSize()) / 1000; } else { m_pCurStates->m_TextY -= FXSYS_Mul(pKerning[nsegs - 1], m_pCurStates->m_TextState.GetFontSize()) / 1000; } } }
void CTextPage::ProcessObject(CPDF_PageObject* pObject) { if (pObject->m_Type != PDFPAGE_TEXT) { return; } CPDF_TextObject* pText = (CPDF_TextObject*)pObject; CPDF_Font* pFont = pText->m_TextState.GetFont(); int count = pText->CountItems(); FX_FLOAT* pPosArray = FX_Alloc(FX_FLOAT, count * 2); if (pPosArray) { pText->CalcCharPos(pPosArray); } FX_FLOAT fontsize_h = pText->m_TextState.GetFontSizeH(); FX_FLOAT fontsize_v = pText->m_TextState.GetFontSizeV(); FX_DWORD space_charcode = pFont->CharCodeFromUnicode(' '); FX_FLOAT spacew = 0; if (space_charcode != -1) { spacew = fontsize_h * pFont->GetCharWidthF(space_charcode) / 1000; } if (spacew == 0) { spacew = fontsize_h / 4; } if (pText->m_TextState.GetBaselineAngle() != 0) { int cc = 0; CFX_AffineMatrix matrix; pText->GetTextMatrix(&matrix); for (int i = 0; i < pText->m_nChars; i ++) { FX_DWORD charcode = pText->m_nChars == 1 ? (FX_DWORD)(FX_UINTPTR)pText->m_pCharCodes : pText->m_pCharCodes[i]; if (charcode == (FX_DWORD) - 1) { continue; } FX_RECT char_box; pFont->GetCharBBox(charcode, char_box); FX_FLOAT char_left = pPosArray ? pPosArray[cc * 2] : char_box.left * pText->m_TextState.GetFontSize() / 1000; FX_FLOAT char_right = pPosArray ? pPosArray[cc * 2 + 1] : char_box.right * pText->m_TextState.GetFontSize() / 1000; FX_FLOAT char_top = char_box.top * pText->m_TextState.GetFontSize() / 1000; FX_FLOAT char_bottom = char_box.bottom * pText->m_TextState.GetFontSize() / 1000; cc ++; FX_FLOAT char_origx, char_origy; matrix.Transform(char_left, 0, char_origx, char_origy); matrix.TransformRect(char_left, char_right, char_top, char_bottom); CFX_ByteString str; pFont->AppendChar(str, charcode); InsertTextBox(NULL, char_origy, char_left, char_right, char_top, char_bottom, spacew, fontsize_v, str, pFont); } if (pPosArray) { FX_Free(pPosArray); } return; } FX_FLOAT ratio_h = fontsize_h / pText->m_TextState.GetFontSize(); for (int ii = 0; ii < count * 2; ii ++) { pPosArray[ii] *= ratio_h; } FX_FLOAT baseline = pText->m_PosY; CTextBaseLine* pBaseLine = NULL; FX_FLOAT topy = pText->m_Top; FX_FLOAT bottomy = pText->m_Bottom; FX_FLOAT leftx = pText->m_Left; int cc = 0; CFX_ByteString segment; int space_count = 0; FX_FLOAT last_left = 0, last_right = 0, segment_left = 0, segment_right = 0; for (int i = 0; i < pText->m_nChars; i ++) { FX_DWORD charcode = pText->m_nChars == 1 ? (FX_DWORD)(FX_UINTPTR)pText->m_pCharCodes : pText->m_pCharCodes[i]; if (charcode == (FX_DWORD) - 1) { continue; } FX_FLOAT char_left = pPosArray[cc * 2]; FX_FLOAT char_right = pPosArray[cc * 2 + 1]; cc ++; if (char_left < last_left || (char_left - last_right) > spacew / 2) { pBaseLine = InsertTextBox(pBaseLine, baseline, leftx + segment_left, leftx + segment_right, topy, bottomy, spacew, fontsize_v, segment, pFont); segment_left = char_left; segment = ""; } if (space_count > 1) { pBaseLine = InsertTextBox(pBaseLine, baseline, leftx + segment_left, leftx + segment_right, topy, bottomy, spacew, fontsize_v, segment, pFont); segment = ""; } else if (space_count == 1) { pFont->AppendChar(segment, ' '); } if (segment.GetLength() == 0) { segment_left = char_left; } segment_right = char_right; pFont->AppendChar(segment, charcode); space_count = 0; last_left = char_left; last_right = char_right; } if (segment.GetLength()) pBaseLine = InsertTextBox(pBaseLine, baseline, leftx + segment_left, leftx + segment_right, topy, bottomy, spacew, fontsize_v, segment, pFont); FX_Free(pPosArray); }
void CPDF_TextObject::CalcPositionData(FX_FLOAT* pTextAdvanceX, FX_FLOAT* pTextAdvanceY, FX_FLOAT horz_scale, int level) { FX_FLOAT curpos = 0; FX_FLOAT min_x = 10000 * 1.0f; FX_FLOAT max_x = -10000 * 1.0f; FX_FLOAT min_y = 10000 * 1.0f; FX_FLOAT max_y = -10000 * 1.0f; CPDF_Font* pFont = m_TextState.GetFont(); FX_BOOL bVertWriting = FALSE; CPDF_CIDFont* pCIDFont = pFont->GetCIDFont(); if (pCIDFont) { bVertWriting = pCIDFont->IsVertWriting(); } FX_FLOAT fontsize = m_TextState.GetFontSize(); for (int i = 0; i < m_nChars; ++i) { FX_DWORD charcode = m_nChars == 1 ? (FX_DWORD)(uintptr_t)m_pCharCodes : m_pCharCodes[i]; if (charcode == (FX_DWORD) - 1) { curpos -= FXSYS_Mul(m_pCharPos[i - 1], fontsize) / 1000; continue; } if (i) { m_pCharPos[i - 1] = curpos; } FX_RECT char_rect; pFont->GetCharBBox(charcode, char_rect, level); FX_FLOAT charwidth; if (!bVertWriting) { if (min_y > char_rect.top) { min_y = (FX_FLOAT)char_rect.top; } if (max_y < char_rect.top) { max_y = (FX_FLOAT)char_rect.top; } if (min_y > char_rect.bottom) { min_y = (FX_FLOAT)char_rect.bottom; } if (max_y < char_rect.bottom) { max_y = (FX_FLOAT)char_rect.bottom; } FX_FLOAT char_left = curpos + char_rect.left * fontsize / 1000; FX_FLOAT char_right = curpos + char_rect.right * fontsize / 1000; if (min_x > char_left) { min_x = char_left; } if (max_x < char_left) { max_x = char_left; } if (min_x > char_right) { min_x = char_right; } if (max_x < char_right) { max_x = char_right; } charwidth = pFont->GetCharWidthF(charcode, level) * fontsize / 1000; } else { FX_WORD CID = pCIDFont->CIDFromCharCode(charcode); short vx; short vy; pCIDFont->GetVertOrigin(CID, vx, vy); char_rect.left -= vx; char_rect.right -= vx; char_rect.top -= vy; char_rect.bottom -= vy; if (min_x > char_rect.left) { min_x = (FX_FLOAT)char_rect.left; } if (max_x < char_rect.left) { max_x = (FX_FLOAT)char_rect.left; } if (min_x > char_rect.right) { min_x = (FX_FLOAT)char_rect.right; } if (max_x < char_rect.right) { max_x = (FX_FLOAT)char_rect.right; } FX_FLOAT char_top = curpos + char_rect.top * fontsize / 1000; FX_FLOAT char_bottom = curpos + char_rect.bottom * fontsize / 1000; if (min_y > char_top) { min_y = char_top; } if (max_y < char_top) { max_y = char_top; } if (min_y > char_bottom) { min_y = char_bottom; } if (max_y < char_bottom) { max_y = char_bottom; } charwidth = pCIDFont->GetVertWidth(CID) * fontsize / 1000; } curpos += charwidth; if (charcode == ' ' && (!pCIDFont || pCIDFont->GetCharSize(32) == 1)) { curpos += m_TextState.GetObject()->m_WordSpace; } curpos += m_TextState.GetObject()->m_CharSpace; } if (bVertWriting) { if (pTextAdvanceX) { *pTextAdvanceX = 0; } if (pTextAdvanceY) { *pTextAdvanceY = curpos; } min_x = min_x * fontsize / 1000; max_x = max_x * fontsize / 1000; } else { if (pTextAdvanceX) { *pTextAdvanceX = FXSYS_Mul(curpos, horz_scale); } if (pTextAdvanceY) { *pTextAdvanceY = 0; } min_y = min_y * fontsize / 1000; max_y = max_y * fontsize / 1000; } CFX_AffineMatrix matrix; GetTextMatrix(&matrix); m_Left = min_x; m_Right = max_x; m_Bottom = min_y; m_Top = max_y; matrix.TransformRect(m_Left, m_Right, m_Top, m_Bottom); int textmode = m_TextState.GetObject()->m_TextMode; if (textmode == 1 || textmode == 2 || textmode == 5 || textmode == 6) { FX_FLOAT half_width = m_GraphState.GetObject()->m_LineWidth / 2; m_Left -= half_width; m_Right += half_width; m_Top += half_width; m_Bottom -= half_width; } }
void CPDF_TextPage::ProcessTextObject(PDFTEXT_Obj Obj) { CPDF_TextObject* pTextObj = Obj.m_pTextObj.Get(); if (fabs(pTextObj->GetRect().Width()) < kSizeEpsilon) return; CFX_Matrix formMatrix = Obj.m_formMatrix; CPDF_Font* pFont = pTextObj->GetFont(); CFX_Matrix matrix = pTextObj->GetTextMatrix() * formMatrix; FPDFText_MarkedContent ePreMKC = PreMarkedContent(Obj); if (ePreMKC == FPDFText_MarkedContent::Done) { m_pPreTextObj = pTextObj; m_perMatrix = formMatrix; return; } GenerateCharacter result = GenerateCharacter::None; if (m_pPreTextObj) { result = ProcessInsertObject(pTextObj, formMatrix); if (result == GenerateCharacter::LineBreak) m_CurlineRect = Obj.m_pTextObj->GetRect(); else m_CurlineRect.Union(Obj.m_pTextObj->GetRect()); switch (result) { case GenerateCharacter::None: break; case GenerateCharacter::Space: { Optional<PAGECHAR_INFO> pGenerateChar = GenerateCharInfo(TEXT_SPACE_CHAR); if (pGenerateChar) { if (!formMatrix.IsIdentity()) pGenerateChar->m_Matrix = formMatrix; m_TempTextBuf.AppendChar(TEXT_SPACE_CHAR); m_TempCharList.push_back(*pGenerateChar); } break; } case GenerateCharacter::LineBreak: CloseTempLine(); if (m_TextBuf.GetSize()) { AppendGeneratedCharacter(TEXT_RETURN_CHAR, formMatrix); AppendGeneratedCharacter(TEXT_LINEFEED_CHAR, formMatrix); } break; case GenerateCharacter::Hyphen: if (pTextObj->CountChars() == 1) { CPDF_TextObjectItem item; pTextObj->GetCharInfo(0, &item); WideString wstrItem = pTextObj->GetFont()->UnicodeFromCharCode(item.m_CharCode); if (wstrItem.IsEmpty()) wstrItem += (wchar_t)item.m_CharCode; wchar_t curChar = wstrItem[0]; if (IsHyphenCode(curChar)) return; } while (m_TempTextBuf.GetSize() > 0 && m_TempTextBuf.AsStringView()[m_TempTextBuf.GetLength() - 1] == 0x20) { m_TempTextBuf.Delete(m_TempTextBuf.GetLength() - 1, 1); m_TempCharList.pop_back(); } PAGECHAR_INFO* charinfo = &m_TempCharList.back(); m_TempTextBuf.Delete(m_TempTextBuf.GetLength() - 1, 1); charinfo->m_Unicode = 0x2; charinfo->m_Flag = FPDFTEXT_CHAR_HYPHEN; m_TempTextBuf.AppendChar(0xfffe); break; } } else { m_CurlineRect = Obj.m_pTextObj->GetRect(); } if (ePreMKC == FPDFText_MarkedContent::Delay) { ProcessMarkedContent(Obj); m_pPreTextObj = pTextObj; m_perMatrix = formMatrix; return; } m_pPreTextObj = pTextObj; m_perMatrix = formMatrix; float baseSpace = CalculateBaseSpace(pTextObj, matrix); const bool bR2L = IsRightToLeft(*pTextObj, *pFont); const bool bIsBidiAndMirrorInverse = bR2L && (matrix.a * matrix.d - matrix.b * matrix.c) < 0; int32_t iBufStartAppend = m_TempTextBuf.GetLength(); int32_t iCharListStartAppend = pdfium::CollectionSize<int32_t>(m_TempCharList); float spacing = 0; const size_t nItems = pTextObj->CountItems(); for (size_t i = 0; i < nItems; ++i) { CPDF_TextObjectItem item; PAGECHAR_INFO charinfo; pTextObj->GetItemInfo(i, &item); if (item.m_CharCode == static_cast<uint32_t>(-1)) { WideString str = m_TempTextBuf.MakeString(); if (str.IsEmpty()) str = m_TextBuf.AsStringView(); if (str.IsEmpty() || str[str.GetLength() - 1] == TEXT_SPACE_CHAR) continue; float fontsize_h = pTextObj->m_TextState.GetFontSizeH(); spacing = -fontsize_h * item.m_Origin.x / 1000; continue; } float charSpace = pTextObj->m_TextState.GetCharSpace(); if (charSpace > 0.001) spacing += matrix.TransformDistance(charSpace); else if (charSpace < -0.001) spacing -= matrix.TransformDistance(fabs(charSpace)); spacing -= baseSpace; if (spacing && i > 0) { float fontsize_h = pTextObj->m_TextState.GetFontSizeH(); uint32_t space_charcode = pFont->CharCodeFromUnicode(' '); float threshold = 0; if (space_charcode != CPDF_Font::kInvalidCharCode) threshold = fontsize_h * pFont->GetCharWidthF(space_charcode) / 1000; if (threshold > fontsize_h / 3) threshold = 0; else threshold /= 2; if (threshold == 0) { threshold = static_cast<float>(GetCharWidth(item.m_CharCode, pFont)); threshold = NormalizeThreshold(threshold, 300, 500, 700); threshold = fontsize_h * threshold / 1000; } if (threshold && (spacing && spacing >= threshold)) { charinfo.m_Unicode = TEXT_SPACE_CHAR; charinfo.m_Flag = FPDFTEXT_CHAR_GENERATED; charinfo.m_pTextObj = pTextObj; charinfo.m_Index = m_TextBuf.GetLength(); m_TempTextBuf.AppendChar(TEXT_SPACE_CHAR); charinfo.m_CharCode = CPDF_Font::kInvalidCharCode; charinfo.m_Matrix = formMatrix; charinfo.m_Origin = matrix.Transform(item.m_Origin); charinfo.m_CharBox = CFX_FloatRect(charinfo.m_Origin.x, charinfo.m_Origin.y, charinfo.m_Origin.x, charinfo.m_Origin.y); m_TempCharList.push_back(charinfo); } if (item.m_CharCode == CPDF_Font::kInvalidCharCode) continue; } spacing = 0; WideString wstrItem = pFont->UnicodeFromCharCode(item.m_CharCode); bool bNoUnicode = false; if (wstrItem.IsEmpty() && item.m_CharCode) { wstrItem += static_cast<wchar_t>(item.m_CharCode); bNoUnicode = true; } charinfo.m_Index = -1; charinfo.m_CharCode = item.m_CharCode; charinfo.m_Flag = bNoUnicode ? FPDFTEXT_CHAR_UNUNICODE : FPDFTEXT_CHAR_NORMAL; charinfo.m_pTextObj = pTextObj; charinfo.m_Origin = matrix.Transform(item.m_Origin); const FX_RECT rect = charinfo.m_pTextObj->GetFont()->GetCharBBox(charinfo.m_CharCode); const float fFontSize = pTextObj->GetFontSize() / 1000; charinfo.m_CharBox.top = rect.top * fFontSize + item.m_Origin.y; charinfo.m_CharBox.left = rect.left * fFontSize + item.m_Origin.x; charinfo.m_CharBox.right = rect.right * fFontSize + item.m_Origin.x; charinfo.m_CharBox.bottom = rect.bottom * fFontSize + item.m_Origin.y; if (fabsf(charinfo.m_CharBox.top - charinfo.m_CharBox.bottom) < kSizeEpsilon) { charinfo.m_CharBox.top = charinfo.m_CharBox.bottom + pTextObj->GetFontSize(); } if (fabsf(charinfo.m_CharBox.right - charinfo.m_CharBox.left) < kSizeEpsilon) { charinfo.m_CharBox.right = charinfo.m_CharBox.left + pTextObj->GetCharWidth(charinfo.m_CharCode); } charinfo.m_CharBox = matrix.TransformRect(charinfo.m_CharBox); charinfo.m_Matrix = matrix; if (wstrItem.IsEmpty()) { charinfo.m_Unicode = 0; m_TempCharList.push_back(charinfo); m_TempTextBuf.AppendChar(0xfffe); continue; } int nTotal = wstrItem.GetLength(); bool bDel = false; const int count = std::min(pdfium::CollectionSize<int>(m_TempCharList), 7); float threshold = charinfo.m_Matrix.TransformXDistance( static_cast<float>(TEXT_CHARRATIO_GAPDELTA) * pTextObj->GetFontSize()); for (int n = pdfium::CollectionSize<int>(m_TempCharList); n > pdfium::CollectionSize<int>(m_TempCharList) - count; --n) { const PAGECHAR_INFO& charinfo1 = m_TempCharList[n - 1]; CFX_PointF diff = charinfo1.m_Origin - charinfo.m_Origin; if (charinfo1.m_CharCode == charinfo.m_CharCode && charinfo1.m_pTextObj->GetFont() == charinfo.m_pTextObj->GetFont() && fabs(diff.x) < threshold && fabs(diff.y) < threshold) { bDel = true; break; } } if (!bDel) { for (int nIndex = 0; nIndex < nTotal; ++nIndex) { charinfo.m_Unicode = wstrItem[nIndex]; if (charinfo.m_Unicode) { charinfo.m_Index = m_TextBuf.GetLength(); m_TempTextBuf.AppendChar(charinfo.m_Unicode); } else { m_TempTextBuf.AppendChar(0xfffe); } m_TempCharList.push_back(charinfo); } } else if (i == 0) { WideString str = m_TempTextBuf.MakeString(); if (!str.IsEmpty() && str[str.GetLength() - 1] == TEXT_SPACE_CHAR) { m_TempTextBuf.Delete(m_TempTextBuf.GetLength() - 1, 1); m_TempCharList.pop_back(); } } } if (bIsBidiAndMirrorInverse) SwapTempTextBuf(iCharListStartAppend, iBufStartAppend); }