void CPDF_ReflowedPage::GetDisplayMatrix(CFX_AffineMatrix& matrix, FX_INT32 xPos, FX_INT32 yPos, FX_INT32 xSize, FX_INT32 ySize, FX_INT32 iRotate, const CFX_AffineMatrix* pPageMatrix) { CFX_AffineMatrix display_matrix; if(m_PageHeight == 0) { matrix.Set(1, 0, 0, -1, 0, 0); return; } FX_INT32 x0, y0, x1, y1, x2, y2; iRotate %= 4; switch (iRotate) { case 0: x0 = xPos; y0 = yPos; x1 = xPos; y1 = yPos + ySize; x2 = xPos + xSize; y2 = yPos; break; case 3: x0 = xPos; y0 = ySize + yPos; x1 = xPos + xSize; y1 = yPos + ySize; x2 = xPos; y2 = yPos; break; case 2: x0 = xSize + xPos; y0 = ySize + yPos; x1 = xSize + xPos ; y1 = yPos; x2 = xPos; y2 = ySize + yPos; break; case 1: x0 = xPos + xSize; y0 = yPos; x1 = xPos; y1 = yPos; x2 = xPos + xSize; y2 = yPos + ySize; break; } display_matrix.Set(FXSYS_Div((FX_FLOAT)(x2 - x0), m_PageWidth), FXSYS_Div((FX_FLOAT)(y2 - y0), m_PageWidth), FXSYS_Div((FX_FLOAT)(x1 - x0), m_PageHeight), FXSYS_Div((FX_FLOAT)(y1 - y0), m_PageHeight), (FX_FLOAT)(x0), (FX_FLOAT)(y0)); matrix.Set(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f); matrix.Concat(display_matrix); return; }
void CPDF_RenderStatus::DrawTextPathWithPattern( const CPDF_TextObject* textobj, const CFX_AffineMatrix* pObj2Device, CPDF_Font* pFont, FX_FLOAT font_size, const CFX_AffineMatrix* pTextMatrix, FX_BOOL bFill, FX_BOOL bStroke) { if (!bStroke) { CPDF_PathObject path; CPDF_TextObject* pCopy = new CPDF_TextObject; pCopy->Copy(textobj); path.m_bStroke = FALSE; path.m_FillType = FXFILL_WINDING; path.m_ClipPath.AppendTexts(&pCopy, 1); path.m_ColorState = textobj->m_ColorState; path.m_Path.New()->AppendRect(textobj->m_Left, textobj->m_Bottom, textobj->m_Right, textobj->m_Top); path.m_Left = textobj->m_Left; path.m_Bottom = textobj->m_Bottom; path.m_Right = textobj->m_Right; path.m_Top = textobj->m_Top; RenderSingleObject(&path, pObj2Device); return; } CFX_FontCache* pCache; if (pFont->m_pDocument) { pCache = pFont->m_pDocument->GetRenderData()->GetFontCache(); } else { pCache = CFX_GEModule::Get()->GetFontCache(); } CFX_FaceCache* pFaceCache = pCache->GetCachedFace(&pFont->m_Font); FX_FONTCACHE_DEFINE(pCache, &pFont->m_Font); CPDF_CharPosList CharPosList; CharPosList.Load(textobj->m_nChars, textobj->m_pCharCodes, textobj->m_pCharPos, pFont, font_size); for (FX_DWORD i = 0; i < CharPosList.m_nChars; i++) { FXTEXT_CHARPOS& charpos = CharPosList.m_pCharPos[i]; const CFX_PathData* pPath = pFaceCache->LoadGlyphPath( &pFont->m_Font, charpos.m_GlyphIndex, charpos.m_FontCharWidth); if (pPath == NULL) { continue; } CPDF_PathObject path; path.m_GraphState = textobj->m_GraphState; path.m_ColorState = textobj->m_ColorState; CFX_AffineMatrix matrix; if (charpos.m_bGlyphAdjust) matrix.Set(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1], charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0); matrix.Concat(font_size, 0, 0, font_size, charpos.m_OriginX, charpos.m_OriginY); path.m_Path.New()->Append(pPath, &matrix); path.m_Matrix = *pTextMatrix; path.m_bStroke = bStroke; path.m_FillType = bFill ? FXFILL_WINDING : 0; path.CalcBoundingBox(); ProcessPath(&path, pObj2Device); } }
CFX_AffineMatrix CPDF_Array::GetMatrix() { CFX_AffineMatrix matrix; if (m_Type != PDFOBJ_ARRAY || m_Objects.GetSize() != 6) { return matrix; } matrix.Set(GetNumber(0), GetNumber(1), GetNumber(2), GetNumber(3), GetNumber(4), GetNumber(5)); return matrix; }
static void CheckRotate(CPDF_Page& page, CFX_FloatRect& page_bbox) { int total_count = 0, rotated_count[3] = {0, 0, 0}; FX_POSITION pos = page.GetFirstObjectPosition(); while (pos) { CPDF_PageObject* pObj = page.GetNextObject(pos); if (pObj->m_Type != PDFPAGE_TEXT) { continue; } total_count ++; CPDF_TextObject* pText = (CPDF_TextObject*)pObj; FX_FLOAT angle = pText->m_TextState.GetBaselineAngle(); if (angle == 0.0) { continue; } int degree = (int)(angle * 180 / PI + 0.5); if (degree % 90) { continue; } if (degree < 0) { degree += 360; } int index = degree / 90 % 3 - 1; if (index < 0) { continue; } rotated_count[index] ++; } if (total_count == 0) { return; } CFX_AffineMatrix matrix; if (rotated_count[0] > total_count * 2 / 3) { matrix.Set(0, -1, 1, 0, 0, page.GetPageHeight()); } else if (rotated_count[1] > total_count * 2 / 3) { matrix.Set(-1, 0, 0, -1, page.GetPageWidth(), page.GetPageHeight()); } else if (rotated_count[2] > total_count * 2 / 3) { matrix.Set(0, 1, -1, 0, page.GetPageWidth(), 0); } else { return; } page.Transform(matrix); page_bbox.Transform(&matrix); }
static void nativeSetTransformAndClip(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex, jlong transformPtr, jint clipLeft, jint clipTop, jint clipRight, jint clipBottom) { FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); CPDF_Page* page = (CPDF_Page*) FPDF_LoadPage(document, pageIndex); if (!page) { jniThrowException(env, "java/lang/IllegalStateException", "cannot open page"); return; } double width = 0; double height = 0; const int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height); if (!result) { jniThrowException(env, "java/lang/IllegalStateException", "cannot get page size"); return; } CFX_AffineMatrix matrix; SkMatrix* skTransform = reinterpret_cast<SkMatrix*>(transformPtr); SkScalar transformValues[6]; if (!skTransform->asAffine(transformValues)) { jniThrowException(env, "java/lang/IllegalArgumentException", "transform matrix has perspective. Only affine matrices are allowed."); return; } // PDF's coordinate system origin is left-bottom while in graphics it // is the top-left. So, translate the PDF coordinates to ours. matrix.Set(1, 0, 0, -1, 0, page->GetPageHeight()); // Apply the transformation what was created in our coordinates. matrix.Concat(transformValues[SkMatrix::kAScaleX], transformValues[SkMatrix::kASkewY], transformValues[SkMatrix::kASkewX], transformValues[SkMatrix::kAScaleY], transformValues[SkMatrix::kATransX], transformValues[SkMatrix::kATransY]); // Translate the result back to PDF coordinates. matrix.Concat(1, 0, 0, -1, 0, page->GetPageHeight()); FS_MATRIX transform = {matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f}; FS_RECTF clip = {(float) clipLeft, (float) clipTop, (float) clipRight, (float) clipBottom}; FPDFPage_TransFormWithClip(page, &transform, &clip); FPDF_ClosePage(page); }
CFX_AffineMatrix CPDF_DefaultAppearance::GetTextMatrix() { CFX_AffineMatrix tm; if (m_csDA.IsEmpty()) { return tm; } CPDF_SimpleParser syntax(m_csDA); if (syntax.FindTagParam("Tm", 6)) { FX_FLOAT f[6]; for (int i = 0; i < 6; i ++) { f[i] = FX_atof((CFX_ByteString)syntax.GetWord()); } tm.Set(f[0], f[1], f[2], f[3], f[4], f[5]); } return tm; }
static void renderPageBitmap(FPDF_BITMAP bitmap, FPDF_PAGE page, int destLeft, int destTop, int destRight, int destBottom, SkMatrix* transform, int flags) { // Note: this code ignores the currently unused RENDER_NO_NATIVETEXT, // FPDF_RENDER_LIMITEDIMAGECACHE, FPDF_RENDER_FORCEHALFTONE, FPDF_GRAYSCALE, // and FPDF_ANNOT flags. To add support for that refer to FPDF_RenderPage_Retail // in fpdfview.cpp CRenderContext* pContext = FX_NEW CRenderContext; CPDF_Page* pPage = (CPDF_Page*) page; pPage->SetPrivateData((void*) 1, pContext, DropContext); CFX_FxgeDevice* fxgeDevice = FX_NEW CFX_FxgeDevice; pContext->m_pDevice = fxgeDevice; // Reverse the bytes (last argument TRUE) since the Android // format is ARGB while the renderer uses BGRA internally. fxgeDevice->Attach((CFX_DIBitmap*) bitmap, 0, TRUE); CPDF_RenderOptions* renderOptions = pContext->m_pOptions; if (!renderOptions) { renderOptions = FX_NEW CPDF_RenderOptions; pContext->m_pOptions = renderOptions; } if (flags & FPDF_LCD_TEXT) { renderOptions->m_Flags |= RENDER_CLEARTYPE; } else { renderOptions->m_Flags &= ~RENDER_CLEARTYPE; } const CPDF_OCContext::UsageType usage = (flags & FPDF_PRINTING) ? CPDF_OCContext::Print : CPDF_OCContext::View; renderOptions->m_AddFlags = flags >> 8; renderOptions->m_pOCContext = new CPDF_OCContext(pPage->m_pDocument, usage); fxgeDevice->SaveState(); FX_RECT clip; clip.left = destLeft; clip.right = destRight; clip.top = destTop; clip.bottom = destBottom; fxgeDevice->SetClip_Rect(&clip); CPDF_RenderContext* pageContext = FX_NEW CPDF_RenderContext; pContext->m_pContext = pageContext; pageContext->Create(pPage); CFX_AffineMatrix matrix; if (!transform) { pPage->GetDisplayMatrix(matrix, destLeft, destTop, destRight - destLeft, destBottom - destTop, 0); } else { // PDF's coordinate system origin is left-bottom while // in graphics it is the top-left, so remap the origin. matrix.Set(1, 0, 0, -1, 0, pPage->GetPageHeight()); SkScalar transformValues[6]; transform->asAffine(transformValues); matrix.Concat(transformValues[SkMatrix::kAScaleX], transformValues[SkMatrix::kASkewY], transformValues[SkMatrix::kASkewX], transformValues[SkMatrix::kAScaleY], transformValues[SkMatrix::kATransX], transformValues[SkMatrix::kATransY]); } pageContext->AppendObjectList(pPage, &matrix); pContext->m_pRenderer = FX_NEW CPDF_ProgressiveRenderer; pContext->m_pRenderer->Start(pageContext, fxgeDevice, renderOptions, NULL); fxgeDevice->RestoreState(); pPage->RemovePrivateData((void*) 1); delete pContext; }
void CFX_PSRenderer::FindPSFontGlyph(CFX_FaceCache* pFaceCache, CFX_Font* pFont, const FXTEXT_CHARPOS& charpos, int& ps_fontnum, int &ps_glyphindex) { for (int i = 0; i < (int)m_PSFontList.GetSize(); i ++) { CPSFont* pPSFont = m_PSFontList[i]; for (int j = 0; j < pPSFont->m_nGlyphs; j ++) if (pPSFont->m_Glyphs[j].m_pFont == pFont && pPSFont->m_Glyphs[j].m_GlyphIndex == charpos.m_GlyphIndex) { if ((!pPSFont->m_Glyphs[j].m_bGlyphAdjust && !charpos.m_bGlyphAdjust) || (pPSFont->m_Glyphs[j].m_bGlyphAdjust && charpos.m_bGlyphAdjust && (FXSYS_fabs(pPSFont->m_Glyphs[j].m_AdjustMatrix[0] - charpos.m_AdjustMatrix[0]) < 0.01 && FXSYS_fabs(pPSFont->m_Glyphs[j].m_AdjustMatrix[1] - charpos.m_AdjustMatrix[1]) < 0.01 && FXSYS_fabs(pPSFont->m_Glyphs[j].m_AdjustMatrix[2] - charpos.m_AdjustMatrix[2]) < 0.01 && FXSYS_fabs(pPSFont->m_Glyphs[j].m_AdjustMatrix[3] - charpos.m_AdjustMatrix[3]) < 0.01))) { ps_fontnum = i; ps_glyphindex = j; return; } } } if (m_PSFontList.GetSize() == 0 || m_PSFontList[m_PSFontList.GetSize() - 1]->m_nGlyphs == 256) { CPSFont* pPSFont = new CPSFont; pPSFont->m_nGlyphs = 0; m_PSFontList.Add(pPSFont); CFX_ByteTextBuf buf; buf << FX_BSTRC("8 dict begin/FontType 3 def/FontMatrix[1 0 0 1 0 0]def\n" "/FontBBox[0 0 0 0]def/Encoding 256 array def 0 1 255{Encoding exch/.notdef put}for\n" "/CharProcs 1 dict def CharProcs begin/.notdef {} def end\n" "/BuildGlyph{1 0 -10 -10 10 10 setcachedevice exch/CharProcs get exch 2 copy known not{pop/.notdef}if get exec}bind def\n" "/BuildChar{1 index/Encoding get exch get 1 index/BuildGlyph get exec}bind def\n" "currentdict end\n"); buf << FX_BSTRC("/X") << m_PSFontList.GetSize() - 1 << FX_BSTRC(" exch definefont pop\n"); m_pOutput->OutputPS((FX_LPCSTR)buf.GetBuffer(), buf.GetSize()); buf.Clear(); } ps_fontnum = m_PSFontList.GetSize() - 1; CPSFont* pPSFont = m_PSFontList[ps_fontnum]; ps_glyphindex = pPSFont->m_nGlyphs; pPSFont->m_Glyphs[ps_glyphindex].m_GlyphIndex = charpos.m_GlyphIndex; pPSFont->m_Glyphs[ps_glyphindex].m_pFont = pFont; pPSFont->m_Glyphs[ps_glyphindex].m_bGlyphAdjust = charpos.m_bGlyphAdjust; if (charpos.m_bGlyphAdjust) { pPSFont->m_Glyphs[ps_glyphindex].m_AdjustMatrix[0] = charpos.m_AdjustMatrix[0]; pPSFont->m_Glyphs[ps_glyphindex].m_AdjustMatrix[1] = charpos.m_AdjustMatrix[1]; pPSFont->m_Glyphs[ps_glyphindex].m_AdjustMatrix[2] = charpos.m_AdjustMatrix[2]; pPSFont->m_Glyphs[ps_glyphindex].m_AdjustMatrix[3] = charpos.m_AdjustMatrix[3]; } pPSFont->m_nGlyphs ++; CFX_AffineMatrix matrix; if (charpos.m_bGlyphAdjust) matrix.Set(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1], charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0); matrix.Concat(1.0f, 0, 0, 1.0f, 0, 0); const CFX_PathData* pPathData = pFaceCache->LoadGlyphPath(pFont, charpos.m_GlyphIndex, charpos.m_FontCharWidth); if (pPathData == NULL) { return; } CFX_PathData TransformedPath(*pPathData); if (charpos.m_bGlyphAdjust) { TransformedPath.Transform(&matrix); } CFX_ByteTextBuf buf; buf << FX_BSTRC("/X") << ps_fontnum << FX_BSTRC(" Ff/CharProcs get begin/") << ps_glyphindex << FX_BSTRC("{"); buf << FX_BSTRC("n "); for (int p = 0; p < TransformedPath.GetPointCount(); p ++) { FX_FLOAT x = TransformedPath.GetPointX(p), y = TransformedPath.GetPointY(p); switch (TransformedPath.GetFlag(p) & FXPT_TYPE) { case FXPT_MOVETO: { buf << x << FX_BSTRC(" ") << y << FX_BSTRC(" m\n"); break; } case FXPT_LINETO: { buf << x << FX_BSTRC(" ") << y << FX_BSTRC(" l\n"); break; } case FXPT_BEZIERTO: { buf << x << FX_BSTRC(" ") << y << FX_BSTRC(" ") << TransformedPath.GetPointX(p + 1) << FX_BSTRC(" ") << TransformedPath.GetPointY(p + 1) << FX_BSTRC(" ") << TransformedPath.GetPointX(p + 2) << FX_BSTRC(" ") << TransformedPath.GetPointY(p + 2) << FX_BSTRC(" c\n"); p += 2; break; } } } buf << FX_BSTRC("f"); buf << FX_BSTRC("}bind def end\n"); buf << FX_BSTRC("/X") << ps_fontnum << FX_BSTRC(" Ff/Encoding get ") << ps_glyphindex << FX_BSTRC("/") << ps_glyphindex << FX_BSTRC(" put\n"); m_pOutput->OutputPS((FX_LPCSTR)buf.GetBuffer(), buf.GetSize()); }