diff options
Diffstat (limited to 'core/fxge/ge')
-rw-r--r-- | core/fxge/ge/fx_ge.cpp | 60 | ||||
-rw-r--r-- | core/fxge/ge/fx_ge_device.cpp | 474 | ||||
-rw-r--r-- | core/fxge/ge/fx_ge_font.cpp | 545 | ||||
-rw-r--r-- | core/fxge/ge/fx_ge_fontmap.cpp | 1623 | ||||
-rw-r--r-- | core/fxge/ge/fx_ge_linux.cpp | 147 | ||||
-rw-r--r-- | core/fxge/ge/fx_ge_path.cpp | 656 | ||||
-rw-r--r-- | core/fxge/ge/fx_ge_ps.cpp | 700 | ||||
-rw-r--r-- | core/fxge/ge/fx_ge_text.cpp | 1872 | ||||
-rw-r--r-- | core/fxge/ge/fx_text_int.h | 84 |
9 files changed, 6161 insertions, 0 deletions
diff --git a/core/fxge/ge/fx_ge.cpp b/core/fxge/ge/fx_ge.cpp new file mode 100644 index 0000000000..7ae9942dec --- /dev/null +++ b/core/fxge/ge/fx_ge.cpp @@ -0,0 +1,60 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/include/fxge/fx_ge.h" + +#include "core/fxge/ge/fx_text_int.h" + +static CFX_GEModule* g_pGEModule = NULL; +CFX_GEModule::CFX_GEModule(const char** pUserFontPaths) { + m_pFontCache = NULL; + m_pFontMgr = NULL; + m_FTLibrary = NULL; + m_pCodecModule = NULL; + m_pPlatformData = NULL; + m_pUserFontPaths = pUserFontPaths; +} +CFX_GEModule::~CFX_GEModule() { + delete m_pFontCache; + m_pFontCache = NULL; + delete m_pFontMgr; + m_pFontMgr = NULL; + DestroyPlatform(); +} +CFX_GEModule* CFX_GEModule::Get() { + return g_pGEModule; +} +void CFX_GEModule::Create(const char** userFontPaths) { + g_pGEModule = new CFX_GEModule(userFontPaths); + g_pGEModule->m_pFontMgr = new CFX_FontMgr; + g_pGEModule->InitPlatform(); + g_pGEModule->SetTextGamma(2.2f); +} +void CFX_GEModule::Use(CFX_GEModule* pModule) { + g_pGEModule = pModule; +} +void CFX_GEModule::Destroy() { + delete g_pGEModule; + g_pGEModule = NULL; +} +CFX_FontCache* CFX_GEModule::GetFontCache() { + if (!m_pFontCache) { + m_pFontCache = new CFX_FontCache(); + } + return m_pFontCache; +} +void CFX_GEModule::SetTextGamma(FX_FLOAT gammaValue) { + gammaValue /= 2.2f; + int i = 0; + while (i < 256) { + m_GammaValue[i] = + (uint8_t)(FXSYS_pow((FX_FLOAT)i / 255, gammaValue) * 255.0f + 0.5f); + i++; + } +} +const uint8_t* CFX_GEModule::GetTextGammaTable() { + return m_GammaValue; +} diff --git a/core/fxge/ge/fx_ge_device.cpp b/core/fxge/ge/fx_ge_device.cpp new file mode 100644 index 0000000000..b8ddfec841 --- /dev/null +++ b/core/fxge/ge/fx_ge_device.cpp @@ -0,0 +1,474 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/include/fxge/fx_ge.h" + +CFX_RenderDevice::CFX_RenderDevice() { + m_pDeviceDriver = NULL; + m_pBitmap = NULL; +} +CFX_RenderDevice::~CFX_RenderDevice() { + delete m_pDeviceDriver; +} +void CFX_RenderDevice::SetDeviceDriver(IFX_RenderDeviceDriver* pDriver) { + delete m_pDeviceDriver; + m_pDeviceDriver = pDriver; + InitDeviceInfo(); +} +void CFX_RenderDevice::InitDeviceInfo() { + m_Width = m_pDeviceDriver->GetDeviceCaps(FXDC_PIXEL_WIDTH); + m_Height = m_pDeviceDriver->GetDeviceCaps(FXDC_PIXEL_HEIGHT); + m_bpp = m_pDeviceDriver->GetDeviceCaps(FXDC_BITS_PIXEL); + m_RenderCaps = m_pDeviceDriver->GetDeviceCaps(FXDC_RENDER_CAPS); + m_DeviceClass = m_pDeviceDriver->GetDeviceCaps(FXDC_DEVICE_CLASS); + if (!m_pDeviceDriver->GetClipBox(&m_ClipBox)) { + m_ClipBox.left = 0; + m_ClipBox.top = 0; + m_ClipBox.right = m_Width; + m_ClipBox.bottom = m_Height; + } +} +FX_BOOL CFX_RenderDevice::StartRendering() { + return m_pDeviceDriver->StartRendering(); +} +void CFX_RenderDevice::EndRendering() { + m_pDeviceDriver->EndRendering(); +} +void CFX_RenderDevice::SaveState() { + m_pDeviceDriver->SaveState(); +} +void CFX_RenderDevice::RestoreState(FX_BOOL bKeepSaved) { + m_pDeviceDriver->RestoreState(bKeepSaved); + UpdateClipBox(); +} +int CFX_RenderDevice::GetDeviceCaps(int caps_id) const { + return m_pDeviceDriver->GetDeviceCaps(caps_id); +} +CFX_Matrix CFX_RenderDevice::GetCTM() const { + return m_pDeviceDriver->GetCTM(); +} +FX_BOOL CFX_RenderDevice::CreateCompatibleBitmap(CFX_DIBitmap* pDIB, + int width, + int height) const { + if (m_RenderCaps & FXRC_CMYK_OUTPUT) { + return pDIB->Create(width, height, m_RenderCaps & FXRC_ALPHA_OUTPUT + ? FXDIB_Cmyka + : FXDIB_Cmyk); + } + if (m_RenderCaps & FXRC_BYTEMASK_OUTPUT) { + return pDIB->Create(width, height, FXDIB_8bppMask); + } +#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ + return pDIB->Create(width, height, m_RenderCaps & FXRC_ALPHA_OUTPUT + ? FXDIB_Argb + : FXDIB_Rgb32); +#else + return pDIB->Create( + width, height, m_RenderCaps & FXRC_ALPHA_OUTPUT ? FXDIB_Argb : FXDIB_Rgb); +#endif +} +FX_BOOL CFX_RenderDevice::SetClip_PathFill(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + int fill_mode) { + if (!m_pDeviceDriver->SetClip_PathFill(pPathData, pObject2Device, + fill_mode)) { + return FALSE; + } + UpdateClipBox(); + return TRUE; +} +FX_BOOL CFX_RenderDevice::SetClip_PathStroke( + const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState) { + if (!m_pDeviceDriver->SetClip_PathStroke(pPathData, pObject2Device, + pGraphState)) { + return FALSE; + } + UpdateClipBox(); + return TRUE; +} +FX_BOOL CFX_RenderDevice::SetClip_Rect(const FX_RECT& rect) { + CFX_PathData path; + path.AppendRect(rect.left, rect.bottom, rect.right, rect.top); + if (!SetClip_PathFill(&path, nullptr, FXFILL_WINDING)) + return FALSE; + + UpdateClipBox(); + return TRUE; +} +void CFX_RenderDevice::UpdateClipBox() { + if (m_pDeviceDriver->GetClipBox(&m_ClipBox)) { + return; + } + m_ClipBox.left = 0; + m_ClipBox.top = 0; + m_ClipBox.right = m_Width; + m_ClipBox.bottom = m_Height; +} +FX_BOOL CFX_RenderDevice::DrawPath(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState, + FX_DWORD fill_color, + FX_DWORD stroke_color, + int fill_mode, + int alpha_flag, + void* pIccTransform, + int blend_type) { + uint8_t fill_alpha, stroke_alpha; + if (FXGETFLAG_COLORTYPE(alpha_flag)) { + fill_alpha = FXGETFLAG_ALPHA_FILL(alpha_flag); + stroke_alpha = FXGETFLAG_ALPHA_STROKE(alpha_flag); + } else { + fill_alpha = FXARGB_A(fill_color); + stroke_alpha = FXARGB_A(stroke_color); + } + if ((fill_mode & 3) == 0) { + fill_alpha = 0; + } + if (!pGraphState) { + stroke_alpha = 0; + } + if (stroke_alpha == 0 && pPathData->GetPointCount() == 2) { + FX_PATHPOINT* pPoints = pPathData->GetPoints(); + FX_FLOAT x1, x2, y1, y2; + if (pObject2Device) { + pObject2Device->Transform(pPoints[0].m_PointX, pPoints[0].m_PointY, x1, + y1); + pObject2Device->Transform(pPoints[1].m_PointX, pPoints[1].m_PointY, x2, + y2); + } else { + x1 = pPoints[0].m_PointX; + y1 = pPoints[0].m_PointY; + x2 = pPoints[1].m_PointX; + y2 = pPoints[1].m_PointY; + } + DrawCosmeticLine(x1, y1, x2, y2, fill_color, fill_mode, alpha_flag, + pIccTransform, blend_type); + return TRUE; + } + if ((pPathData->GetPointCount() == 5 || pPathData->GetPointCount() == 4) && + stroke_alpha == 0) { + CFX_FloatRect rect_f; + if (!(fill_mode & FXFILL_RECT_AA) && + pPathData->IsRect(pObject2Device, &rect_f)) { + FX_RECT rect_i = rect_f.GetOutterRect(); + int width = (int)FXSYS_ceil(rect_f.right - rect_f.left); + if (width < 1) { + width = 1; + if (rect_i.left == rect_i.right) { + rect_i.right++; + } + } + int height = (int)FXSYS_ceil(rect_f.top - rect_f.bottom); + if (height < 1) { + height = 1; + if (rect_i.bottom == rect_i.top) { + rect_i.bottom++; + } + } + if (rect_i.Width() >= width + 1) { + if (rect_f.left - (FX_FLOAT)(rect_i.left) > + (FX_FLOAT)(rect_i.right) - rect_f.right) { + rect_i.left++; + } else { + rect_i.right--; + } + } + if (rect_i.Height() >= height + 1) { + if (rect_f.top - (FX_FLOAT)(rect_i.top) > + (FX_FLOAT)(rect_i.bottom) - rect_f.bottom) { + rect_i.top++; + } else { + rect_i.bottom--; + } + } + if (FillRect(&rect_i, fill_color, alpha_flag, pIccTransform, + blend_type)) { + return TRUE; + } + } + } + if ((fill_mode & 3) && stroke_alpha == 0 && !(fill_mode & FX_FILL_STROKE) && + !(fill_mode & FX_FILL_TEXT_MODE)) { + CFX_PathData newPath; + FX_BOOL bThin = FALSE; + if (pPathData->GetZeroAreaPath(newPath, (CFX_Matrix*)pObject2Device, bThin, + m_pDeviceDriver->GetDriverType())) { + CFX_GraphStateData graphState; + graphState.m_LineWidth = 0.0f; + FX_DWORD strokecolor = fill_color; + if (bThin) { + if (FXGETFLAG_COLORTYPE(alpha_flag)) { + FXSETFLAG_ALPHA_STROKE(alpha_flag, fill_alpha >> 2); + } else { + strokecolor = + (((fill_alpha >> 2) << 24) | (strokecolor & 0x00ffffff)); + } + } + CFX_Matrix* pMatrix = NULL; + if (pObject2Device && !pObject2Device->IsIdentity()) { + pMatrix = (CFX_Matrix*)pObject2Device; + } + int smooth_path = FX_ZEROAREA_FILL; + if (fill_mode & FXFILL_NOPATHSMOOTH) { + smooth_path |= FXFILL_NOPATHSMOOTH; + } + m_pDeviceDriver->DrawPath(&newPath, pMatrix, &graphState, 0, strokecolor, + smooth_path, alpha_flag, pIccTransform, + blend_type); + } + } + if ((fill_mode & 3) && fill_alpha && stroke_alpha < 0xff && + (fill_mode & FX_FILL_STROKE)) { + if (!(m_RenderCaps & FXRC_GET_BITS)) { + return FALSE; + } + CFX_FloatRect bbox; + if (pGraphState) { + bbox = pPathData->GetBoundingBox(pGraphState->m_LineWidth, + pGraphState->m_MiterLimit); + } else { + bbox = pPathData->GetBoundingBox(); + } + if (pObject2Device) { + bbox.Transform(pObject2Device); + } + CFX_Matrix ctm = GetCTM(); + FX_FLOAT fScaleX = FXSYS_fabs(ctm.a); + FX_FLOAT fScaleY = FXSYS_fabs(ctm.d); + FX_RECT rect = bbox.GetOutterRect(); + CFX_DIBitmap bitmap, Backdrop; + if (!CreateCompatibleBitmap(&bitmap, FXSYS_round(rect.Width() * fScaleX), + FXSYS_round(rect.Height() * fScaleY))) { + return FALSE; + } + if (bitmap.HasAlpha()) { + bitmap.Clear(0); + Backdrop.Copy(&bitmap); + } else { + if (!m_pDeviceDriver->GetDIBits(&bitmap, rect.left, rect.top, NULL)) { + return FALSE; + } + Backdrop.Copy(&bitmap); + } + CFX_FxgeDevice bitmap_device; + bitmap_device.Attach(&bitmap, 0, FALSE, &Backdrop, TRUE); + CFX_Matrix matrix; + if (pObject2Device) { + matrix = *pObject2Device; + } + matrix.TranslateI(-rect.left, -rect.top); + matrix.Concat(fScaleX, 0, 0, fScaleY, 0, 0); + if (!bitmap_device.GetDeviceDriver()->DrawPath( + pPathData, &matrix, pGraphState, fill_color, stroke_color, + fill_mode, alpha_flag, pIccTransform, blend_type)) { + return FALSE; + } + FX_RECT src_rect(0, 0, FXSYS_round(rect.Width() * fScaleX), + FXSYS_round(rect.Height() * fScaleY)); + return m_pDeviceDriver->SetDIBits(&bitmap, 0, &src_rect, rect.left, + rect.top, FXDIB_BLEND_NORMAL); + } + return m_pDeviceDriver->DrawPath(pPathData, pObject2Device, pGraphState, + fill_color, stroke_color, fill_mode, + alpha_flag, pIccTransform, blend_type); +} +FX_BOOL CFX_RenderDevice::SetPixel(int x, + int y, + FX_DWORD color, + int alpha_flag, + void* pIccTransform) { + if (m_pDeviceDriver->SetPixel(x, y, color, alpha_flag, pIccTransform)) { + return TRUE; + } + FX_RECT rect(x, y, x + 1, y + 1); + return FillRect(&rect, color, alpha_flag, pIccTransform); +} +FX_BOOL CFX_RenderDevice::FillRect(const FX_RECT* pRect, + FX_DWORD fill_color, + int alpha_flag, + void* pIccTransform, + int blend_type) { + if (m_pDeviceDriver->FillRect(pRect, fill_color, alpha_flag, pIccTransform, + blend_type)) { + return TRUE; + } + if (!(m_RenderCaps & FXRC_GET_BITS)) { + return FALSE; + } + CFX_DIBitmap bitmap; + if (!CreateCompatibleBitmap(&bitmap, pRect->Width(), pRect->Height())) { + return FALSE; + } + if (!m_pDeviceDriver->GetDIBits(&bitmap, pRect->left, pRect->top)) { + return FALSE; + } + if (!bitmap.CompositeRect(0, 0, pRect->Width(), pRect->Height(), fill_color, + alpha_flag, pIccTransform)) { + return FALSE; + } + FX_RECT src_rect(0, 0, pRect->Width(), pRect->Height()); + m_pDeviceDriver->SetDIBits(&bitmap, 0, &src_rect, pRect->left, pRect->top, + FXDIB_BLEND_NORMAL); + return TRUE; +} +FX_BOOL CFX_RenderDevice::DrawCosmeticLine(FX_FLOAT x1, + FX_FLOAT y1, + FX_FLOAT x2, + FX_FLOAT y2, + FX_DWORD color, + int fill_mode, + int alpha_flag, + void* pIccTransform, + int blend_type) { + if (((m_RenderCaps & FXRC_ALPHA_PATH) && + (FXGETFLAG_COLORTYPE(alpha_flag) && + FXGETFLAG_ALPHA_FILL(alpha_flag) == 0xff)) || + color >= 0xff000000) { + if (m_pDeviceDriver->DrawCosmeticLine(x1, y1, x2, y2, color, alpha_flag, + pIccTransform, blend_type)) { + return TRUE; + } + } + CFX_GraphStateData graph_state; + CFX_PathData path; + path.SetPointCount(2); + path.SetPoint(0, x1, y1, FXPT_MOVETO); + path.SetPoint(1, x2, y2, FXPT_LINETO); + return m_pDeviceDriver->DrawPath(&path, NULL, &graph_state, 0, color, + fill_mode, alpha_flag, pIccTransform, + blend_type); +} +FX_BOOL CFX_RenderDevice::GetDIBits(CFX_DIBitmap* pBitmap, + int left, + int top, + void* pIccTransform) { + if (!(m_RenderCaps & FXRC_GET_BITS)) { + return FALSE; + } + return m_pDeviceDriver->GetDIBits(pBitmap, left, top, pIccTransform); +} +CFX_DIBitmap* CFX_RenderDevice::GetBackDrop() { + return m_pDeviceDriver->GetBackDrop(); +} +FX_BOOL CFX_RenderDevice::SetDIBits(const CFX_DIBSource* pBitmap, + int left, + int top, + int blend_mode, + void* pIccTransform) { + ASSERT(!pBitmap->IsAlphaMask()); + CFX_Matrix ctm = GetCTM(); + FX_FLOAT fScaleX = FXSYS_fabs(ctm.a); + FX_FLOAT fScaleY = FXSYS_fabs(ctm.d); + FX_RECT dest_rect(left, top, + FXSYS_round(left + pBitmap->GetWidth() / fScaleX), + FXSYS_round(top + pBitmap->GetHeight() / fScaleY)); + dest_rect.Intersect(m_ClipBox); + if (dest_rect.IsEmpty()) { + return TRUE; + } + FX_RECT src_rect(dest_rect.left - left, dest_rect.top - top, + dest_rect.left - left + dest_rect.Width(), + dest_rect.top - top + dest_rect.Height()); + src_rect.left = FXSYS_round(src_rect.left * fScaleX); + src_rect.top = FXSYS_round(src_rect.top * fScaleY); + src_rect.right = FXSYS_round(src_rect.right * fScaleX); + src_rect.bottom = FXSYS_round(src_rect.bottom * fScaleY); + if ((blend_mode != FXDIB_BLEND_NORMAL && !(m_RenderCaps & FXRC_BLEND_MODE)) || + (pBitmap->HasAlpha() && !(m_RenderCaps & FXRC_ALPHA_IMAGE))) { + if (!(m_RenderCaps & FXRC_GET_BITS)) { + return FALSE; + } + int bg_pixel_width = FXSYS_round(dest_rect.Width() * fScaleX); + int bg_pixel_height = FXSYS_round(dest_rect.Height() * fScaleY); + CFX_DIBitmap background; + if (!background.Create( + bg_pixel_width, bg_pixel_height, + (m_RenderCaps & FXRC_CMYK_OUTPUT) ? FXDIB_Cmyk : FXDIB_Rgb32)) { + return FALSE; + } + if (!m_pDeviceDriver->GetDIBits(&background, dest_rect.left, + dest_rect.top)) { + return FALSE; + } + if (!background.CompositeBitmap(0, 0, bg_pixel_width, bg_pixel_height, + pBitmap, src_rect.left, src_rect.top, + blend_mode, NULL, FALSE, pIccTransform)) { + return FALSE; + } + FX_RECT src_rect(0, 0, bg_pixel_width, bg_pixel_height); + return m_pDeviceDriver->SetDIBits(&background, 0, &src_rect, dest_rect.left, + dest_rect.top, FXDIB_BLEND_NORMAL); + } + return m_pDeviceDriver->SetDIBits(pBitmap, 0, &src_rect, dest_rect.left, + dest_rect.top, blend_mode, 0, + pIccTransform); +} +FX_BOOL CFX_RenderDevice::StretchDIBits(const CFX_DIBSource* pBitmap, + int left, + int top, + int dest_width, + int dest_height, + FX_DWORD flags, + void* pIccTransform, + int blend_mode) { + FX_RECT dest_rect(left, top, left + dest_width, top + dest_height); + FX_RECT clip_box = m_ClipBox; + clip_box.Intersect(dest_rect); + if (clip_box.IsEmpty()) { + return TRUE; + } + return m_pDeviceDriver->StretchDIBits(pBitmap, 0, left, top, dest_width, + dest_height, &clip_box, flags, 0, + pIccTransform, blend_mode); +} +FX_BOOL CFX_RenderDevice::SetBitMask(const CFX_DIBSource* pBitmap, + int left, + int top, + FX_DWORD argb, + int alpha_flag, + void* pIccTransform) { + FX_RECT src_rect(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight()); + return m_pDeviceDriver->SetDIBits(pBitmap, argb, &src_rect, left, top, + FXDIB_BLEND_NORMAL, alpha_flag, + pIccTransform); +} +FX_BOOL CFX_RenderDevice::StretchBitMask(const CFX_DIBSource* pBitmap, + int left, + int top, + int dest_width, + int dest_height, + FX_DWORD argb, + FX_DWORD flags, + int alpha_flag, + void* pIccTransform) { + FX_RECT dest_rect(left, top, left + dest_width, top + dest_height); + FX_RECT clip_box = m_ClipBox; + clip_box.Intersect(dest_rect); + return m_pDeviceDriver->StretchDIBits(pBitmap, argb, left, top, dest_width, + dest_height, &clip_box, flags, + alpha_flag, pIccTransform); +} +FX_BOOL CFX_RenderDevice::StartDIBits(const CFX_DIBSource* pBitmap, + int bitmap_alpha, + FX_DWORD argb, + const CFX_Matrix* pMatrix, + FX_DWORD flags, + void*& handle, + int alpha_flag, + void* pIccTransform, + int blend_mode) { + return m_pDeviceDriver->StartDIBits(pBitmap, bitmap_alpha, argb, pMatrix, + flags, handle, alpha_flag, pIccTransform, + blend_mode); +} +FX_BOOL CFX_RenderDevice::ContinueDIBits(void* handle, IFX_Pause* pPause) { + return m_pDeviceDriver->ContinueDIBits(handle, pPause); +} +void CFX_RenderDevice::CancelDIBits(void* handle) { + m_pDeviceDriver->CancelDIBits(handle); +} diff --git a/core/fxge/ge/fx_ge_font.cpp b/core/fxge/ge/fx_ge_font.cpp new file mode 100644 index 0000000000..14783085ac --- /dev/null +++ b/core/fxge/ge/fx_ge_font.cpp @@ -0,0 +1,545 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxge/ge/fx_text_int.h" +#include "core/include/fxge/fx_freetype.h" +#include "core/include/fxge/fx_ge.h" + +#define EM_ADJUST(em, a) (em == 0 ? (a) : (a)*1000 / em) + +#ifdef PDF_ENABLE_XFA +extern void _FPDFAPI_GetInternalFontData(int id1, + const uint8_t*& data, + FX_DWORD& size); +#endif // PDF_ENABLE_XFA + +namespace { + +#ifdef PDF_ENABLE_XFA +const FX_DWORD g_EncodingID[] = { + FXFM_ENCODING_MS_SYMBOL, FXFM_ENCODING_UNICODE, + FXFM_ENCODING_MS_SJIS, FXFM_ENCODING_MS_GB2312, + FXFM_ENCODING_MS_BIG5, FXFM_ENCODING_MS_WANSUNG, + FXFM_ENCODING_MS_JOHAB, FXFM_ENCODING_ADOBE_STANDARD, + FXFM_ENCODING_ADOBE_EXPERT, FXFM_ENCODING_ADOBE_CUSTOM, + FXFM_ENCODING_ADOBE_LATIN_1, FXFM_ENCODING_OLD_LATIN_2, + FXFM_ENCODING_APPLE_ROMAN, +}; + +CFX_UnicodeEncodingEx* _FXFM_CreateFontEncoding(CFX_Font* pFont, + FX_DWORD nEncodingID) { + if (FXFT_Select_Charmap(pFont->GetFace(), nEncodingID)) + return nullptr; + return new CFX_UnicodeEncodingEx(pFont, nEncodingID); +} +#endif // PDF_ENABLE_XFA + +FXFT_Face FT_LoadFont(const uint8_t* pData, int size) { + return CFX_GEModule::Get()->GetFontMgr()->GetFixedFace(pData, size, 0); +} + +} // namespace + +CFX_Font::CFX_Font() { + m_pSubstFont = NULL; + m_Face = NULL; + m_bEmbedded = FALSE; + m_bVertical = FALSE; + m_pFontData = NULL; + m_pFontDataAllocation = NULL; + m_dwSize = 0; + m_pGsubData = NULL; + m_pPlatformFont = NULL; + m_pPlatformFontCollection = NULL; + m_pDwFont = NULL; + m_hHandle = NULL; + m_bDwLoaded = FALSE; +#ifdef PDF_ENABLE_XFA + m_bLogic = FALSE; + m_pOwnedStream = NULL; +#endif // PDF_ENABLE_XFA +} + +#ifdef PDF_ENABLE_XFA +FX_BOOL CFX_Font::LoadClone(const CFX_Font* pFont) { + if (pFont == NULL) { + return FALSE; + } + m_bLogic = TRUE; + if (pFont->m_pSubstFont) { + m_pSubstFont = new CFX_SubstFont; + m_pSubstFont->m_Charset = pFont->m_pSubstFont->m_Charset; + m_pSubstFont->m_ExtHandle = pFont->m_pSubstFont->m_ExtHandle; + m_pSubstFont->m_SubstFlags = pFont->m_pSubstFont->m_SubstFlags; + m_pSubstFont->m_Weight = pFont->m_pSubstFont->m_Weight; + m_pSubstFont->m_Family = pFont->m_pSubstFont->m_Family; + m_pSubstFont->m_ItalicAngle = pFont->m_pSubstFont->m_ItalicAngle; + } + if (pFont->m_OtfFontData.GetSize()) { + m_OtfFontData.AttachData(pFont->m_OtfFontData.GetBuffer(), + pFont->m_OtfFontData.GetSize()); + } + m_Face = pFont->m_Face; + m_bEmbedded = pFont->m_bEmbedded; + m_bVertical = pFont->m_bVertical; + m_dwSize = pFont->m_dwSize; + m_pFontData = pFont->m_pFontData; + m_pGsubData = pFont->m_pGsubData; + m_pPlatformFont = pFont->m_pPlatformFont; + m_pPlatformFontCollection = pFont->m_pPlatformFontCollection; + m_pDwFont = pFont->m_pDwFont; + m_hHandle = pFont->m_hHandle; + m_bDwLoaded = pFont->m_bDwLoaded; + m_pOwnedStream = pFont->m_pOwnedStream; + return TRUE; +} +#endif // PDF_ENABLE_XFA + +CFX_Font::~CFX_Font() { + delete m_pSubstFont; + FX_Free(m_pFontDataAllocation); +#ifdef PDF_ENABLE_XFA + if (m_bLogic) { + m_OtfFontData.DetachBuffer(); + return; + } +#endif // PDF_ENABLE_XFA + if (m_Face) { +#ifndef PDF_ENABLE_XFA + if (FXFT_Get_Face_External_Stream(m_Face)) { + FXFT_Clear_Face_External_Stream(m_Face); + } +#endif // PDF_ENABLE_XFA + if (m_bEmbedded) { + DeleteFace(); + } else { + CFX_GEModule::Get()->GetFontMgr()->ReleaseFace(m_Face); + } + } +#ifdef PDF_ENABLE_XFA + FX_Free(m_pOwnedStream); +#endif // PDF_ENABLE_XFA + FX_Free(m_pGsubData); +#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ + ReleasePlatformResource(); +#endif +} +void CFX_Font::DeleteFace() { + FXFT_Done_Face(m_Face); + m_Face = NULL; +} +void CFX_Font::LoadSubst(const CFX_ByteString& face_name, + FX_BOOL bTrueType, + FX_DWORD flags, + int weight, + int italic_angle, + int CharsetCP, + FX_BOOL bVertical) { + m_bEmbedded = FALSE; + m_bVertical = bVertical; + m_pSubstFont = new CFX_SubstFont; + m_Face = CFX_GEModule::Get()->GetFontMgr()->FindSubstFont( + face_name, bTrueType, flags, weight, italic_angle, CharsetCP, + m_pSubstFont); +#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ + if (m_pSubstFont->m_ExtHandle) { + m_pPlatformFont = m_pSubstFont->m_ExtHandle; + m_pSubstFont->m_ExtHandle = NULL; + } +#endif + if (m_Face) { + m_pFontData = FXFT_Get_Face_Stream_Base(m_Face); + m_dwSize = FXFT_Get_Face_Stream_Size(m_Face); + } +} +#ifdef PDF_ENABLE_XFA +extern "C" { +unsigned long _FTStreamRead(FXFT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count) { + if (count == 0) { + return 0; + } + IFX_FileRead* pFile = (IFX_FileRead*)stream->descriptor.pointer; + int res = pFile->ReadBlock(buffer, offset, count); + if (res) { + return count; + } + return 0; +} +void _FTStreamClose(FXFT_Stream stream) {} +}; +FX_BOOL _LoadFile(FXFT_Library library, + FXFT_Face* Face, + IFX_FileRead* pFile, + FXFT_Stream* stream, + int32_t faceIndex = 0) { + FXFT_Stream stream1 = (FXFT_Stream)FX_Alloc(uint8_t, sizeof(FXFT_StreamRec)); + stream1->base = NULL; + stream1->size = (unsigned long)pFile->GetSize(); + stream1->pos = 0; + stream1->descriptor.pointer = pFile; + stream1->close = _FTStreamClose; + stream1->read = _FTStreamRead; + FXFT_Open_Args args; + args.flags = FT_OPEN_STREAM; + args.stream = stream1; + if (FXFT_Open_Face(library, &args, faceIndex, Face)) { + FX_Free(stream1); + return FALSE; + } + if (stream) { + *stream = stream1; + } + return TRUE; +} + +FX_BOOL CFX_Font::LoadFile(IFX_FileRead* pFile, + int nFaceIndex, + int* pFaceCount) { + m_bEmbedded = FALSE; + + CFX_FontMgr* pFontMgr = CFX_GEModule::Get()->GetFontMgr(); + pFontMgr->InitFTLibrary(); + FXFT_Library library = pFontMgr->GetFTLibrary(); + + FXFT_Stream stream = nullptr; + if (!_LoadFile(library, &m_Face, pFile, &stream, nFaceIndex)) + return FALSE; + + if (pFaceCount) + *pFaceCount = (int)m_Face->num_faces; + m_pOwnedStream = stream; + FXFT_Set_Pixel_Sizes(m_Face, 0, 64); + return TRUE; +} +#endif // PDF_ENABLE_XFA + +int CFX_Font::GetGlyphWidth(FX_DWORD glyph_index) { + if (!m_Face) { + return 0; + } + if (m_pSubstFont && (m_pSubstFont->m_SubstFlags & FXFONT_SUBST_MM)) { + AdjustMMParams(glyph_index, 0, 0); + } + int err = FXFT_Load_Glyph( + m_Face, glyph_index, + FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH); + if (err) { + return 0; + } + int width = EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face), + FXFT_Get_Glyph_HoriAdvance(m_Face)); + return width; +} + +FX_BOOL CFX_Font::LoadEmbedded(const uint8_t* data, FX_DWORD size) { + m_pFontDataAllocation = FX_Alloc(uint8_t, size); + FXSYS_memcpy(m_pFontDataAllocation, data, size); + m_Face = FT_LoadFont(m_pFontDataAllocation, size); + m_pFontData = m_pFontDataAllocation; + m_bEmbedded = TRUE; + m_dwSize = size; + return m_Face != NULL; +} + +FX_BOOL CFX_Font::IsTTFont() const { + if (!m_Face) + return FALSE; + return FXFT_Is_Face_TT_OT(m_Face) == FXFT_FACE_FLAG_SFNT; +} + +int CFX_Font::GetAscent() const { + if (!m_Face) + return 0; + return EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face), + FXFT_Get_Face_Ascender(m_Face)); +} + +int CFX_Font::GetDescent() const { + if (!m_Face) + return 0; + return EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face), + FXFT_Get_Face_Descender(m_Face)); +} + +FX_BOOL CFX_Font::GetGlyphBBox(FX_DWORD glyph_index, FX_RECT& bbox) { + if (!m_Face) + return FALSE; + + if (FXFT_Is_Face_Tricky(m_Face)) { + int error = FXFT_Set_Char_Size(m_Face, 0, 1000 * 64, 72, 72); + if (error) { + return FALSE; + } + error = FXFT_Load_Glyph(m_Face, glyph_index, + FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH); + if (error) { + return FALSE; + } + FXFT_BBox cbox; + FT_Glyph glyph; + error = FXFT_Get_Glyph(((FXFT_Face)m_Face)->glyph, &glyph); + if (error) { + return FALSE; + } + FXFT_Glyph_Get_CBox(glyph, FXFT_GLYPH_BBOX_PIXELS, &cbox); + int pixel_size_x = ((FXFT_Face)m_Face)->size->metrics.x_ppem, + pixel_size_y = ((FXFT_Face)m_Face)->size->metrics.y_ppem; + if (pixel_size_x == 0 || pixel_size_y == 0) { + bbox.left = cbox.xMin; + bbox.right = cbox.xMax; + bbox.top = cbox.yMax; + bbox.bottom = cbox.yMin; + } else { + bbox.left = cbox.xMin * 1000 / pixel_size_x; + bbox.right = cbox.xMax * 1000 / pixel_size_x; + bbox.top = cbox.yMax * 1000 / pixel_size_y; + bbox.bottom = cbox.yMin * 1000 / pixel_size_y; + } + if (bbox.top > FXFT_Get_Face_Ascender(m_Face)) { + bbox.top = FXFT_Get_Face_Ascender(m_Face); + } + if (bbox.bottom < FXFT_Get_Face_Descender(m_Face)) { + bbox.bottom = FXFT_Get_Face_Descender(m_Face); + } + FT_Done_Glyph(glyph); + return FXFT_Set_Pixel_Sizes(m_Face, 0, 64) == 0; + } + if (FXFT_Load_Glyph( + m_Face, glyph_index, + FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH)) { + return FALSE; + } + int em = FXFT_Get_Face_UnitsPerEM(m_Face); + if (em == 0) { + bbox.left = FXFT_Get_Glyph_HoriBearingX(m_Face); + bbox.bottom = FXFT_Get_Glyph_HoriBearingY(m_Face); + bbox.top = bbox.bottom - FXFT_Get_Glyph_Height(m_Face); + bbox.right = bbox.left + FXFT_Get_Glyph_Width(m_Face); + } else { + bbox.left = FXFT_Get_Glyph_HoriBearingX(m_Face) * 1000 / em; + bbox.top = + (FXFT_Get_Glyph_HoriBearingY(m_Face) - FXFT_Get_Glyph_Height(m_Face)) * + 1000 / em; + bbox.right = + (FXFT_Get_Glyph_HoriBearingX(m_Face) + FXFT_Get_Glyph_Width(m_Face)) * + 1000 / em; + bbox.bottom = (FXFT_Get_Glyph_HoriBearingY(m_Face)) * 1000 / em; + } + return TRUE; +} + +FX_BOOL CFX_Font::IsItalic() const { + if (!m_Face) + return FALSE; + + FX_BOOL ret = FXFT_Is_Face_Italic(m_Face) == FXFT_STYLE_FLAG_ITALIC; + if (!ret) { + CFX_ByteString str(FXFT_Get_Face_Style_Name(m_Face)); + str.MakeLower(); + if (str.Find("italic") != -1) { + ret = TRUE; + } + } + return ret; +} + +FX_BOOL CFX_Font::IsBold() const { + if (!m_Face) + return FALSE; + return FXFT_Is_Face_Bold(m_Face) == FXFT_STYLE_FLAG_BOLD; +} + +FX_BOOL CFX_Font::IsFixedWidth() const { + if (!m_Face) + return FALSE; + return FXFT_Is_Face_fixedwidth(m_Face); +} + +CFX_WideString CFX_Font::GetPsName() const { + if (!m_Face) { + return CFX_WideString(); + } + CFX_WideString psName = + CFX_WideString::FromLocal(FXFT_Get_Postscript_Name(m_Face)); + if (psName.IsEmpty()) { + psName = CFX_WideString::FromLocal("Untitled"); + } + return psName; +} +CFX_ByteString CFX_Font::GetFamilyName() const { + if (!m_Face && !m_pSubstFont) { + return CFX_ByteString(); + } + if (m_Face) { + return CFX_ByteString(FXFT_Get_Face_Family_Name(m_Face)); + } + return m_pSubstFont->m_Family; +} +CFX_ByteString CFX_Font::GetFaceName() const { + if (!m_Face && !m_pSubstFont) { + return CFX_ByteString(); + } + if (m_Face) { + CFX_ByteString facename; + CFX_ByteString style = CFX_ByteString(FXFT_Get_Face_Style_Name(m_Face)); + facename = GetFamilyName(); + if (facename.IsEmpty()) { + facename = "Untitled"; + } + if (!style.IsEmpty() && style != "Regular") { + facename += " " + style; + } + return facename; + } + return m_pSubstFont->m_Family; +} +FX_BOOL CFX_Font::GetBBox(FX_RECT& bbox) { + if (!m_Face) { + return FALSE; + } + int em = FXFT_Get_Face_UnitsPerEM(m_Face); + if (em == 0) { + bbox.left = FXFT_Get_Face_xMin(m_Face); + bbox.bottom = FXFT_Get_Face_yMax(m_Face); + bbox.top = FXFT_Get_Face_yMin(m_Face); + bbox.right = FXFT_Get_Face_xMax(m_Face); + } else { + bbox.left = FXFT_Get_Face_xMin(m_Face) * 1000 / em; + bbox.top = FXFT_Get_Face_yMin(m_Face) * 1000 / em; + bbox.right = FXFT_Get_Face_xMax(m_Face) * 1000 / em; + bbox.bottom = FXFT_Get_Face_yMax(m_Face) * 1000 / em; + } + return TRUE; +} + +int CFX_Font::GetHeight() const { + if (!m_Face) + return 0; + + return EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face), + FXFT_Get_Face_Height(m_Face)); +} + +int CFX_Font::GetMaxAdvanceWidth() const { + if (!m_Face) + return 0; + + return EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face), + FXFT_Get_Face_MaxAdvanceWidth(m_Face)); +} + +int CFX_Font::GetULPos() const { + if (!m_Face) + return 0; + + return EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face), + FXFT_Get_Face_UnderLinePosition(m_Face)); +} + +int CFX_Font::GetULthickness() const { + if (!m_Face) + return 0; + + return EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face), + FXFT_Get_Face_UnderLineThickness(m_Face)); +} + +CFX_UnicodeEncoding::CFX_UnicodeEncoding(CFX_Font* pFont) : m_pFont(pFont) {} + +CFX_UnicodeEncoding::~CFX_UnicodeEncoding() {} + +FX_DWORD CFX_UnicodeEncoding::GlyphFromCharCode(FX_DWORD charcode) { + FXFT_Face face = m_pFont->GetFace(); + if (!face) + return charcode; + + if (FXFT_Select_Charmap(face, FXFT_ENCODING_UNICODE) == 0) + return FXFT_Get_Char_Index(face, charcode); + + if (m_pFont->GetSubstFont() && m_pFont->GetSubstFont()->m_Charset == 2) { + FX_DWORD index = 0; + if (FXFT_Select_Charmap(face, FXFT_ENCODING_MS_SYMBOL) == 0) + index = FXFT_Get_Char_Index(face, charcode); + if (!index && !FXFT_Select_Charmap(face, FXFT_ENCODING_APPLE_ROMAN)) + return FXFT_Get_Char_Index(face, charcode); + } + return charcode; +} + +#ifdef PDF_ENABLE_XFA +CFX_UnicodeEncodingEx::CFX_UnicodeEncodingEx(CFX_Font* pFont, + FX_DWORD EncodingID) + : CFX_UnicodeEncoding(pFont), m_nEncodingID(EncodingID) {} + +CFX_UnicodeEncodingEx::~CFX_UnicodeEncodingEx() {} + +FX_DWORD CFX_UnicodeEncodingEx::GlyphFromCharCode(FX_DWORD charcode) { + FXFT_Face face = m_pFont->GetFace(); + FT_UInt nIndex = FXFT_Get_Char_Index(face, charcode); + if (nIndex > 0) { + return nIndex; + } + int nmaps = FXFT_Get_Face_CharmapCount(face); + int m = 0; + while (m < nmaps) { + int nEncodingID = + FXFT_Get_Charmap_Encoding(FXFT_Get_Face_Charmaps(face)[m++]); + if (m_nEncodingID == nEncodingID) { + continue; + } + int error = FXFT_Select_Charmap(face, nEncodingID); + if (error) { + continue; + } + nIndex = FXFT_Get_Char_Index(face, charcode); + if (nIndex > 0) { + m_nEncodingID = nEncodingID; + return nIndex; + } + } + FXFT_Select_Charmap(face, m_nEncodingID); + return 0; +} + +FX_DWORD CFX_UnicodeEncodingEx::CharCodeFromUnicode(FX_WCHAR Unicode) const { + if (m_nEncodingID == FXFM_ENCODING_UNICODE || + m_nEncodingID == FXFM_ENCODING_MS_SYMBOL) { + return Unicode; + } + FXFT_Face face = m_pFont->GetFace(); + int nmaps = FXFT_Get_Face_CharmapCount(face); + for (int i = 0; i < nmaps; i++) { + int nEncodingID = + FXFT_Get_Charmap_Encoding(FXFT_Get_Face_Charmaps(face)[i]); + if (nEncodingID == FXFM_ENCODING_UNICODE || + nEncodingID == FXFM_ENCODING_MS_SYMBOL) { + return Unicode; + } + } + return -1; +} + +CFX_UnicodeEncodingEx* FX_CreateFontEncodingEx(CFX_Font* pFont, + FX_DWORD nEncodingID) { + if (!pFont || !pFont->GetFace()) + return nullptr; + + if (nEncodingID != FXFM_ENCODING_NONE) + return _FXFM_CreateFontEncoding(pFont, nEncodingID); + + for (size_t i = 0; i < FX_ArraySize(g_EncodingID); ++i) { + CFX_UnicodeEncodingEx* pFontEncoding = + _FXFM_CreateFontEncoding(pFont, g_EncodingID[i]); + if (pFontEncoding) { + return pFontEncoding; + } + } + return NULL; +} +#endif // PDF_ENABLE_XFA diff --git a/core/fxge/ge/fx_ge_fontmap.cpp b/core/fxge/ge/fx_ge_fontmap.cpp new file mode 100644 index 0000000000..1dc61a210f --- /dev/null +++ b/core/fxge/ge/fx_ge_fontmap.cpp @@ -0,0 +1,1623 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include <algorithm> +#include <limits> +#include <vector> + +#include "core/fxge/fontdata/chromefontdata/chromefontdata.h" +#include "core/fxge/ge/fx_text_int.h" +#include "core/include/fxge/fx_freetype.h" +#include "core/include/fxge/fx_ge.h" +#include "third_party/base/stl_util.h" + +#define GET_TT_SHORT(w) (FX_WORD)(((w)[0] << 8) | (w)[1]) +#define GET_TT_LONG(w) \ + (FX_DWORD)(((w)[0] << 24) | ((w)[1] << 16) | ((w)[2] << 8) | (w)[3]) + +#define FX_FONT_STYLE_None 0x00 +#define FX_FONT_STYLE_Bold 0x01 +#define FX_FONT_STYLE_Italic 0x02 +#define FX_FONT_STYLE_BoldBold 0x04 + +namespace { + +struct BuiltinFont { + const uint8_t* m_pFontData; + FX_DWORD m_dwSize; +}; + +const BuiltinFont g_FoxitFonts[14] = { + {g_FoxitFixedFontData, 17597}, + {g_FoxitFixedBoldFontData, 18055}, + {g_FoxitFixedBoldItalicFontData, 19151}, + {g_FoxitFixedItalicFontData, 18746}, + {g_FoxitSansFontData, 15025}, + {g_FoxitSansBoldFontData, 16344}, + {g_FoxitSansBoldItalicFontData, 16418}, + {g_FoxitSansItalicFontData, 16339}, + {g_FoxitSerifFontData, 19469}, + {g_FoxitSerifBoldFontData, 19395}, + {g_FoxitSerifBoldItalicFontData, 20733}, + {g_FoxitSerifItalicFontData, 21227}, + {g_FoxitSymbolFontData, 16729}, + {g_FoxitDingbatsFontData, 29513}, +}; + +const BuiltinFont g_MMFonts[2] = { + {g_FoxitSerifMMFontData, 113417}, + {g_FoxitSansMMFontData, 66919}, +}; + +const FX_CHAR* const g_Base14FontNames[14] = { + "Courier", + "Courier-Bold", + "Courier-BoldOblique", + "Courier-Oblique", + "Helvetica", + "Helvetica-Bold", + "Helvetica-BoldOblique", + "Helvetica-Oblique", + "Times-Roman", + "Times-Bold", + "Times-BoldItalic", + "Times-Italic", + "Symbol", + "ZapfDingbats", +}; + +const struct AltFontName { + const FX_CHAR* m_pName; + int m_Index; +} g_AltFontNames[] = { + {"Arial", 4}, + {"Arial,Bold", 5}, + {"Arial,BoldItalic", 6}, + {"Arial,Italic", 7}, + {"Arial-Bold", 5}, + {"Arial-BoldItalic", 6}, + {"Arial-BoldItalicMT", 6}, + {"Arial-BoldMT", 5}, + {"Arial-Italic", 7}, + {"Arial-ItalicMT", 7}, + {"ArialBold", 5}, + {"ArialBoldItalic", 6}, + {"ArialItalic", 7}, + {"ArialMT", 4}, + {"ArialMT,Bold", 5}, + {"ArialMT,BoldItalic", 6}, + {"ArialMT,Italic", 7}, + {"ArialRoundedMTBold", 5}, + {"Courier", 0}, + {"Courier,Bold", 1}, + {"Courier,BoldItalic", 2}, + {"Courier,Italic", 3}, + {"Courier-Bold", 1}, + {"Courier-BoldOblique", 2}, + {"Courier-Oblique", 3}, + {"CourierBold", 1}, + {"CourierBoldItalic", 2}, + {"CourierItalic", 3}, + {"CourierNew", 0}, + {"CourierNew,Bold", 1}, + {"CourierNew,BoldItalic", 2}, + {"CourierNew,Italic", 3}, + {"CourierNew-Bold", 1}, + {"CourierNew-BoldItalic", 2}, + {"CourierNew-Italic", 3}, + {"CourierNewBold", 1}, + {"CourierNewBoldItalic", 2}, + {"CourierNewItalic", 3}, + {"CourierNewPS-BoldItalicMT", 2}, + {"CourierNewPS-BoldMT", 1}, + {"CourierNewPS-ItalicMT", 3}, + {"CourierNewPSMT", 0}, + {"CourierStd", 0}, + {"CourierStd-Bold", 1}, + {"CourierStd-BoldOblique", 2}, + {"CourierStd-Oblique", 3}, + {"Helvetica", 4}, + {"Helvetica,Bold", 5}, + {"Helvetica,BoldItalic", 6}, + {"Helvetica,Italic", 7}, + {"Helvetica-Bold", 5}, + {"Helvetica-BoldItalic", 6}, + {"Helvetica-BoldOblique", 6}, + {"Helvetica-Italic", 7}, + {"Helvetica-Oblique", 7}, + {"HelveticaBold", 5}, + {"HelveticaBoldItalic", 6}, + {"HelveticaItalic", 7}, + {"Symbol", 12}, + {"SymbolMT", 12}, + {"Times-Bold", 9}, + {"Times-BoldItalic", 10}, + {"Times-Italic", 11}, + {"Times-Roman", 8}, + {"TimesBold", 9}, + {"TimesBoldItalic", 10}, + {"TimesItalic", 11}, + {"TimesNewRoman", 8}, + {"TimesNewRoman,Bold", 9}, + {"TimesNewRoman,BoldItalic", 10}, + {"TimesNewRoman,Italic", 11}, + {"TimesNewRoman-Bold", 9}, + {"TimesNewRoman-BoldItalic", 10}, + {"TimesNewRoman-Italic", 11}, + {"TimesNewRomanBold", 9}, + {"TimesNewRomanBoldItalic", 10}, + {"TimesNewRomanItalic", 11}, + {"TimesNewRomanPS", 8}, + {"TimesNewRomanPS-Bold", 9}, + {"TimesNewRomanPS-BoldItalic", 10}, + {"TimesNewRomanPS-BoldItalicMT", 10}, + {"TimesNewRomanPS-BoldMT", 9}, + {"TimesNewRomanPS-Italic", 11}, + {"TimesNewRomanPS-ItalicMT", 11}, + {"TimesNewRomanPSMT", 8}, + {"TimesNewRomanPSMT,Bold", 9}, + {"TimesNewRomanPSMT,BoldItalic", 10}, + {"TimesNewRomanPSMT,Italic", 11}, + {"ZapfDingbats", 13}, +}; + +const struct { + const FX_CHAR* m_pName; + const FX_CHAR* m_pSubstName; +} Base14Substs[] = { + {"Courier", "Courier New"}, + {"Courier-Bold", "Courier New Bold"}, + {"Courier-BoldOblique", "Courier New Bold Italic"}, + {"Courier-Oblique", "Courier New Italic"}, + {"Helvetica", "Arial"}, + {"Helvetica-Bold", "Arial Bold"}, + {"Helvetica-BoldOblique", "Arial Bold Italic"}, + {"Helvetica-Oblique", "Arial Italic"}, + {"Times-Roman", "Times New Roman"}, + {"Times-Bold", "Times New Roman Bold"}, + {"Times-BoldItalic", "Times New Roman Bold Italic"}, + {"Times-Italic", "Times New Roman Italic"}, +}; + +const struct AltFontFamily { + const FX_CHAR* m_pFontName; + const FX_CHAR* m_pFontFamily; +} g_AltFontFamilies[] = { + {"AGaramondPro", "Adobe Garamond Pro"}, + {"BankGothicBT-Medium", "BankGothic Md BT"}, + {"ForteMT", "Forte"}, +}; + +const struct FX_FontStyle { + const FX_CHAR* style; + int32_t len; +} g_FontStyles[] = { + {"Bold", 4}, {"Italic", 6}, {"BoldItalic", 10}, {"Reg", 3}, {"Regular", 7}, +}; + +const struct CODEPAGE_MAP { + FX_WORD codepage; + uint8_t charset; +} g_Codepage2CharsetTable[] = { + {0, 1}, {42, 2}, {437, 254}, {850, 255}, {874, 222}, + {932, 128}, {936, 134}, {949, 129}, {950, 136}, {1250, 238}, + {1251, 204}, {1252, 0}, {1253, 161}, {1254, 162}, {1255, 177}, + {1256, 178}, {1257, 186}, {1258, 163}, {1361, 130}, {10000, 77}, + {10001, 78}, {10002, 81}, {10003, 79}, {10004, 84}, {10005, 83}, + {10006, 85}, {10007, 89}, {10008, 80}, {10021, 87}, {10029, 88}, + {10081, 86}, +}; + +const FX_DWORD kTableNAME = FXDWORD_GET_MSBFIRST("name"); +const FX_DWORD kTableTTCF = FXDWORD_GET_MSBFIRST("ttcf"); + +int CompareFontFamilyString(const void* key, const void* element) { + CFX_ByteString str_key((const FX_CHAR*)key); + if (str_key.Find(((AltFontFamily*)element)->m_pFontName) != -1) { + return 0; + } + return FXSYS_stricmp((const FX_CHAR*)key, + ((AltFontFamily*)element)->m_pFontName); +} + +int CompareString(const void* key, const void* element) { + return FXSYS_stricmp((const FX_CHAR*)key, ((AltFontName*)element)->m_pName); +} + +CFX_ByteString KeyNameFromFace(const CFX_ByteString& face_name, + int weight, + FX_BOOL bItalic) { + CFX_ByteString key(face_name); + key += ','; + key += CFX_ByteString::FormatInteger(weight); + key += bItalic ? 'I' : 'N'; + return key; +} + +CFX_ByteString KeyNameFromSize(int ttc_size, FX_DWORD checksum) { + CFX_ByteString key; + key.Format("%d:%d", ttc_size, checksum); + return key; +} + +CFX_ByteString TT_NormalizeName(const FX_CHAR* family) { + CFX_ByteString norm(family); + norm.Remove(' '); + norm.Remove('-'); + norm.Remove(','); + int pos = norm.Find('+'); + if (pos > 0) { + norm = norm.Left(pos); + } + norm.MakeLower(); + return norm; +} + +CFX_ByteString FPDF_ReadStringFromFile(FXSYS_FILE* pFile, FX_DWORD size) { + CFX_ByteString buffer; + if (!FXSYS_fread(buffer.GetBuffer(size), size, 1, pFile)) { + return CFX_ByteString(); + } + buffer.ReleaseBuffer(size); + return buffer; +} + +CFX_ByteString FPDF_LoadTableFromTT(FXSYS_FILE* pFile, + const uint8_t* pTables, + FX_DWORD nTables, + FX_DWORD tag) { + for (FX_DWORD i = 0; i < nTables; i++) { + const uint8_t* p = pTables + i * 16; + if (GET_TT_LONG(p) == tag) { + FX_DWORD offset = GET_TT_LONG(p + 8); + FX_DWORD size = GET_TT_LONG(p + 12); + FXSYS_fseek(pFile, offset, FXSYS_SEEK_SET); + return FPDF_ReadStringFromFile(pFile, size); + } + } + return CFX_ByteString(); +} + +uint8_t GetCharsetFromCodePage(FX_WORD codepage) { + const CODEPAGE_MAP* pEnd = + g_Codepage2CharsetTable + FX_ArraySize(g_Codepage2CharsetTable); + const CODEPAGE_MAP* pCharmap = + std::lower_bound(g_Codepage2CharsetTable, pEnd, codepage, + [](const CODEPAGE_MAP& charset, FX_WORD page) { + return charset.codepage < page; + }); + if (pCharmap < pEnd && codepage == pCharmap->codepage) + return pCharmap->charset; + return 1; +} + +CFX_ByteString GetFontFamily(CFX_ByteString fontName, int nStyle) { + if (fontName.Find("Script") >= 0) { + if ((nStyle & FX_FONT_STYLE_Bold) == FX_FONT_STYLE_Bold) { + fontName = "ScriptMTBold"; + } else if (fontName.Find("Palace") >= 0) { + fontName = "PalaceScriptMT"; + } else if (fontName.Find("French") >= 0) { + fontName = "FrenchScriptMT"; + } else if (fontName.Find("FreeStyle") >= 0) { + fontName = "FreeStyleScript"; + } + return fontName; + } + AltFontFamily* found = (AltFontFamily*)FXSYS_bsearch( + fontName.c_str(), g_AltFontFamilies, + sizeof g_AltFontFamilies / sizeof(AltFontFamily), sizeof(AltFontFamily), + CompareFontFamilyString); + return found ? CFX_ByteString(found->m_pFontFamily) : fontName; +} + +CFX_ByteString ParseStyle(const FX_CHAR* pStyle, int iLen, int iIndex) { + CFX_ByteTextBuf buf; + if (!iLen || iLen <= iIndex) { + return buf.GetByteString(); + } + while (iIndex < iLen) { + if (pStyle[iIndex] == ',') { + break; + } + buf.AppendChar(pStyle[iIndex]); + ++iIndex; + } + return buf.GetByteString(); +} + +int32_t GetStyleType(const CFX_ByteString& bsStyle, FX_BOOL bRevert) { + int32_t iLen = bsStyle.GetLength(); + if (!iLen) { + return -1; + } + int iSize = sizeof(g_FontStyles) / sizeof(FX_FontStyle); + const FX_FontStyle* pStyle = NULL; + for (int i = iSize - 1; i >= 0; --i) { + pStyle = g_FontStyles + i; + if (!pStyle || pStyle->len > iLen) { + continue; + } + if (!bRevert) { + if (bsStyle.Left(pStyle->len).Compare(pStyle->style) == 0) { + return i; + } + } else { + if (bsStyle.Right(pStyle->len).Compare(pStyle->style) == 0) { + return i; + } + } + } + return -1; +} + +FX_BOOL CheckSupportThirdPartFont(CFX_ByteString name, int& PitchFamily) { + if (name == "MyriadPro") { + PitchFamily &= ~FXFONT_FF_ROMAN; + return TRUE; + } + return FALSE; +} + +FX_DWORD GetCharset(int charset) { + switch (charset) { + case FXFONT_SHIFTJIS_CHARSET: + return CHARSET_FLAG_SHIFTJIS; + case FXFONT_GB2312_CHARSET: + return CHARSET_FLAG_GB; + case FXFONT_CHINESEBIG5_CHARSET: + return CHARSET_FLAG_BIG5; + case FXFONT_HANGEUL_CHARSET: + return CHARSET_FLAG_KOREAN; + case FXFONT_SYMBOL_CHARSET: + return CHARSET_FLAG_SYMBOL; + case FXFONT_ANSI_CHARSET: + return CHARSET_FLAG_ANSI; + default: + break; + } + return 0; +} + +int32_t GetSimilarValue(int weight, + FX_BOOL bItalic, + int pitch_family, + FX_DWORD style) { + int32_t iSimilarValue = 0; + if (!!(style & FXFONT_BOLD) == (weight > 400)) { + iSimilarValue += 16; + } + if (!!(style & FXFONT_ITALIC) == bItalic) { + iSimilarValue += 16; + } + if (!!(style & FXFONT_SERIF) == !!(pitch_family & FXFONT_FF_ROMAN)) { + iSimilarValue += 16; + } + if (!!(style & FXFONT_SCRIPT) == !!(pitch_family & FXFONT_FF_SCRIPT)) { + iSimilarValue += 8; + } + if (!!(style & FXFONT_FIXED_PITCH) == + !!(pitch_family & FXFONT_FF_FIXEDPITCH)) { + iSimilarValue += 8; + } + return iSimilarValue; +} + +} // namespace + +CFX_SubstFont::CFX_SubstFont() { + m_ExtHandle = NULL; + m_Charset = 0; + m_SubstFlags = 0; + m_Weight = 0; + m_ItalicAngle = 0; + m_bSubstOfCJK = FALSE; + m_WeightCJK = 0; + m_bItlicCJK = FALSE; +} +CTTFontDesc::~CTTFontDesc() { + if (m_Type == 1) { + if (m_SingleFace.m_pFace) { + FXFT_Done_Face(m_SingleFace.m_pFace); + } + } else if (m_Type == 2) { + for (int i = 0; i < 16; i++) + if (m_TTCFace.m_pFaces[i]) { + FXFT_Done_Face(m_TTCFace.m_pFaces[i]); + } + } + FX_Free(m_pFontData); +} +int CTTFontDesc::ReleaseFace(FXFT_Face face) { + if (m_Type == 1) { + if (m_SingleFace.m_pFace != face) { + return -1; + } + } else if (m_Type == 2) { + int i; + for (i = 0; i < 16; i++) + if (m_TTCFace.m_pFaces[i] == face) { + break; + } + if (i == 16) { + return -1; + } + } + m_RefCount--; + if (m_RefCount) { + return m_RefCount; + } + delete this; + return 0; +} + +CFX_FontMgr::CFX_FontMgr() : m_FTLibrary(nullptr) { + m_pBuiltinMapper.reset(new CFX_FontMapper(this)); +} + +CFX_FontMgr::~CFX_FontMgr() { + for (const auto& pair : m_FaceMap) + delete pair.second; + + // |m_pBuiltinMapper| references |m_FTLibrary|, so it has to be destroyed + // first. + m_pBuiltinMapper.reset(); + FXFT_Done_FreeType(m_FTLibrary); +} + +void CFX_FontMgr::InitFTLibrary() { + if (m_FTLibrary) + return; + FXFT_Init_FreeType(&m_FTLibrary); +} + +void CFX_FontMgr::SetSystemFontInfo(IFX_SystemFontInfo* pFontInfo) { + m_pBuiltinMapper->SetSystemFontInfo(pFontInfo); +} + +FXFT_Face CFX_FontMgr::FindSubstFont(const CFX_ByteString& face_name, + FX_BOOL bTrueType, + FX_DWORD flags, + int weight, + int italic_angle, + int CharsetCP, + CFX_SubstFont* pSubstFont) { + InitFTLibrary(); + return m_pBuiltinMapper->FindSubstFont(face_name, bTrueType, flags, weight, + italic_angle, CharsetCP, pSubstFont); +} + +FXFT_Face CFX_FontMgr::GetCachedFace(const CFX_ByteString& face_name, + int weight, + FX_BOOL bItalic, + uint8_t*& pFontData) { + auto it = m_FaceMap.find(KeyNameFromFace(face_name, weight, bItalic)); + if (it == m_FaceMap.end()) + return nullptr; + + CTTFontDesc* pFontDesc = it->second; + pFontData = pFontDesc->m_pFontData; + pFontDesc->m_RefCount++; + return pFontDesc->m_SingleFace.m_pFace; +} +FXFT_Face CFX_FontMgr::AddCachedFace(const CFX_ByteString& face_name, + int weight, + FX_BOOL bItalic, + uint8_t* pData, + FX_DWORD size, + int face_index) { + CTTFontDesc* pFontDesc = new CTTFontDesc; + pFontDesc->m_Type = 1; + pFontDesc->m_SingleFace.m_pFace = NULL; + pFontDesc->m_SingleFace.m_bBold = weight; + pFontDesc->m_SingleFace.m_bItalic = bItalic; + pFontDesc->m_pFontData = pData; + pFontDesc->m_RefCount = 1; + + InitFTLibrary(); + FXFT_Library library = m_FTLibrary; + int ret = FXFT_New_Memory_Face(library, pData, size, face_index, + &pFontDesc->m_SingleFace.m_pFace); + if (ret) { + delete pFontDesc; + return NULL; + } + ret = FXFT_Set_Pixel_Sizes(pFontDesc->m_SingleFace.m_pFace, 64, 64); + if (ret) { + delete pFontDesc; + return NULL; + } + m_FaceMap[KeyNameFromFace(face_name, weight, bItalic)] = pFontDesc; + return pFontDesc->m_SingleFace.m_pFace; +} + +int GetTTCIndex(const uint8_t* pFontData, + FX_DWORD ttc_size, + FX_DWORD font_offset) { + int face_index = 0; + const uint8_t* p = pFontData + 8; + FX_DWORD nfont = GET_TT_LONG(p); + FX_DWORD index; + for (index = 0; index < nfont; index++) { + p = pFontData + 12 + index * 4; + if (GET_TT_LONG(p) == font_offset) { + break; + } + } + if (index >= nfont) { + face_index = 0; + } else { + face_index = index; + } + return face_index; +} +FXFT_Face CFX_FontMgr::GetCachedTTCFace(int ttc_size, + FX_DWORD checksum, + int font_offset, + uint8_t*& pFontData) { + auto it = m_FaceMap.find(KeyNameFromSize(ttc_size, checksum)); + if (it == m_FaceMap.end()) + return nullptr; + + CTTFontDesc* pFontDesc = it->second; + pFontData = pFontDesc->m_pFontData; + pFontDesc->m_RefCount++; + int face_index = GetTTCIndex(pFontDesc->m_pFontData, ttc_size, font_offset); + if (!pFontDesc->m_TTCFace.m_pFaces[face_index]) { + pFontDesc->m_TTCFace.m_pFaces[face_index] = + GetFixedFace(pFontDesc->m_pFontData, ttc_size, face_index); + } + return pFontDesc->m_TTCFace.m_pFaces[face_index]; +} +FXFT_Face CFX_FontMgr::AddCachedTTCFace(int ttc_size, + FX_DWORD checksum, + uint8_t* pData, + FX_DWORD size, + int font_offset) { + CTTFontDesc* pFontDesc = new CTTFontDesc; + pFontDesc->m_Type = 2; + pFontDesc->m_pFontData = pData; + for (int i = 0; i < 16; i++) { + pFontDesc->m_TTCFace.m_pFaces[i] = NULL; + } + pFontDesc->m_RefCount++; + m_FaceMap[KeyNameFromSize(ttc_size, checksum)] = pFontDesc; + int face_index = GetTTCIndex(pFontDesc->m_pFontData, ttc_size, font_offset); + pFontDesc->m_TTCFace.m_pFaces[face_index] = + GetFixedFace(pFontDesc->m_pFontData, ttc_size, face_index); + return pFontDesc->m_TTCFace.m_pFaces[face_index]; +} + +FXFT_Face CFX_FontMgr::GetFixedFace(const uint8_t* pData, + FX_DWORD size, + int face_index) { + InitFTLibrary(); + FXFT_Library library = m_FTLibrary; + FXFT_Face face = nullptr; + if (FXFT_New_Memory_Face(library, pData, size, face_index, &face)) + return nullptr; + return FXFT_Set_Pixel_Sizes(face, 64, 64) ? nullptr : face; +} + +FXFT_Face CFX_FontMgr::GetFileFace(const FX_CHAR* filename, int face_index) { + InitFTLibrary(); + FXFT_Library library = m_FTLibrary; + FXFT_Face face = nullptr; + if (FXFT_New_Face(library, filename, face_index, &face)) + return nullptr; + return FXFT_Set_Pixel_Sizes(face, 64, 64) ? nullptr : face; +} + +void CFX_FontMgr::ReleaseFace(FXFT_Face face) { + if (!face) { + return; + } + FX_BOOL bNeedFaceDone = TRUE; + auto it = m_FaceMap.begin(); + while (it != m_FaceMap.end()) { + auto temp = it++; + int nRet = temp->second->ReleaseFace(face); + if (nRet == -1) + continue; + bNeedFaceDone = FALSE; + if (nRet == 0) + m_FaceMap.erase(temp); + break; + } + if (bNeedFaceDone && !m_pBuiltinMapper->IsBuiltinFace(face)) + FXFT_Done_Face(face); +} + +bool CFX_FontMgr::GetBuiltinFont(size_t index, + const uint8_t** pFontData, + FX_DWORD* size) { + if (index < FX_ArraySize(g_FoxitFonts)) { + *pFontData = g_FoxitFonts[index].m_pFontData; + *size = g_FoxitFonts[index].m_dwSize; + return true; + } + index -= FX_ArraySize(g_FoxitFonts); + if (index < FX_ArraySize(g_MMFonts)) { + *pFontData = g_MMFonts[index].m_pFontData; + *size = g_MMFonts[index].m_dwSize; + return true; + } + return false; +} + +CFX_FontMapper::CFX_FontMapper(CFX_FontMgr* mgr) + : m_bListLoaded(FALSE), + m_pFontInfo(nullptr), + m_pFontEnumerator(nullptr), + m_pFontMgr(mgr) { + m_MMFaces[0] = nullptr; + m_MMFaces[1] = nullptr; + FXSYS_memset(m_FoxitFaces, 0, sizeof(m_FoxitFaces)); +} +CFX_FontMapper::~CFX_FontMapper() { + for (size_t i = 0; i < FX_ArraySize(m_FoxitFaces); ++i) { + if (m_FoxitFaces[i]) + FXFT_Done_Face(m_FoxitFaces[i]); + } + if (m_MMFaces[0]) { + FXFT_Done_Face(m_MMFaces[0]); + } + if (m_MMFaces[1]) { + FXFT_Done_Face(m_MMFaces[1]); + } + if (m_pFontInfo) { + m_pFontInfo->Release(); + } +} +void CFX_FontMapper::SetSystemFontInfo(IFX_SystemFontInfo* pFontInfo) { + if (!pFontInfo) { + return; + } + if (m_pFontInfo) { + m_pFontInfo->Release(); + } + m_pFontInfo = pFontInfo; +} + +CFX_ByteString GetNameFromTT(const uint8_t* name_table, FX_DWORD name_id) { + const uint8_t* ptr = name_table + 2; + int name_count = GET_TT_SHORT(ptr); + int string_offset = GET_TT_SHORT(ptr + 2); + const uint8_t* string_ptr = name_table + string_offset; + ptr += 4; + for (int i = 0; i < name_count; i++) { + if (GET_TT_SHORT(ptr + 6) == name_id && GET_TT_SHORT(ptr) == 1 && + GET_TT_SHORT(ptr + 2) == 0) { + return CFX_ByteStringC(string_ptr + GET_TT_SHORT(ptr + 10), + GET_TT_SHORT(ptr + 8)); + } + ptr += 12; + } + return CFX_ByteString(); +} + +CFX_ByteString CFX_FontMapper::GetPSNameFromTT(void* hFont) { + if (!m_pFontInfo) + return CFX_ByteString(); + + FX_DWORD size = m_pFontInfo->GetFontData(hFont, kTableNAME, nullptr, 0); + if (!size) + return CFX_ByteString(); + + std::vector<uint8_t> buffer(size); + uint8_t* buffer_ptr = buffer.data(); + FX_DWORD bytes_read = + m_pFontInfo->GetFontData(hFont, kTableNAME, buffer_ptr, size); + return (bytes_read == size) ? GetNameFromTT(buffer_ptr, 6) : CFX_ByteString(); +} + +void CFX_FontMapper::AddInstalledFont(const CFX_ByteString& name, int charset) { + if (!m_pFontInfo) { + return; + } + if (m_CharsetArray.Find((FX_DWORD)charset) == -1) { + m_CharsetArray.Add((FX_DWORD)charset); + m_FaceArray.push_back(name); + } + if (name == m_LastFamily) { + return; + } + const uint8_t* ptr = name; + FX_BOOL bLocalized = FALSE; + for (int i = 0; i < name.GetLength(); i++) + if (ptr[i] > 0x80) { + bLocalized = TRUE; + break; + } + if (bLocalized) { + void* hFont = m_pFontInfo->GetFont(name); + if (!hFont) { + int iExact; + hFont = + m_pFontInfo->MapFont(0, 0, FXFONT_DEFAULT_CHARSET, 0, name, iExact); + if (!hFont) { + return; + } + } + CFX_ByteString new_name = GetPSNameFromTT(hFont); + if (!new_name.IsEmpty()) { + new_name.Insert(0, ' '); + m_InstalledTTFonts.push_back(new_name); + } + m_pFontInfo->DeleteFont(hFont); + } + m_InstalledTTFonts.push_back(name); + m_LastFamily = name; +} +void CFX_FontMapper::LoadInstalledFonts() { + if (!m_pFontInfo) { + return; + } + if (m_bListLoaded) { + return; + } + if (m_bListLoaded) { + return; + } + m_pFontInfo->EnumFontList(this); + m_bListLoaded = TRUE; +} +CFX_ByteString CFX_FontMapper::MatchInstalledFonts( + const CFX_ByteString& norm_name) { + LoadInstalledFonts(); + int i; + for (i = pdfium::CollectionSize<int>(m_InstalledTTFonts) - 1; i >= 0; i--) { + CFX_ByteString norm1 = TT_NormalizeName(m_InstalledTTFonts[i]); + if (norm1 == norm_name) { + break; + } + } + if (i < 0) { + return CFX_ByteString(); + } + CFX_ByteString match = m_InstalledTTFonts[i]; + if (match[0] == ' ') { + match = m_InstalledTTFonts[i + 1]; + } + return match; +} + +FXFT_Face CFX_FontMapper::UseInternalSubst(CFX_SubstFont* pSubstFont, + int iBaseFont, + int italic_angle, + int weight, + int picthfamily) { + if (iBaseFont < 12) { + if (m_FoxitFaces[iBaseFont]) { + return m_FoxitFaces[iBaseFont]; + } + const uint8_t* pFontData = NULL; + FX_DWORD size = 0; + if (m_pFontMgr->GetBuiltinFont(iBaseFont, &pFontData, &size)) { + m_FoxitFaces[iBaseFont] = m_pFontMgr->GetFixedFace(pFontData, size, 0); + return m_FoxitFaces[iBaseFont]; + } + } + pSubstFont->m_SubstFlags |= FXFONT_SUBST_MM; + pSubstFont->m_ItalicAngle = italic_angle; + if (weight) { + pSubstFont->m_Weight = weight; + } + if (picthfamily & FXFONT_FF_ROMAN) { + pSubstFont->m_Weight = pSubstFont->m_Weight * 4 / 5; + pSubstFont->m_Family = "Chrome Serif"; + if (m_MMFaces[1]) { + return m_MMFaces[1]; + } + const uint8_t* pFontData = NULL; + FX_DWORD size = 0; + m_pFontMgr->GetBuiltinFont(14, &pFontData, &size); + m_MMFaces[1] = m_pFontMgr->GetFixedFace(pFontData, size, 0); + return m_MMFaces[1]; + } + pSubstFont->m_Family = "Chrome Sans"; + if (m_MMFaces[0]) { + return m_MMFaces[0]; + } + const uint8_t* pFontData = NULL; + FX_DWORD size = 0; + m_pFontMgr->GetBuiltinFont(15, &pFontData, &size); + m_MMFaces[0] = m_pFontMgr->GetFixedFace(pFontData, size, 0); + return m_MMFaces[0]; +} + +FXFT_Face CFX_FontMapper::FindSubstFont(const CFX_ByteString& name, + FX_BOOL bTrueType, + FX_DWORD flags, + int weight, + int italic_angle, + int WindowCP, + CFX_SubstFont* pSubstFont) { + if (!(flags & FXFONT_USEEXTERNATTR)) { + weight = FXFONT_FW_NORMAL; + italic_angle = 0; + } + CFX_ByteString SubstName = name; + SubstName.Remove(0x20); + if (bTrueType) { + if (name[0] == '@') { + SubstName = name.Mid(1); + } + } + PDF_GetStandardFontName(&SubstName); + if (SubstName == "Symbol" && !bTrueType) { + pSubstFont->m_Family = "Chrome Symbol"; + pSubstFont->m_Charset = FXFONT_SYMBOL_CHARSET; + pSubstFont->m_SubstFlags |= FXFONT_SUBST_STANDARD; + if (m_FoxitFaces[12]) { + return m_FoxitFaces[12]; + } + const uint8_t* pFontData = NULL; + FX_DWORD size = 0; + m_pFontMgr->GetBuiltinFont(12, &pFontData, &size); + m_FoxitFaces[12] = m_pFontMgr->GetFixedFace(pFontData, size, 0); + return m_FoxitFaces[12]; + } + if (SubstName == "ZapfDingbats") { + pSubstFont->m_Family = "Chrome Dingbats"; + pSubstFont->m_Charset = FXFONT_SYMBOL_CHARSET; + pSubstFont->m_SubstFlags |= FXFONT_SUBST_STANDARD; + if (m_FoxitFaces[13]) { + return m_FoxitFaces[13]; + } + const uint8_t* pFontData = NULL; + FX_DWORD size = 0; + m_pFontMgr->GetBuiltinFont(13, &pFontData, &size); + m_FoxitFaces[13] = m_pFontMgr->GetFixedFace(pFontData, size, 0); + return m_FoxitFaces[13]; + } + int iBaseFont = 0; + CFX_ByteString family, style; + FX_BOOL bHasComma = FALSE; + FX_BOOL bHasHypen = FALSE; + int find = SubstName.Find(",", 0); + if (find >= 0) { + family = SubstName.Left(find); + PDF_GetStandardFontName(&family); + style = SubstName.Mid(find + 1); + bHasComma = TRUE; + } else { + family = SubstName; + } + for (; iBaseFont < 12; iBaseFont++) + if (family == CFX_ByteStringC(g_Base14FontNames[iBaseFont])) { + break; + } + int PitchFamily = 0; + FX_BOOL bItalic = FALSE; + FX_DWORD nStyle = 0; + FX_BOOL bStyleAvail = FALSE; + if (iBaseFont < 12) { + family = g_Base14FontNames[iBaseFont]; + if ((iBaseFont % 4) == 1 || (iBaseFont % 4) == 2) { + nStyle |= FX_FONT_STYLE_Bold; + } + if ((iBaseFont % 4) / 2) { + nStyle |= FX_FONT_STYLE_Italic; + } + if (iBaseFont < 4) { + PitchFamily |= FXFONT_FF_FIXEDPITCH; + } + if (iBaseFont >= 8) { + PitchFamily |= FXFONT_FF_ROMAN; + } + } else { + if (!bHasComma) { + find = family.ReverseFind('-'); + if (find >= 0) { + style = family.Mid(find + 1); + family = family.Left(find); + bHasHypen = TRUE; + } + } + if (!bHasHypen) { + int nLen = family.GetLength(); + int32_t nRet = GetStyleType(family, TRUE); + if (nRet > -1) { + family = family.Left(nLen - g_FontStyles[nRet].len); + if (nRet == 0) { + nStyle |= FX_FONT_STYLE_Bold; + } + if (nRet == 1) { + nStyle |= FX_FONT_STYLE_Italic; + } + if (nRet == 2) { + nStyle |= (FX_FONT_STYLE_Bold | FX_FONT_STYLE_Italic); + } + } + } + if (flags & FXFONT_SERIF) { + PitchFamily |= FXFONT_FF_ROMAN; + } + if (flags & FXFONT_SCRIPT) { + PitchFamily |= FXFONT_FF_SCRIPT; + } + if (flags & FXFONT_FIXED_PITCH) { + PitchFamily |= FXFONT_FF_FIXEDPITCH; + } + } + if (!style.IsEmpty()) { + int nLen = style.GetLength(); + const FX_CHAR* pStyle = style; + int i = 0; + FX_BOOL bFirstItem = TRUE; + CFX_ByteString buf; + while (i < nLen) { + buf = ParseStyle(pStyle, nLen, i); + int32_t nRet = GetStyleType(buf, FALSE); + if ((i && !bStyleAvail) || (!i && nRet < 0)) { + family = SubstName; + iBaseFont = 12; + break; + } else if (nRet >= 0) { + bStyleAvail = TRUE; + } + if (nRet == 0) { + if (nStyle & FX_FONT_STYLE_Bold) { + nStyle |= FX_FONT_STYLE_BoldBold; + } else { + nStyle |= FX_FONT_STYLE_Bold; + } + bFirstItem = FALSE; + } + if (nRet == 1) { + if (bFirstItem) { + nStyle |= FX_FONT_STYLE_Italic; + } else { + family = SubstName; + iBaseFont = 12; + } + break; + } + if (nRet == 2) { + nStyle |= FX_FONT_STYLE_Italic; + if (nStyle & FX_FONT_STYLE_Bold) { + nStyle |= FX_FONT_STYLE_BoldBold; + } else { + nStyle |= FX_FONT_STYLE_Bold; + } + bFirstItem = FALSE; + } + i += buf.GetLength() + 1; + } + } + weight = weight ? weight : FXFONT_FW_NORMAL; + int old_weight = weight; + if (nStyle) { + weight = + nStyle & FX_FONT_STYLE_BoldBold + ? 900 + : (nStyle & FX_FONT_STYLE_Bold ? FXFONT_FW_BOLD : FXFONT_FW_NORMAL); + } + if (nStyle & FX_FONT_STYLE_Italic) { + bItalic = TRUE; + } + FX_BOOL bCJK = FALSE; + int iExact = 0; + int Charset = FXFONT_ANSI_CHARSET; + if (WindowCP) { + Charset = GetCharsetFromCodePage(WindowCP); + } else if (iBaseFont == 12 && (flags & FXFONT_SYMBOLIC)) { + Charset = FXFONT_SYMBOL_CHARSET; + } + if (Charset == FXFONT_SHIFTJIS_CHARSET || Charset == FXFONT_GB2312_CHARSET || + Charset == FXFONT_HANGEUL_CHARSET || + Charset == FXFONT_CHINESEBIG5_CHARSET) { + bCJK = TRUE; + } + if (!m_pFontInfo) { + pSubstFont->m_SubstFlags |= FXFONT_SUBST_STANDARD; + return UseInternalSubst(pSubstFont, iBaseFont, italic_angle, old_weight, + PitchFamily); + } + family = GetFontFamily(family, nStyle); + CFX_ByteString match = MatchInstalledFonts(TT_NormalizeName(family)); + if (match.IsEmpty() && family != SubstName && + (!bHasComma && (!bHasHypen || (bHasHypen && !bStyleAvail)))) { + match = MatchInstalledFonts(TT_NormalizeName(SubstName)); + } + if (match.IsEmpty() && iBaseFont >= 12) { + if (!bCJK) { + if (!CheckSupportThirdPartFont(family, PitchFamily)) { + if (italic_angle != 0) { + bItalic = TRUE; + } else { + bItalic = FALSE; + } + weight = old_weight; + } + } else { + pSubstFont->m_bSubstOfCJK = TRUE; + if (nStyle) { + pSubstFont->m_WeightCJK = weight; + } else { + pSubstFont->m_WeightCJK = FXFONT_FW_NORMAL; + } + if (nStyle & FX_FONT_STYLE_Italic) { + pSubstFont->m_bItlicCJK = TRUE; + } + } + } else { + italic_angle = 0; + weight = + nStyle & FX_FONT_STYLE_BoldBold + ? 900 + : (nStyle & FX_FONT_STYLE_Bold ? FXFONT_FW_BOLD : FXFONT_FW_NORMAL); + } + if (!match.IsEmpty() || iBaseFont < 12) { + if (!match.IsEmpty()) { + family = match; + } + if (iBaseFont < 12) { + if (nStyle && !(iBaseFont % 4)) { + if ((nStyle & 0x3) == 1) { + iBaseFont += 1; + } + if ((nStyle & 0x3) == 2) { + iBaseFont += 3; + } + if ((nStyle & 0x3) == 3) { + iBaseFont += 2; + } + } + family = g_Base14FontNames[iBaseFont]; + pSubstFont->m_SubstFlags |= FXFONT_SUBST_STANDARD; + } + } else { + if (flags & FXFONT_ITALIC) { + bItalic = TRUE; + } + } + iExact = !match.IsEmpty(); + void* hFont = m_pFontInfo->MapFont(weight, bItalic, Charset, PitchFamily, + family, iExact); + if (iExact) { + pSubstFont->m_SubstFlags |= FXFONT_SUBST_EXACT; + } + if (!hFont) { +#ifdef PDF_ENABLE_XFA + if (flags & FXFONT_EXACTMATCH) { + return NULL; + } +#endif // PDF_ENABLE_XFA + if (bCJK) { + if (italic_angle != 0) { + bItalic = TRUE; + } else { + bItalic = FALSE; + } + weight = old_weight; + } + if (!match.IsEmpty()) { + hFont = m_pFontInfo->GetFont(match); + if (!hFont) { + return UseInternalSubst(pSubstFont, iBaseFont, italic_angle, old_weight, + PitchFamily); + } + } else { + if (Charset == FXFONT_SYMBOL_CHARSET) { +#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ || \ + _FXM_PLATFORM_ == _FXM_PLATFORM_ANDROID_ + if (SubstName == "Symbol") { + pSubstFont->m_Family = "Chrome Symbol"; + pSubstFont->m_SubstFlags |= FXFONT_SUBST_STANDARD; + pSubstFont->m_Charset = FXFONT_SYMBOL_CHARSET; + if (m_FoxitFaces[12]) { + return m_FoxitFaces[12]; + } + const uint8_t* pFontData = NULL; + FX_DWORD size = 0; + m_pFontMgr->GetBuiltinFont(12, &pFontData, &size); + m_FoxitFaces[12] = m_pFontMgr->GetFixedFace(pFontData, size, 0); + return m_FoxitFaces[12]; + } +#endif + pSubstFont->m_SubstFlags |= FXFONT_SUBST_NONSYMBOL; + return FindSubstFont(family, bTrueType, flags & ~FXFONT_SYMBOLIC, + weight, italic_angle, 0, pSubstFont); + } + if (Charset == FXFONT_ANSI_CHARSET) { + pSubstFont->m_SubstFlags |= FXFONT_SUBST_STANDARD; + return UseInternalSubst(pSubstFont, iBaseFont, italic_angle, old_weight, + PitchFamily); + } + int index = m_CharsetArray.Find(Charset); + if (index < 0) { + return UseInternalSubst(pSubstFont, iBaseFont, italic_angle, old_weight, + PitchFamily); + } + hFont = m_pFontInfo->GetFont(m_FaceArray[index]); + } + } + pSubstFont->m_ExtHandle = m_pFontInfo->RetainFont(hFont); + if (!hFont) + return nullptr; + + m_pFontInfo->GetFaceName(hFont, SubstName); + if (Charset == FXFONT_DEFAULT_CHARSET) { + m_pFontInfo->GetFontCharset(hFont, Charset); + } + FX_DWORD ttc_size = m_pFontInfo->GetFontData(hFont, kTableTTCF, nullptr, 0); + FX_DWORD font_size = m_pFontInfo->GetFontData(hFont, 0, nullptr, 0); + if (font_size == 0 && ttc_size == 0) { + m_pFontInfo->DeleteFont(hFont); + return nullptr; + } + FXFT_Face face = nullptr; + if (ttc_size) { + uint8_t temp[1024]; + m_pFontInfo->GetFontData(hFont, kTableTTCF, temp, 1024); + FX_DWORD checksum = 0; + for (int i = 0; i < 256; i++) { + checksum += ((FX_DWORD*)temp)[i]; + } + uint8_t* pFontData; + face = m_pFontMgr->GetCachedTTCFace(ttc_size, checksum, + ttc_size - font_size, pFontData); + if (!face) { + pFontData = FX_Alloc(uint8_t, ttc_size); + m_pFontInfo->GetFontData(hFont, kTableTTCF, pFontData, ttc_size); + face = m_pFontMgr->AddCachedTTCFace(ttc_size, checksum, pFontData, + ttc_size, ttc_size - font_size); + } + } else { + uint8_t* pFontData; + face = m_pFontMgr->GetCachedFace(SubstName, weight, bItalic, pFontData); + if (!face) { + pFontData = FX_Alloc(uint8_t, font_size); + m_pFontInfo->GetFontData(hFont, 0, pFontData, font_size); + face = m_pFontMgr->AddCachedFace(SubstName, weight, bItalic, pFontData, + font_size, + m_pFontInfo->GetFaceIndex(hFont)); + } + } + if (!face) { + m_pFontInfo->DeleteFont(hFont); + return NULL; + } + pSubstFont->m_Family = SubstName; + pSubstFont->m_Charset = Charset; + FX_BOOL bNeedUpdateWeight = FALSE; + if (FXFT_Is_Face_Bold(face)) { + if (weight == FXFONT_FW_BOLD) { + bNeedUpdateWeight = FALSE; + } else { + bNeedUpdateWeight = TRUE; + } + } else { + if (weight == FXFONT_FW_NORMAL) { + bNeedUpdateWeight = FALSE; + } else { + bNeedUpdateWeight = TRUE; + } + } + if (bNeedUpdateWeight) { + pSubstFont->m_Weight = weight; + } + if (bItalic && !FXFT_Is_Face_Italic(face)) { + if (italic_angle == 0) { + italic_angle = -12; + } else if (FXSYS_abs(italic_angle) < 5) { + italic_angle = 0; + } + pSubstFont->m_ItalicAngle = italic_angle; + } + m_pFontInfo->DeleteFont(hFont); + return face; +} +#ifdef PDF_ENABLE_XFA +FXFT_Face CFX_FontMapper::FindSubstFontByUnicode(FX_DWORD dwUnicode, + FX_DWORD flags, + int weight, + int italic_angle) { + if (m_pFontInfo == NULL) { + return NULL; + } + FX_BOOL bItalic = (flags & FXFONT_ITALIC) != 0; + int PitchFamily = 0; + if (flags & FXFONT_SERIF) { + PitchFamily |= FXFONT_FF_ROMAN; + } + if (flags & FXFONT_SCRIPT) { + PitchFamily |= FXFONT_FF_SCRIPT; + } + if (flags & FXFONT_FIXED_PITCH) { + PitchFamily |= FXFONT_FF_FIXEDPITCH; + } + void* hFont = + m_pFontInfo->MapFontByUnicode(dwUnicode, weight, bItalic, PitchFamily); + if (hFont == NULL) { + return NULL; + } + FX_DWORD ttc_size = m_pFontInfo->GetFontData(hFont, 0x74746366, NULL, 0); + FX_DWORD font_size = m_pFontInfo->GetFontData(hFont, 0, NULL, 0); + if (font_size == 0 && ttc_size == 0) { + m_pFontInfo->DeleteFont(hFont); + return NULL; + } + FXFT_Face face = NULL; + if (ttc_size) { + uint8_t temp[1024]; + m_pFontInfo->GetFontData(hFont, 0x74746366, temp, 1024); + FX_DWORD checksum = 0; + for (int i = 0; i < 256; i++) { + checksum += ((FX_DWORD*)temp)[i]; + } + uint8_t* pFontData; + face = m_pFontMgr->GetCachedTTCFace(ttc_size, checksum, + ttc_size - font_size, pFontData); + if (face == NULL) { + pFontData = FX_Alloc(uint8_t, ttc_size); + if (pFontData) { + m_pFontInfo->GetFontData(hFont, 0x74746366, pFontData, ttc_size); + face = m_pFontMgr->AddCachedTTCFace(ttc_size, checksum, pFontData, + ttc_size, ttc_size - font_size); + } + } + } else { + CFX_ByteString SubstName; + m_pFontInfo->GetFaceName(hFont, SubstName); + uint8_t* pFontData; + face = m_pFontMgr->GetCachedFace(SubstName, weight, bItalic, pFontData); + if (face == NULL) { + pFontData = FX_Alloc(uint8_t, font_size); + if (!pFontData) { + m_pFontInfo->DeleteFont(hFont); + return NULL; + } + m_pFontInfo->GetFontData(hFont, 0, pFontData, font_size); + face = m_pFontMgr->AddCachedFace(SubstName, weight, bItalic, pFontData, + font_size, + m_pFontInfo->GetFaceIndex(hFont)); + } + } + m_pFontInfo->DeleteFont(hFont); + return face; +} + +void* IFX_SystemFontInfo::MapFontByUnicode(FX_DWORD dwUnicode, + int weight, + FX_BOOL bItalic, + int pitch_family) { + return nullptr; +} +#endif // PDF_ENABLE_XFA + +int IFX_SystemFontInfo::GetFaceIndex(void* hFont) { + return 0; +} + +void* IFX_SystemFontInfo::RetainFont(void* hFont) { + return NULL; +} + +int CFX_FontMapper::GetFaceSize() const { + return pdfium::CollectionSize<int>(m_FaceArray); +} + +FX_BOOL CFX_FontMapper::IsBuiltinFace(const FXFT_Face face) const { + for (int i = 0; i < MM_FACE_COUNT; ++i) { + if (m_MMFaces[i] == face) { + return TRUE; + } + } + for (int i = 0; i < FOXIT_FACE_COUNT; ++i) { + if (m_FoxitFaces[i] == face) { + return TRUE; + } + } + return FALSE; +} + +extern "C" { +unsigned long _FTStreamRead(FXFT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count); +void _FTStreamClose(FXFT_Stream stream); +}; + +#if _FX_OS_ == _FX_ANDROID_ +IFX_SystemFontInfo* IFX_SystemFontInfo::CreateDefault(const char** pUnused) { + return NULL; +} +#endif + +CFX_FolderFontInfo::CFX_FolderFontInfo() {} +CFX_FolderFontInfo::~CFX_FolderFontInfo() { + for (const auto& pair : m_FontList) { + delete pair.second; + } +} +void CFX_FolderFontInfo::AddPath(const CFX_ByteStringC& path) { + m_PathList.push_back(path); +} +void CFX_FolderFontInfo::Release() { + delete this; +} +FX_BOOL CFX_FolderFontInfo::EnumFontList(CFX_FontMapper* pMapper) { + m_pMapper = pMapper; + for (const auto& path : m_PathList) { + ScanPath(path); + } + return TRUE; +} +void CFX_FolderFontInfo::ScanPath(const CFX_ByteString& path) { + void* handle = FX_OpenFolder(path); + if (!handle) { + return; + } + CFX_ByteString filename; + FX_BOOL bFolder; + while (FX_GetNextFile(handle, filename, bFolder)) { + if (bFolder) { + if (filename == "." || filename == "..") { + continue; + } + } else { + CFX_ByteString ext = filename.Right(4); + ext.MakeUpper(); + if (ext != ".TTF" && ext != ".OTF" && ext != ".TTC") { + continue; + } + } + CFX_ByteString fullpath = path; +#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ + fullpath += "\\"; +#else + fullpath += "/"; +#endif + fullpath += filename; + if (bFolder) { + ScanPath(fullpath); + } else { + ScanFile(fullpath); + } + } + FX_CloseFolder(handle); +} +void CFX_FolderFontInfo::ScanFile(const CFX_ByteString& path) { + FXSYS_FILE* pFile = FXSYS_fopen(path, "rb"); + if (!pFile) { + return; + } + FXSYS_fseek(pFile, 0, FXSYS_SEEK_END); + FX_DWORD filesize = FXSYS_ftell(pFile); + uint8_t buffer[16]; + FXSYS_fseek(pFile, 0, FXSYS_SEEK_SET); + size_t readCnt = FXSYS_fread(buffer, 12, 1, pFile); + if (readCnt != 1) { + FXSYS_fclose(pFile); + return; + } + + if (GET_TT_LONG(buffer) == kTableTTCF) { + FX_DWORD nFaces = GET_TT_LONG(buffer + 8); + if (nFaces > std::numeric_limits<FX_DWORD>::max() / 4) { + FXSYS_fclose(pFile); + return; + } + FX_DWORD face_bytes = nFaces * 4; + uint8_t* offsets = FX_Alloc(uint8_t, face_bytes); + readCnt = FXSYS_fread(offsets, 1, face_bytes, pFile); + if (readCnt != face_bytes) { + FX_Free(offsets); + FXSYS_fclose(pFile); + return; + } + for (FX_DWORD i = 0; i < nFaces; i++) { + uint8_t* p = offsets + i * 4; + ReportFace(path, pFile, filesize, GET_TT_LONG(p)); + } + FX_Free(offsets); + } else { + ReportFace(path, pFile, filesize, 0); + } + FXSYS_fclose(pFile); +} +void CFX_FolderFontInfo::ReportFace(const CFX_ByteString& path, + FXSYS_FILE* pFile, + FX_DWORD filesize, + FX_DWORD offset) { + FXSYS_fseek(pFile, offset, FXSYS_SEEK_SET); + char buffer[16]; + if (!FXSYS_fread(buffer, 12, 1, pFile)) { + return; + } + FX_DWORD nTables = GET_TT_SHORT(buffer + 4); + CFX_ByteString tables = FPDF_ReadStringFromFile(pFile, nTables * 16); + if (tables.IsEmpty()) { + return; + } + CFX_ByteString names = + FPDF_LoadTableFromTT(pFile, tables, nTables, 0x6e616d65); + if (names.IsEmpty()) { + return; + } + CFX_ByteString facename = GetNameFromTT(names, 1); + CFX_ByteString style = GetNameFromTT(names, 2); + if (style != "Regular") { + facename += " " + style; + } + if (pdfium::ContainsKey(m_FontList, facename)) + return; + + CFX_FontFaceInfo* pInfo = + new CFX_FontFaceInfo(path, facename, tables, offset, filesize); + CFX_ByteString os2 = FPDF_LoadTableFromTT(pFile, tables, nTables, 0x4f532f32); + if (os2.GetLength() >= 86) { + const uint8_t* p = (const uint8_t*)os2 + 78; + FX_DWORD codepages = GET_TT_LONG(p); + if (codepages & (1 << 17)) { + m_pMapper->AddInstalledFont(facename, FXFONT_SHIFTJIS_CHARSET); + pInfo->m_Charsets |= CHARSET_FLAG_SHIFTJIS; + } + if (codepages & (1 << 18)) { + m_pMapper->AddInstalledFont(facename, FXFONT_GB2312_CHARSET); + pInfo->m_Charsets |= CHARSET_FLAG_GB; + } + if (codepages & (1 << 20)) { + m_pMapper->AddInstalledFont(facename, FXFONT_CHINESEBIG5_CHARSET); + pInfo->m_Charsets |= CHARSET_FLAG_BIG5; + } + if ((codepages & (1 << 19)) || (codepages & (1 << 21))) { + m_pMapper->AddInstalledFont(facename, FXFONT_HANGEUL_CHARSET); + pInfo->m_Charsets |= CHARSET_FLAG_KOREAN; + } + if (codepages & (1 << 31)) { + m_pMapper->AddInstalledFont(facename, FXFONT_SYMBOL_CHARSET); + pInfo->m_Charsets |= CHARSET_FLAG_SYMBOL; + } + } + m_pMapper->AddInstalledFont(facename, FXFONT_ANSI_CHARSET); + pInfo->m_Charsets |= CHARSET_FLAG_ANSI; + pInfo->m_Styles = 0; + if (style.Find("Bold") > -1) { + pInfo->m_Styles |= FXFONT_BOLD; + } + if (style.Find("Italic") > -1 || style.Find("Oblique") > -1) { + pInfo->m_Styles |= FXFONT_ITALIC; + } + if (facename.Find("Serif") > -1) { + pInfo->m_Styles |= FXFONT_SERIF; + } + m_FontList[facename] = pInfo; +} + +void* CFX_FolderFontInfo::GetSubstFont(const CFX_ByteString& face) { + for (size_t iBaseFont = 0; iBaseFont < FX_ArraySize(Base14Substs); + iBaseFont++) { + if (face == Base14Substs[iBaseFont].m_pName) { + return GetFont(Base14Substs[iBaseFont].m_pSubstName); + } + } + return nullptr; +} + +void* CFX_FolderFontInfo::FindFont(int weight, + FX_BOOL bItalic, + int charset, + int pitch_family, + const FX_CHAR* family, + FX_BOOL bMatchName) { + CFX_FontFaceInfo* pFind = nullptr; + if (charset == FXFONT_ANSI_CHARSET && (pitch_family & FXFONT_FF_FIXEDPITCH)) { + return GetFont("Courier New"); + } + FX_DWORD charset_flag = GetCharset(charset); + int32_t iBestSimilar = 0; + for (const auto& it : m_FontList) { + const CFX_ByteString& bsName = it.first; + CFX_FontFaceInfo* pFont = it.second; + if (!(pFont->m_Charsets & charset_flag) && + charset != FXFONT_DEFAULT_CHARSET) { + continue; + } + int32_t index = bsName.Find(family); + if (bMatchName && index < 0) { + continue; + } + int32_t iSimilarValue = + GetSimilarValue(weight, bItalic, pitch_family, pFont->m_Styles); + if (iSimilarValue > iBestSimilar) { + iBestSimilar = iSimilarValue; + pFind = pFont; + } + } + return pFind; +} +void* CFX_FolderFontInfo::MapFont(int weight, + FX_BOOL bItalic, + int charset, + int pitch_family, + const FX_CHAR* family, + int& iExact) { + return NULL; +} + +#ifdef PDF_ENABLE_XFA +void* CFX_FolderFontInfo::MapFontByUnicode(FX_DWORD dwUnicode, + int weight, + FX_BOOL bItalic, + int pitch_family) { + return NULL; +} +#endif // PDF_ENABLE_XFA + +void* CFX_FolderFontInfo::GetFont(const FX_CHAR* face) { + auto it = m_FontList.find(face); + return it != m_FontList.end() ? it->second : nullptr; +} + +FX_DWORD CFX_FolderFontInfo::GetFontData(void* hFont, + FX_DWORD table, + uint8_t* buffer, + FX_DWORD size) { + if (!hFont) + return 0; + + const CFX_FontFaceInfo* pFont = static_cast<CFX_FontFaceInfo*>(hFont); + FX_DWORD datasize = 0; + FX_DWORD offset = 0; + if (table == 0) { + datasize = pFont->m_FontOffset ? 0 : pFont->m_FileSize; + } else if (table == kTableTTCF) { + datasize = pFont->m_FontOffset ? pFont->m_FileSize : 0; + } else { + FX_DWORD nTables = pFont->m_FontTables.GetLength() / 16; + for (FX_DWORD i = 0; i < nTables; i++) { + const uint8_t* p = + static_cast<const uint8_t*>(pFont->m_FontTables) + i * 16; + if (GET_TT_LONG(p) == table) { + offset = GET_TT_LONG(p + 8); + datasize = GET_TT_LONG(p + 12); + } + } + } + + if (!datasize || size < datasize) + return datasize; + + FXSYS_FILE* pFile = FXSYS_fopen(pFont->m_FilePath, "rb"); + if (!pFile) + return 0; + + if (FXSYS_fseek(pFile, offset, FXSYS_SEEK_SET) < 0 || + FXSYS_fread(buffer, datasize, 1, pFile) != 1) { + datasize = 0; + } + FXSYS_fclose(pFile); + return datasize; +} + +void CFX_FolderFontInfo::DeleteFont(void* hFont) {} +FX_BOOL CFX_FolderFontInfo::GetFaceName(void* hFont, CFX_ByteString& name) { + if (!hFont) { + return FALSE; + } + CFX_FontFaceInfo* pFont = (CFX_FontFaceInfo*)hFont; + name = pFont->m_FaceName; + return TRUE; +} +FX_BOOL CFX_FolderFontInfo::GetFontCharset(void* hFont, int& charset) { + return FALSE; +} + +int PDF_GetStandardFontName(CFX_ByteString* name) { + AltFontName* found = static_cast<AltFontName*>( + FXSYS_bsearch(name->c_str(), g_AltFontNames, FX_ArraySize(g_AltFontNames), + sizeof(AltFontName), CompareString)); + if (!found) + return -1; + + *name = g_Base14FontNames[found->m_Index]; + return found->m_Index; +} diff --git a/core/fxge/ge/fx_ge_linux.cpp b/core/fxge/ge/fx_ge_linux.cpp new file mode 100644 index 0000000000..af731f78da --- /dev/null +++ b/core/fxge/ge/fx_ge_linux.cpp @@ -0,0 +1,147 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxge/agg/fx_agg_driver.h" +#include "core/fxge/ge/fx_text_int.h" +#include "core/include/fxge/fx_ge.h" + +#if _FXM_PLATFORM_ == _FXM_PLATFORM_LINUX_ +class CFX_LinuxFontInfo : public CFX_FolderFontInfo { + public: + void* MapFont(int weight, + FX_BOOL bItalic, + int charset, + int pitch_family, + const FX_CHAR* family, + int& iExact) override; + FX_BOOL ParseFontCfg(const char** pUserPaths); +}; +#define LINUX_GPNAMESIZE 6 +static const struct { + const FX_CHAR* NameArr[LINUX_GPNAMESIZE]; +} LinuxGpFontList[] = { + {{"TakaoPGothic", "VL PGothic", "IPAPGothic", "VL Gothic", "Kochi Gothic", + "VL Gothic regular"}}, + {{"TakaoGothic", "VL Gothic", "IPAGothic", "Kochi Gothic", NULL, + "VL Gothic regular"}}, + {{"TakaoPMincho", "IPAPMincho", "VL Gothic", "Kochi Mincho", NULL, + "VL Gothic regular"}}, + {{"TakaoMincho", "IPAMincho", "VL Gothic", "Kochi Mincho", NULL, + "VL Gothic regular"}}, +}; +static const FX_CHAR* const g_LinuxGbFontList[] = { + "AR PL UMing CN Light", "WenQuanYi Micro Hei", "AR PL UKai CN", +}; +static const FX_CHAR* const g_LinuxB5FontList[] = { + "AR PL UMing TW Light", "WenQuanYi Micro Hei", "AR PL UKai TW", +}; +static const FX_CHAR* const g_LinuxHGFontList[] = { + "UnDotum", +}; +static int32_t GetJapanesePreference(const FX_CHAR* facearr, + int weight, + int picth_family) { + CFX_ByteString face = facearr; + if (face.Find("Gothic") >= 0 || + face.Find("\x83\x53\x83\x56\x83\x62\x83\x4e") >= 0) { + if (face.Find("PGothic") >= 0 || + face.Find("\x82\x6f\x83\x53\x83\x56\x83\x62\x83\x4e") >= 0) { + return 0; + } + return 1; + } + if (face.Find("Mincho") >= 0 || face.Find("\x96\xbe\x92\xa9") >= 0) { + if (face.Find("PMincho") >= 0 || + face.Find("\x82\x6f\x96\xbe\x92\xa9") >= 0) { + return 2; + } + return 3; + } + if (!(picth_family & FXFONT_FF_ROMAN) && weight > 400) { + return 0; + } + return 2; +} +void* CFX_LinuxFontInfo::MapFont(int weight, + FX_BOOL bItalic, + int charset, + int pitch_family, + const FX_CHAR* cstr_face, + int& iExact) { + void* font = GetSubstFont(cstr_face); + if (font) { + iExact = 1; + return font; + } + FX_BOOL bCJK = TRUE; + switch (charset) { + case FXFONT_SHIFTJIS_CHARSET: { + int32_t index = GetJapanesePreference(cstr_face, weight, pitch_family); + if (index < 0) { + break; + } + for (int32_t i = 0; i < LINUX_GPNAMESIZE; i++) { + auto it = m_FontList.find(LinuxGpFontList[index].NameArr[i]); + if (it != m_FontList.end()) { + return it->second; + } + } + } break; + case FXFONT_GB2312_CHARSET: { + for (size_t i = 0; i < FX_ArraySize(g_LinuxGbFontList); ++i) { + auto it = m_FontList.find(g_LinuxGbFontList[i]); + if (it != m_FontList.end()) { + return it->second; + } + } + } break; + case FXFONT_CHINESEBIG5_CHARSET: { + for (size_t i = 0; i < FX_ArraySize(g_LinuxB5FontList); ++i) { + auto it = m_FontList.find(g_LinuxB5FontList[i]); + if (it != m_FontList.end()) { + return it->second; + } + } + } break; + case FXFONT_HANGEUL_CHARSET: { + for (size_t i = 0; i < FX_ArraySize(g_LinuxHGFontList); ++i) { + auto it = m_FontList.find(g_LinuxHGFontList[i]); + if (it != m_FontList.end()) { + return it->second; + } + } + } break; + default: + bCJK = FALSE; + break; + } + return FindFont(weight, bItalic, charset, pitch_family, cstr_face, !bCJK); +} +IFX_SystemFontInfo* IFX_SystemFontInfo::CreateDefault(const char** pUserPaths) { + CFX_LinuxFontInfo* pInfo = new CFX_LinuxFontInfo; + if (!pInfo->ParseFontCfg(pUserPaths)) { + pInfo->AddPath("/usr/share/fonts"); + pInfo->AddPath("/usr/share/X11/fonts/Type1"); + pInfo->AddPath("/usr/share/X11/fonts/TTF"); + pInfo->AddPath("/usr/local/share/fonts"); + } + return pInfo; +} +FX_BOOL CFX_LinuxFontInfo::ParseFontCfg(const char** pUserPaths) { + if (!pUserPaths) { + return FALSE; + } + for (const char** pPath = pUserPaths; *pPath; ++pPath) { + AddPath(*pPath); + } + return TRUE; +} +void CFX_GEModule::InitPlatform() { + m_pFontMgr->SetSystemFontInfo( + IFX_SystemFontInfo::CreateDefault(m_pUserFontPaths)); +} +void CFX_GEModule::DestroyPlatform() {} +#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_LINUX_ diff --git a/core/fxge/ge/fx_ge_path.cpp b/core/fxge/ge/fx_ge_path.cpp new file mode 100644 index 0000000000..0b52cdf9e4 --- /dev/null +++ b/core/fxge/ge/fx_ge_path.cpp @@ -0,0 +1,656 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/include/fxcrt/fx_system.h" +#include "core/include/fxge/fx_ge.h" +#include "third_party/base/numerics/safe_math.h" + +CFX_ClipRgn::CFX_ClipRgn(int width, int height) { + m_Type = RectI; + m_Box.left = m_Box.top = 0; + m_Box.right = width; + m_Box.bottom = height; +} +CFX_ClipRgn::CFX_ClipRgn(const FX_RECT& rect) { + m_Type = RectI; + m_Box = rect; +} +CFX_ClipRgn::CFX_ClipRgn(const CFX_ClipRgn& src) { + m_Type = src.m_Type; + m_Box = src.m_Box; + m_Mask = src.m_Mask; +} +CFX_ClipRgn::~CFX_ClipRgn() {} +void CFX_ClipRgn::Reset(const FX_RECT& rect) { + m_Type = RectI; + m_Box = rect; + m_Mask.SetNull(); +} +void CFX_ClipRgn::IntersectRect(const FX_RECT& rect) { + if (m_Type == RectI) { + m_Box.Intersect(rect); + return; + } + if (m_Type == MaskF) { + IntersectMaskRect(rect, m_Box, m_Mask); + return; + } +} +void CFX_ClipRgn::IntersectMaskRect(FX_RECT rect, + FX_RECT mask_rect, + CFX_DIBitmapRef Mask) { + const CFX_DIBitmap* mask_dib = Mask; + m_Type = MaskF; + m_Box = rect; + m_Box.Intersect(mask_rect); + if (m_Box.IsEmpty()) { + m_Type = RectI; + return; + } + if (m_Box == mask_rect) { + m_Mask = Mask; + return; + } + CFX_DIBitmap* new_dib = m_Mask.New(); + if (!new_dib) { + return; + } + new_dib->Create(m_Box.Width(), m_Box.Height(), FXDIB_8bppMask); + for (int row = m_Box.top; row < m_Box.bottom; row++) { + uint8_t* dest_scan = + new_dib->GetBuffer() + new_dib->GetPitch() * (row - m_Box.top); + uint8_t* src_scan = + mask_dib->GetBuffer() + mask_dib->GetPitch() * (row - mask_rect.top); + for (int col = m_Box.left; col < m_Box.right; col++) { + dest_scan[col - m_Box.left] = src_scan[col - mask_rect.left]; + } + } +} +void CFX_ClipRgn::IntersectMaskF(int left, int top, CFX_DIBitmapRef Mask) { + const CFX_DIBitmap* mask_dib = Mask; + ASSERT(mask_dib->GetFormat() == FXDIB_8bppMask); + FX_RECT mask_box(left, top, left + mask_dib->GetWidth(), + top + mask_dib->GetHeight()); + if (m_Type == RectI) { + IntersectMaskRect(m_Box, mask_box, Mask); + return; + } + if (m_Type == MaskF) { + FX_RECT new_box = m_Box; + new_box.Intersect(mask_box); + if (new_box.IsEmpty()) { + m_Type = RectI; + m_Mask.SetNull(); + m_Box = new_box; + return; + } + CFX_DIBitmapRef new_mask; + CFX_DIBitmap* new_dib = new_mask.New(); + if (!new_dib) { + return; + } + new_dib->Create(new_box.Width(), new_box.Height(), FXDIB_8bppMask); + const CFX_DIBitmap* old_dib = m_Mask; + for (int row = new_box.top; row < new_box.bottom; row++) { + uint8_t* old_scan = + old_dib->GetBuffer() + (row - m_Box.top) * old_dib->GetPitch(); + uint8_t* mask_scan = + mask_dib->GetBuffer() + (row - top) * mask_dib->GetPitch(); + uint8_t* new_scan = + new_dib->GetBuffer() + (row - new_box.top) * new_dib->GetPitch(); + for (int col = new_box.left; col < new_box.right; col++) { + new_scan[col - new_box.left] = + old_scan[col - m_Box.left] * mask_scan[col - left] / 255; + } + } + m_Box = new_box; + m_Mask = new_mask; + return; + } + ASSERT(FALSE); +} +CFX_PathData::CFX_PathData() { + m_PointCount = m_AllocCount = 0; + m_pPoints = NULL; +} +CFX_PathData::~CFX_PathData() { + FX_Free(m_pPoints); +} +void CFX_PathData::SetPointCount(int nPoints) { + m_PointCount = nPoints; + if (m_AllocCount < nPoints) { + FX_Free(m_pPoints); + m_pPoints = FX_Alloc(FX_PATHPOINT, nPoints); + m_AllocCount = nPoints; + } +} +void CFX_PathData::AllocPointCount(int nPoints) { + if (m_AllocCount < nPoints) { + FX_PATHPOINT* pNewBuf = FX_Alloc(FX_PATHPOINT, nPoints); + if (m_PointCount) { + FXSYS_memcpy(pNewBuf, m_pPoints, m_PointCount * sizeof(FX_PATHPOINT)); + } + FX_Free(m_pPoints); + m_pPoints = pNewBuf; + m_AllocCount = nPoints; + } +} +CFX_PathData::CFX_PathData(const CFX_PathData& src) { + m_PointCount = m_AllocCount = src.m_PointCount; + m_pPoints = FX_Alloc(FX_PATHPOINT, src.m_PointCount); + FXSYS_memcpy(m_pPoints, src.m_pPoints, sizeof(FX_PATHPOINT) * m_PointCount); +} +void CFX_PathData::TrimPoints(int nPoints) { + if (m_PointCount <= nPoints) { + return; + } + SetPointCount(nPoints); +} +void CFX_PathData::AddPointCount(int addPoints) { + pdfium::base::CheckedNumeric<int> safe_new_count = m_PointCount; + safe_new_count += addPoints; + int new_count = safe_new_count.ValueOrDie(); + AllocPointCount(new_count); + m_PointCount = new_count; +} +void CFX_PathData::Append(const CFX_PathData* pSrc, const CFX_Matrix* pMatrix) { + int old_count = m_PointCount; + AddPointCount(pSrc->m_PointCount); + FXSYS_memcpy(m_pPoints + old_count, pSrc->m_pPoints, + pSrc->m_PointCount * sizeof(FX_PATHPOINT)); + if (pMatrix) { + for (int i = 0; i < pSrc->m_PointCount; i++) { + pMatrix->Transform(m_pPoints[old_count + i].m_PointX, + m_pPoints[old_count + i].m_PointY); + } + } +} +void CFX_PathData::SetPoint(int index, FX_FLOAT x, FX_FLOAT y, int flag) { + ASSERT(index < m_PointCount); + m_pPoints[index].m_PointX = x; + m_pPoints[index].m_PointY = y; + m_pPoints[index].m_Flag = flag; +} +void CFX_PathData::AppendRect(FX_FLOAT left, + FX_FLOAT bottom, + FX_FLOAT right, + FX_FLOAT top) { + int old_count = m_PointCount; + AddPointCount(5); + FX_PATHPOINT* pPoints = m_pPoints + old_count; + pPoints[0].m_PointX = pPoints[1].m_PointX = pPoints[4].m_PointX = left; + pPoints[2].m_PointX = pPoints[3].m_PointX = right; + pPoints[0].m_PointY = pPoints[3].m_PointY = pPoints[4].m_PointY = bottom; + pPoints[1].m_PointY = pPoints[2].m_PointY = top; + pPoints[0].m_Flag = FXPT_MOVETO; + pPoints[1].m_Flag = pPoints[2].m_Flag = pPoints[3].m_Flag = FXPT_LINETO; + pPoints[4].m_Flag = FXPT_LINETO | FXPT_CLOSEFIGURE; +} +CFX_FloatRect CFX_PathData::GetBoundingBox() const { + CFX_FloatRect rect; + if (m_PointCount) { + rect.InitRect(m_pPoints[0].m_PointX, m_pPoints[0].m_PointY); + for (int i = 1; i < m_PointCount; i++) { + rect.UpdateRect(m_pPoints[i].m_PointX, m_pPoints[i].m_PointY); + } + } + return rect; +} +static void _UpdateLineEndPoints(CFX_FloatRect& rect, + FX_FLOAT start_x, + FX_FLOAT start_y, + FX_FLOAT end_x, + FX_FLOAT end_y, + FX_FLOAT hw) { + if (start_x == end_x) { + if (start_y == end_y) { + rect.UpdateRect(end_x + hw, end_y + hw); + rect.UpdateRect(end_x - hw, end_y - hw); + return; + } + FX_FLOAT point_y; + if (end_y < start_y) { + point_y = end_y - hw; + } else { + point_y = end_y + hw; + } + rect.UpdateRect(end_x + hw, point_y); + rect.UpdateRect(end_x - hw, point_y); + return; + } + if (start_y == end_y) { + FX_FLOAT point_x; + if (end_x < start_x) { + point_x = end_x - hw; + } else { + point_x = end_x + hw; + } + rect.UpdateRect(point_x, end_y + hw); + rect.UpdateRect(point_x, end_y - hw); + return; + } + FX_FLOAT dx = end_x - start_x; + FX_FLOAT dy = end_y - start_y; + FX_FLOAT ll = FXSYS_sqrt2(dx, dy); + FX_FLOAT mx = end_x + hw * dx / ll; + FX_FLOAT my = end_y + hw * dy / ll; + FX_FLOAT dx1 = hw * dy / ll; + FX_FLOAT dy1 = hw * dx / ll; + rect.UpdateRect(mx - dx1, my + dy1); + rect.UpdateRect(mx + dx1, my - dy1); +} +static void _UpdateLineJoinPoints(CFX_FloatRect& rect, + FX_FLOAT start_x, + FX_FLOAT start_y, + FX_FLOAT middle_x, + FX_FLOAT middle_y, + FX_FLOAT end_x, + FX_FLOAT end_y, + FX_FLOAT half_width, + FX_FLOAT miter_limit) { + FX_FLOAT start_k = 0, start_c = 0, end_k = 0, end_c = 0, start_len = 0, + start_dc = 0, end_len = 0, end_dc = 0; + FX_BOOL bStartVert = FXSYS_fabs(start_x - middle_x) < 1.0f / 20; + FX_BOOL bEndVert = FXSYS_fabs(middle_x - end_x) < 1.0f / 20; + if (bStartVert && bEndVert) { + int start_dir = middle_y > start_y ? 1 : -1; + FX_FLOAT point_y = middle_y + half_width * start_dir; + rect.UpdateRect(middle_x + half_width, point_y); + rect.UpdateRect(middle_x - half_width, point_y); + return; + } + if (!bStartVert) { + start_k = (middle_y - start_y) / (middle_x - start_x); + start_c = middle_y - (start_k * middle_x); + start_len = FXSYS_sqrt2(start_x - middle_x, start_y - middle_y); + start_dc = + (FX_FLOAT)FXSYS_fabs(half_width * start_len / (start_x - middle_x)); + } + if (!bEndVert) { + end_k = (end_y - middle_y) / (end_x - middle_x); + end_c = middle_y - (end_k * middle_x); + end_len = FXSYS_sqrt2(end_x - middle_x, end_y - middle_y); + end_dc = (FX_FLOAT)FXSYS_fabs(half_width * end_len / (end_x - middle_x)); + } + if (bStartVert) { + FX_FLOAT outside_x = start_x; + if (end_x < start_x) { + outside_x += half_width; + } else { + outside_x -= half_width; + } + FX_FLOAT outside_y; + if (start_y < (end_k * start_x) + end_c) { + outside_y = (end_k * outside_x) + end_c + end_dc; + } else { + outside_y = (end_k * outside_x) + end_c - end_dc; + } + rect.UpdateRect(outside_x, outside_y); + return; + } + if (bEndVert) { + FX_FLOAT outside_x = end_x; + if (start_x < end_x) { + outside_x += half_width; + } else { + outside_x -= half_width; + } + FX_FLOAT outside_y; + if (end_y < (start_k * end_x) + start_c) { + outside_y = (start_k * outside_x) + start_c + start_dc; + } else { + outside_y = (start_k * outside_x) + start_c - start_dc; + } + rect.UpdateRect(outside_x, outside_y); + return; + } + if (FXSYS_fabs(start_k - end_k) < 1.0f / 20) { + int start_dir = middle_x > start_x ? 1 : -1; + int end_dir = end_x > middle_x ? 1 : -1; + if (start_dir == end_dir) { + _UpdateLineEndPoints(rect, middle_x, middle_y, end_x, end_y, half_width); + } else { + _UpdateLineEndPoints(rect, start_x, start_y, middle_x, middle_y, + half_width); + } + return; + } + FX_FLOAT start_outside_c = start_c; + if (end_y < (start_k * end_x) + start_c) { + start_outside_c += start_dc; + } else { + start_outside_c -= start_dc; + } + FX_FLOAT end_outside_c = end_c; + if (start_y < (end_k * start_x) + end_c) { + end_outside_c += end_dc; + } else { + end_outside_c -= end_dc; + } + FX_FLOAT join_x = (end_outside_c - start_outside_c) / (start_k - end_k); + FX_FLOAT join_y = (start_k * join_x) + start_outside_c; + rect.UpdateRect(join_x, join_y); +} +CFX_FloatRect CFX_PathData::GetBoundingBox(FX_FLOAT line_width, + FX_FLOAT miter_limit) const { + CFX_FloatRect rect(100000 * 1.0f, 100000 * 1.0f, -100000 * 1.0f, + -100000 * 1.0f); + int iPoint = 0; + FX_FLOAT half_width = line_width; + int iStartPoint, iEndPoint, iMiddlePoint; + FX_BOOL bJoin; + while (iPoint < m_PointCount) { + if (m_pPoints[iPoint].m_Flag == FXPT_MOVETO) { + iStartPoint = iPoint + 1; + iEndPoint = iPoint; + bJoin = FALSE; + } else { + if (m_pPoints[iPoint].m_Flag == FXPT_BEZIERTO) { + rect.UpdateRect(m_pPoints[iPoint].m_PointX, m_pPoints[iPoint].m_PointY); + rect.UpdateRect(m_pPoints[iPoint + 1].m_PointX, + m_pPoints[iPoint + 1].m_PointY); + iPoint += 2; + } + if (iPoint == m_PointCount - 1 || + m_pPoints[iPoint + 1].m_Flag == FXPT_MOVETO) { + iStartPoint = iPoint - 1; + iEndPoint = iPoint; + bJoin = FALSE; + } else { + iStartPoint = iPoint - 1; + iMiddlePoint = iPoint; + iEndPoint = iPoint + 1; + bJoin = TRUE; + } + } + FX_FLOAT start_x = m_pPoints[iStartPoint].m_PointX; + FX_FLOAT start_y = m_pPoints[iStartPoint].m_PointY; + FX_FLOAT end_x = m_pPoints[iEndPoint].m_PointX; + FX_FLOAT end_y = m_pPoints[iEndPoint].m_PointY; + if (bJoin) { + FX_FLOAT middle_x = m_pPoints[iMiddlePoint].m_PointX; + FX_FLOAT middle_y = m_pPoints[iMiddlePoint].m_PointY; + _UpdateLineJoinPoints(rect, start_x, start_y, middle_x, middle_y, end_x, + end_y, half_width, miter_limit); + } else { + _UpdateLineEndPoints(rect, start_x, start_y, end_x, end_y, half_width); + } + iPoint++; + } + return rect; +} +void CFX_PathData::Transform(const CFX_Matrix* pMatrix) { + if (!pMatrix) { + return; + } + for (int i = 0; i < m_PointCount; i++) { + pMatrix->Transform(m_pPoints[i].m_PointX, m_pPoints[i].m_PointY); + } +} +FX_BOOL CFX_PathData::GetZeroAreaPath(CFX_PathData& NewPath, + CFX_Matrix* pMatrix, + FX_BOOL& bThin, + FX_BOOL bAdjust) const { + if (m_PointCount < 3) { + return FALSE; + } + if (m_PointCount == 3 && (m_pPoints[0].m_Flag & FXPT_TYPE) == FXPT_MOVETO && + (m_pPoints[1].m_Flag & FXPT_TYPE) == FXPT_LINETO && + (m_pPoints[2].m_Flag & FXPT_TYPE) == FXPT_LINETO && + m_pPoints[0].m_PointX == m_pPoints[2].m_PointX && + m_pPoints[0].m_PointY == m_pPoints[2].m_PointY) { + NewPath.AddPointCount(2); + if (bAdjust) { + if (pMatrix) { + FX_FLOAT x = m_pPoints[0].m_PointX, y = m_pPoints[0].m_PointY; + pMatrix->TransformPoint(x, y); + x = (int)x + 0.5f; + y = (int)y + 0.5f; + NewPath.SetPoint(0, x, y, FXPT_MOVETO); + x = m_pPoints[1].m_PointX, y = m_pPoints[1].m_PointY; + pMatrix->TransformPoint(x, y); + x = (int)x + 0.5f; + y = (int)y + 0.5f; + NewPath.SetPoint(1, x, y, FXPT_LINETO); + pMatrix->SetIdentity(); + } else { + FX_FLOAT x = (int)m_pPoints[0].m_PointX + 0.5f, + y = (int)m_pPoints[0].m_PointY + 0.5f; + NewPath.SetPoint(0, x, y, FXPT_MOVETO); + x = (int)m_pPoints[1].m_PointX + 0.5f, + y = (int)m_pPoints[1].m_PointY + 0.5f; + NewPath.SetPoint(1, x, y, FXPT_LINETO); + } + } else { + NewPath.SetPoint(0, m_pPoints[0].m_PointX, m_pPoints[0].m_PointY, + FXPT_MOVETO); + NewPath.SetPoint(1, m_pPoints[1].m_PointX, m_pPoints[1].m_PointY, + FXPT_LINETO); + } + if (m_pPoints[0].m_PointX != m_pPoints[1].m_PointX && + m_pPoints[0].m_PointY != m_pPoints[1].m_PointY) { + bThin = TRUE; + } + return TRUE; + } + if (((m_PointCount > 3) && (m_PointCount % 2))) { + int mid = m_PointCount / 2; + FX_BOOL bZeroArea = FALSE; + CFX_PathData t_path; + for (int i = 0; i < mid; i++) { + if (!(m_pPoints[mid - i - 1].m_PointX == + m_pPoints[mid + i + 1].m_PointX && + m_pPoints[mid - i - 1].m_PointY == + m_pPoints[mid + i + 1].m_PointY && + ((m_pPoints[mid - i - 1].m_Flag & FXPT_TYPE) != FXPT_BEZIERTO && + (m_pPoints[mid + i + 1].m_Flag & FXPT_TYPE) != FXPT_BEZIERTO))) { + bZeroArea = TRUE; + break; + } + int new_count = t_path.GetPointCount(); + t_path.AddPointCount(2); + t_path.SetPoint(new_count, m_pPoints[mid - i].m_PointX, + m_pPoints[mid - i].m_PointY, FXPT_MOVETO); + t_path.SetPoint(new_count + 1, m_pPoints[mid - i - 1].m_PointX, + m_pPoints[mid - i - 1].m_PointY, FXPT_LINETO); + } + if (!bZeroArea) { + NewPath.Append(&t_path, NULL); + bThin = TRUE; + return TRUE; + } + } + int stratPoint = 0; + int next = 0, i; + for (i = 0; i < m_PointCount; i++) { + int point_type = m_pPoints[i].m_Flag & FXPT_TYPE; + if (point_type == FXPT_MOVETO) { + stratPoint = i; + } else if (point_type == FXPT_LINETO) { + next = (i + 1 - stratPoint) % (m_PointCount - stratPoint) + stratPoint; + if ((m_pPoints[next].m_Flag & FXPT_TYPE) != FXPT_BEZIERTO && + (m_pPoints[next].m_Flag & FXPT_TYPE) != FXPT_MOVETO) { + if ((m_pPoints[i - 1].m_PointX == m_pPoints[i].m_PointX && + m_pPoints[i].m_PointX == m_pPoints[next].m_PointX) && + ((m_pPoints[i].m_PointY - m_pPoints[i - 1].m_PointY) * + (m_pPoints[i].m_PointY - m_pPoints[next].m_PointY) > + 0)) { + int pre = i; + if (FXSYS_fabs(m_pPoints[i].m_PointY - m_pPoints[i - 1].m_PointY) < + FXSYS_fabs(m_pPoints[i].m_PointY - m_pPoints[next].m_PointY)) { + pre--; + next--; + } + int new_count = NewPath.GetPointCount(); + NewPath.AddPointCount(2); + NewPath.SetPoint(new_count, m_pPoints[pre].m_PointX, + m_pPoints[pre].m_PointY, FXPT_MOVETO); + NewPath.SetPoint(new_count + 1, m_pPoints[next].m_PointX, + m_pPoints[next].m_PointY, FXPT_LINETO); + } else if ((m_pPoints[i - 1].m_PointY == m_pPoints[i].m_PointY && + m_pPoints[i].m_PointY == m_pPoints[next].m_PointY) && + ((m_pPoints[i].m_PointX - m_pPoints[i - 1].m_PointX) * + (m_pPoints[i].m_PointX - m_pPoints[next].m_PointX) > + 0)) { + int pre = i; + if (FXSYS_fabs(m_pPoints[i].m_PointX - m_pPoints[i - 1].m_PointX) < + FXSYS_fabs(m_pPoints[i].m_PointX - m_pPoints[next].m_PointX)) { + pre--; + next--; + } + int new_count = NewPath.GetPointCount(); + NewPath.AddPointCount(2); + NewPath.SetPoint(new_count, m_pPoints[pre].m_PointX, + m_pPoints[pre].m_PointY, FXPT_MOVETO); + NewPath.SetPoint(new_count + 1, m_pPoints[next].m_PointX, + m_pPoints[next].m_PointY, FXPT_LINETO); + } else if ((m_pPoints[i - 1].m_Flag & FXPT_TYPE) == FXPT_MOVETO && + (m_pPoints[next].m_Flag & FXPT_TYPE) == FXPT_LINETO && + m_pPoints[i - 1].m_PointX == m_pPoints[next].m_PointX && + m_pPoints[i - 1].m_PointY == m_pPoints[next].m_PointY && + m_pPoints[next].m_Flag & FXPT_CLOSEFIGURE) { + int new_count = NewPath.GetPointCount(); + NewPath.AddPointCount(2); + NewPath.SetPoint(new_count, m_pPoints[i - 1].m_PointX, + m_pPoints[i - 1].m_PointY, FXPT_MOVETO); + NewPath.SetPoint(new_count + 1, m_pPoints[i].m_PointX, + m_pPoints[i].m_PointY, FXPT_LINETO); + bThin = TRUE; + } + } + } else if (point_type == FXPT_BEZIERTO) { + i += 2; + continue; + } + } + if (m_PointCount > 3 && NewPath.GetPointCount()) { + bThin = TRUE; + } + if (NewPath.GetPointCount() == 0) { + return FALSE; + } + return TRUE; +} +FX_BOOL CFX_PathData::IsRect() const { + if (m_PointCount != 5 && m_PointCount != 4) { + return FALSE; + } + if ((m_PointCount == 5 && (m_pPoints[0].m_PointX != m_pPoints[4].m_PointX || + m_pPoints[0].m_PointY != m_pPoints[4].m_PointY)) || + (m_pPoints[0].m_PointX == m_pPoints[2].m_PointX && + m_pPoints[0].m_PointY == m_pPoints[2].m_PointY) || + (m_pPoints[1].m_PointX == m_pPoints[3].m_PointX && + m_pPoints[1].m_PointY == m_pPoints[3].m_PointY)) { + return FALSE; + } + if (m_pPoints[0].m_PointX != m_pPoints[3].m_PointX && + m_pPoints[0].m_PointY != m_pPoints[3].m_PointY) { + return FALSE; + } + for (int i = 1; i < 4; i++) { + if ((m_pPoints[i].m_Flag & FXPT_TYPE) != FXPT_LINETO) { + return FALSE; + } + if (m_pPoints[i].m_PointX != m_pPoints[i - 1].m_PointX && + m_pPoints[i].m_PointY != m_pPoints[i - 1].m_PointY) { + return FALSE; + } + } + return m_PointCount == 5 || (m_pPoints[3].m_Flag & FXPT_CLOSEFIGURE); +} +FX_BOOL CFX_PathData::IsRect(const CFX_Matrix* pMatrix, + CFX_FloatRect* pRect) const { + if (!pMatrix) { + if (!IsRect()) { + return FALSE; + } + if (pRect) { + pRect->left = m_pPoints[0].m_PointX; + pRect->right = m_pPoints[2].m_PointX; + pRect->bottom = m_pPoints[0].m_PointY; + pRect->top = m_pPoints[2].m_PointY; + pRect->Normalize(); + } + return TRUE; + } + if (m_PointCount != 5 && m_PointCount != 4) { + return FALSE; + } + if ((m_PointCount == 5 && (m_pPoints[0].m_PointX != m_pPoints[4].m_PointX || + m_pPoints[0].m_PointY != m_pPoints[4].m_PointY)) || + (m_pPoints[1].m_PointX == m_pPoints[3].m_PointX && + m_pPoints[1].m_PointY == m_pPoints[3].m_PointY)) { + return FALSE; + } + if (m_PointCount == 4 && m_pPoints[0].m_PointX != m_pPoints[3].m_PointX && + m_pPoints[0].m_PointY != m_pPoints[3].m_PointY) { + return FALSE; + } + FX_FLOAT x[5], y[5]; + for (int i = 0; i < m_PointCount; i++) { + pMatrix->Transform(m_pPoints[i].m_PointX, m_pPoints[i].m_PointY, x[i], + y[i]); + if (i) { + if ((m_pPoints[i].m_Flag & FXPT_TYPE) != FXPT_LINETO) { + return FALSE; + } + if (x[i] != x[i - 1] && y[i] != y[i - 1]) { + return FALSE; + } + } + } + if (pRect) { + pRect->left = x[0]; + pRect->right = x[2]; + pRect->bottom = y[0]; + pRect->top = y[2]; + pRect->Normalize(); + } + return TRUE; +} +void CFX_PathData::Copy(const CFX_PathData& src) { + SetPointCount(src.m_PointCount); + FXSYS_memcpy(m_pPoints, src.m_pPoints, sizeof(FX_PATHPOINT) * m_PointCount); +} +CFX_GraphStateData::CFX_GraphStateData() { + m_LineCap = LineCapButt; + m_DashCount = 0; + m_DashArray = NULL; + m_DashPhase = 0; + m_LineJoin = LineJoinMiter; + m_MiterLimit = 10 * 1.0f; + m_LineWidth = 1.0f; +} +CFX_GraphStateData::CFX_GraphStateData(const CFX_GraphStateData& src) { + m_DashArray = NULL; + Copy(src); +} +void CFX_GraphStateData::Copy(const CFX_GraphStateData& src) { + m_LineCap = src.m_LineCap; + m_DashCount = src.m_DashCount; + FX_Free(m_DashArray); + m_DashArray = NULL; + m_DashPhase = src.m_DashPhase; + m_LineJoin = src.m_LineJoin; + m_MiterLimit = src.m_MiterLimit; + m_LineWidth = src.m_LineWidth; + if (m_DashCount) { + m_DashArray = FX_Alloc(FX_FLOAT, m_DashCount); + FXSYS_memcpy(m_DashArray, src.m_DashArray, m_DashCount * sizeof(FX_FLOAT)); + } +} +CFX_GraphStateData::~CFX_GraphStateData() { + FX_Free(m_DashArray); +} +void CFX_GraphStateData::SetDashCount(int count) { + FX_Free(m_DashArray); + m_DashArray = NULL; + m_DashCount = count; + if (count == 0) { + return; + } + m_DashArray = FX_Alloc(FX_FLOAT, count); +} diff --git a/core/fxge/ge/fx_ge_ps.cpp b/core/fxge/ge/fx_ge_ps.cpp new file mode 100644 index 0000000000..2470025852 --- /dev/null +++ b/core/fxge/ge/fx_ge_ps.cpp @@ -0,0 +1,700 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/include/fxge/fx_ge.h" + +#include "core/fxge/ge/fx_text_int.h" +#include "core/include/fxcodec/fx_codec.h" + +struct PSGlyph { + CFX_Font* m_pFont; + FX_DWORD m_GlyphIndex; + FX_BOOL m_bGlyphAdjust; + FX_FLOAT m_AdjustMatrix[4]; +}; +class CPSFont { + public: + PSGlyph m_Glyphs[256]; + int m_nGlyphs; +}; +CFX_PSRenderer::CFX_PSRenderer() { + m_pOutput = NULL; + m_bColorSet = m_bGraphStateSet = FALSE; + m_bInited = FALSE; +} +CFX_PSRenderer::~CFX_PSRenderer() { + for (int i = 0; i < (int)m_PSFontList.GetSize(); i++) { + CPSFont* pFont = m_PSFontList[i]; + delete pFont; + } +} +#define OUTPUT_PS(str) m_pOutput->OutputPS(str, sizeof str - 1) +void CFX_PSRenderer::Init(IFX_PSOutput* pOutput, + int pslevel, + int width, + int height, + FX_BOOL bCmykOutput) { + m_PSLevel = pslevel; + m_pOutput = pOutput; + m_ClipBox.left = m_ClipBox.top = 0; + m_ClipBox.right = width; + m_ClipBox.bottom = height; + m_bCmykOutput = bCmykOutput; +} +FX_BOOL CFX_PSRenderer::StartRendering() { + if (m_bInited) { + return TRUE; + } + static const char init_str[] = + "\nsave\n/im/initmatrix load def\n" + "/n/newpath load def/m/moveto load def/l/lineto load def/c/curveto load " + "def/h/closepath load def\n" + "/f/fill load def/F/eofill load def/s/stroke load def/W/clip load " + "def/W*/eoclip load def\n" + "/rg/setrgbcolor load def/k/setcmykcolor load def\n" + "/J/setlinecap load def/j/setlinejoin load def/w/setlinewidth load " + "def/M/setmiterlimit load def/d/setdash load def\n" + "/q/gsave load def/Q/grestore load def/iM/imagemask load def\n" + "/Tj/show load def/Ff/findfont load def/Fs/scalefont load def/Sf/setfont " + "load def\n" + "/cm/concat load def/Cm/currentmatrix load def/mx/matrix load " + "def/sm/setmatrix load def\n"; + OUTPUT_PS(init_str); + m_bInited = TRUE; + return TRUE; +} +void CFX_PSRenderer::EndRendering() { + if (m_bInited) { + OUTPUT_PS("\nrestore\n"); + } + m_bInited = FALSE; +} +void CFX_PSRenderer::SaveState() { + StartRendering(); + OUTPUT_PS("q\n"); + m_ClipBoxStack.Add(m_ClipBox); +} +void CFX_PSRenderer::RestoreState(FX_BOOL bKeepSaved) { + StartRendering(); + if (bKeepSaved) { + OUTPUT_PS("Q\nq\n"); + } else { + OUTPUT_PS("Q\n"); + } + m_bColorSet = m_bGraphStateSet = FALSE; + m_ClipBox = m_ClipBoxStack.GetAt(m_ClipBoxStack.GetSize() - 1); + if (!bKeepSaved) { + m_ClipBoxStack.RemoveAt(m_ClipBoxStack.GetSize() - 1); + } +} +void CFX_PSRenderer::OutputPath(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device) { + int nPoints = pPathData->GetPointCount(); + CFX_ByteTextBuf buf; + buf.EstimateSize(nPoints * 10); + for (int i = 0; i < nPoints; i++) { + uint8_t flag = pPathData->GetFlag(i); + FX_FLOAT x = pPathData->GetPointX(i); + FX_FLOAT y = pPathData->GetPointY(i); + if (pObject2Device) { + pObject2Device->Transform(x, y); + } + buf << x << " " << y; + switch (flag & FXPT_TYPE) { + case FXPT_MOVETO: + buf << " m "; + break; + case FXPT_LINETO: + if (flag & FXPT_CLOSEFIGURE) { + buf << " l h "; + } else { + buf << " l "; + } + break; + case FXPT_BEZIERTO: { + FX_FLOAT x1 = pPathData->GetPointX(i + 1); + FX_FLOAT x2 = pPathData->GetPointX(i + 2); + FX_FLOAT y1 = pPathData->GetPointY(i + 1); + FX_FLOAT y2 = pPathData->GetPointY(i + 2); + if (pObject2Device) { + pObject2Device->Transform(x1, y1); + pObject2Device->Transform(x2, y2); + } + buf << " " << x1 << " " << y1 << " " << x2 << " " << y2; + if (flag & FXPT_CLOSEFIGURE) { + buf << " c h\n"; + } else { + buf << " c\n"; + } + i += 2; + break; + } + } + } + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); +} +void CFX_PSRenderer::SetClip_PathFill(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + int fill_mode) { + StartRendering(); + OutputPath(pPathData, pObject2Device); + CFX_FloatRect rect = pPathData->GetBoundingBox(); + if (pObject2Device) { + rect.Transform(pObject2Device); + } + m_ClipBox.Intersect(rect.GetOutterRect()); + if ((fill_mode & 3) == FXFILL_WINDING) { + OUTPUT_PS("W n\n"); + } else { + OUTPUT_PS("W* n\n"); + } +} +void CFX_PSRenderer::SetClip_PathStroke(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState) { + StartRendering(); + SetGraphState(pGraphState); + if (pObject2Device) { + CFX_ByteTextBuf buf; + buf << "mx Cm [" << pObject2Device->a << " " << pObject2Device->b << " " + << pObject2Device->c << " " << pObject2Device->d << " " + << pObject2Device->e << " " << pObject2Device->f << "]cm "; + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + } + OutputPath(pPathData, NULL); + CFX_FloatRect rect = pPathData->GetBoundingBox(pGraphState->m_LineWidth, + pGraphState->m_MiterLimit); + rect.Transform(pObject2Device); + m_ClipBox.Intersect(rect.GetOutterRect()); + if (pObject2Device) { + OUTPUT_PS("strokepath W n sm\n"); + } else { + OUTPUT_PS("strokepath W n\n"); + } +} +FX_BOOL CFX_PSRenderer::DrawPath(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState, + FX_DWORD fill_color, + FX_DWORD stroke_color, + int fill_mode, + int alpha_flag, + void* pIccTransform) { + StartRendering(); + int fill_alpha = FXGETFLAG_COLORTYPE(alpha_flag) + ? FXGETFLAG_ALPHA_FILL(alpha_flag) + : FXARGB_A(fill_color); + int stroke_alpha = FXGETFLAG_COLORTYPE(alpha_flag) + ? FXGETFLAG_ALPHA_STROKE(alpha_flag) + : FXARGB_A(stroke_color); + if (fill_alpha && fill_alpha < 255) { + return FALSE; + } + if (stroke_alpha && stroke_alpha < 255) { + return FALSE; + } + if (fill_alpha == 0 && stroke_alpha == 0) { + return FALSE; + } + if (stroke_alpha) { + SetGraphState(pGraphState); + if (pObject2Device) { + CFX_ByteTextBuf buf; + buf << "mx Cm [" << pObject2Device->a << " " << pObject2Device->b << " " + << pObject2Device->c << " " << pObject2Device->d << " " + << pObject2Device->e << " " << pObject2Device->f << "]cm "; + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + } + } + OutputPath(pPathData, stroke_alpha ? NULL : pObject2Device); + if (fill_mode && fill_alpha) { + SetColor(fill_color, alpha_flag, pIccTransform); + if ((fill_mode & 3) == FXFILL_WINDING) { + if (stroke_alpha) { + OUTPUT_PS("q f Q "); + } else { + OUTPUT_PS("f"); + } + } else if ((fill_mode & 3) == FXFILL_ALTERNATE) { + if (stroke_alpha) { + OUTPUT_PS("q F Q "); + } else { + OUTPUT_PS("F"); + } + } + } + if (stroke_alpha) { + SetColor(stroke_color, alpha_flag, pIccTransform); + if (pObject2Device) { + OUTPUT_PS("s sm"); + } else { + OUTPUT_PS("s"); + } + } + OUTPUT_PS("\n"); + return TRUE; +} +void CFX_PSRenderer::SetGraphState(const CFX_GraphStateData* pGraphState) { + CFX_ByteTextBuf buf; + if (!m_bGraphStateSet || + m_CurGraphState.m_LineCap != pGraphState->m_LineCap) { + buf << pGraphState->m_LineCap << " J\n"; + } + if (!m_bGraphStateSet || + m_CurGraphState.m_DashCount != pGraphState->m_DashCount || + FXSYS_memcmp(m_CurGraphState.m_DashArray, pGraphState->m_DashArray, + sizeof(FX_FLOAT) * m_CurGraphState.m_DashCount)) { + buf << "["; + for (int i = 0; i < pGraphState->m_DashCount; i++) { + buf << pGraphState->m_DashArray[i] << " "; + } + buf << "]" << pGraphState->m_DashPhase << " d\n"; + } + if (!m_bGraphStateSet || + m_CurGraphState.m_LineJoin != pGraphState->m_LineJoin) { + buf << pGraphState->m_LineJoin << " j\n"; + } + if (!m_bGraphStateSet || + m_CurGraphState.m_LineWidth != pGraphState->m_LineWidth) { + buf << pGraphState->m_LineWidth << " w\n"; + } + if (!m_bGraphStateSet || + m_CurGraphState.m_MiterLimit != pGraphState->m_MiterLimit) { + buf << pGraphState->m_MiterLimit << " M\n"; + } + m_CurGraphState.Copy(*pGraphState); + m_bGraphStateSet = TRUE; + if (buf.GetSize()) { + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + } +} +static void FaxCompressData(uint8_t* src_buf, + int width, + int height, + uint8_t*& dest_buf, + FX_DWORD& dest_size) { + CCodec_ModuleMgr* pEncoders = CFX_GEModule::Get()->GetCodecModule(); + if (width * height > 128 && pEncoders && + pEncoders->GetFaxModule()->Encode(src_buf, width, height, (width + 7) / 8, + dest_buf, dest_size)) { + FX_Free(src_buf); + } else { + dest_buf = src_buf; + dest_size = (width + 7) / 8 * height; + } +} +static void PSCompressData(int PSLevel, + uint8_t* src_buf, + FX_DWORD src_size, + uint8_t*& output_buf, + FX_DWORD& output_size, + const FX_CHAR*& filter) { + output_buf = src_buf; + output_size = src_size; + filter = ""; + if (src_size < 1024) { + return; + } + CCodec_ModuleMgr* pEncoders = CFX_GEModule::Get()->GetCodecModule(); + uint8_t* dest_buf = NULL; + FX_DWORD dest_size = src_size; + if (PSLevel >= 3) { + if (pEncoders && + pEncoders->GetFlateModule()->Encode(src_buf, src_size, dest_buf, + dest_size)) { + filter = "/FlateDecode filter "; + } + } else { + if (pEncoders && + pEncoders->GetBasicModule()->RunLengthEncode(src_buf, src_size, + dest_buf, dest_size)) { + filter = "/RunLengthDecode filter "; + } + } + if (dest_size < src_size) { + output_buf = dest_buf; + output_size = dest_size; + } else { + filter = NULL; + FX_Free(dest_buf); + } +} +FX_BOOL CFX_PSRenderer::SetDIBits(const CFX_DIBSource* pSource, + FX_DWORD color, + int left, + int top, + int alpha_flag, + void* pIccTransform) { + StartRendering(); + CFX_Matrix matrix((FX_FLOAT)(pSource->GetWidth()), 0.0f, 0.0f, + -(FX_FLOAT)(pSource->GetHeight()), (FX_FLOAT)(left), + (FX_FLOAT)(top + pSource->GetHeight())); + return DrawDIBits(pSource, color, &matrix, 0, alpha_flag, pIccTransform); +} +FX_BOOL CFX_PSRenderer::StretchDIBits(const CFX_DIBSource* pSource, + FX_DWORD color, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + FX_DWORD flags, + int alpha_flag, + void* pIccTransform) { + StartRendering(); + CFX_Matrix matrix((FX_FLOAT)(dest_width), 0.0f, 0.0f, + (FX_FLOAT)(-dest_height), (FX_FLOAT)(dest_left), + (FX_FLOAT)(dest_top + dest_height)); + return DrawDIBits(pSource, color, &matrix, flags, alpha_flag, pIccTransform); +} +FX_BOOL CFX_PSRenderer::DrawDIBits(const CFX_DIBSource* pSource, + FX_DWORD color, + const CFX_Matrix* pMatrix, + FX_DWORD flags, + int alpha_flag, + void* pIccTransform) { + StartRendering(); + if ((pMatrix->a == 0 && pMatrix->b == 0) || + (pMatrix->c == 0 && pMatrix->d == 0)) { + return TRUE; + } + if (pSource->HasAlpha()) { + return FALSE; + } + int alpha = FXGETFLAG_COLORTYPE(alpha_flag) ? FXGETFLAG_ALPHA_FILL(color) + : FXARGB_A(color); + if (pSource->IsAlphaMask() && (alpha < 255 || pSource->GetBPP() != 1)) { + return FALSE; + } + OUTPUT_PS("q\n"); + CFX_ByteTextBuf buf; + buf << "[" << pMatrix->a << " " << pMatrix->b << " " << pMatrix->c << " " + << pMatrix->d << " " << pMatrix->e << " " << pMatrix->f << "]cm "; + int width = pSource->GetWidth(); + int height = pSource->GetHeight(); + buf << width << " " << height; + if (pSource->GetBPP() == 1 && !pSource->GetPalette()) { + int pitch = (width + 7) / 8; + FX_DWORD src_size = height * pitch; + uint8_t* src_buf = FX_Alloc(uint8_t, src_size); + for (int row = 0; row < height; row++) { + const uint8_t* src_scan = pSource->GetScanline(row); + FXSYS_memcpy(src_buf + row * pitch, src_scan, pitch); + } + uint8_t* output_buf; + FX_DWORD output_size; + FaxCompressData(src_buf, width, height, output_buf, output_size); + if (pSource->IsAlphaMask()) { + SetColor(color, alpha_flag, pIccTransform); + m_bColorSet = FALSE; + buf << " true["; + } else { + buf << " 1["; + } + buf << width << " 0 0 -" << height << " 0 " << height + << "]currentfile/ASCII85Decode filter "; + if (output_buf != src_buf) + buf << "<</K -1/EndOfBlock false/Columns " << width << "/Rows " << height + << ">>/CCITTFaxDecode filter "; + if (pSource->IsAlphaMask()) { + buf << "iM\n"; + } else { + buf << "false 1 colorimage\n"; + } + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + WritePSBinary(output_buf, output_size); + FX_Free(output_buf); + } else { + CFX_DIBSource* pConverted = (CFX_DIBSource*)pSource; + if (pIccTransform) { + FXDIB_Format format = m_bCmykOutput ? FXDIB_Cmyk : FXDIB_Rgb; + pConverted = pSource->CloneConvert(format, NULL, pIccTransform); + } else { + switch (pSource->GetFormat()) { + case FXDIB_1bppRgb: + case FXDIB_Rgb32: + pConverted = pSource->CloneConvert(FXDIB_Rgb); + break; + case FXDIB_8bppRgb: + if (pSource->GetPalette()) { + pConverted = pSource->CloneConvert(FXDIB_Rgb); + } + break; + case FXDIB_1bppCmyk: + pConverted = pSource->CloneConvert(FXDIB_Cmyk); + break; + case FXDIB_8bppCmyk: + if (pSource->GetPalette()) { + pConverted = pSource->CloneConvert(FXDIB_Cmyk); + } + break; + default: + break; + } + } + if (!pConverted) { + OUTPUT_PS("\nQ\n"); + return FALSE; + } + int Bpp = pConverted->GetBPP() / 8; + uint8_t* output_buf = NULL; + FX_STRSIZE output_size = 0; + const FX_CHAR* filter = NULL; + if (flags & FXRENDER_IMAGE_LOSSY) { + CCodec_ModuleMgr* pEncoders = CFX_GEModule::Get()->GetCodecModule(); + if (pEncoders && + pEncoders->GetJpegModule()->Encode(pConverted, output_buf, + output_size)) { + filter = "/DCTDecode filter "; + } + } + if (!filter) { + int src_pitch = width * Bpp; + output_size = height * src_pitch; + output_buf = FX_Alloc(uint8_t, output_size); + for (int row = 0; row < height; row++) { + const uint8_t* src_scan = pConverted->GetScanline(row); + uint8_t* dest_scan = output_buf + row * src_pitch; + if (Bpp == 3) { + for (int col = 0; col < width; col++) { + *dest_scan++ = src_scan[2]; + *dest_scan++ = src_scan[1]; + *dest_scan++ = *src_scan; + src_scan += 3; + } + } else { + FXSYS_memcpy(dest_scan, src_scan, src_pitch); + } + } + uint8_t* compressed_buf; + FX_DWORD compressed_size; + PSCompressData(m_PSLevel, output_buf, output_size, compressed_buf, + compressed_size, filter); + if (output_buf != compressed_buf) { + FX_Free(output_buf); + } + output_buf = compressed_buf; + output_size = compressed_size; + } + if (pConverted != pSource) { + delete pConverted; + pConverted = NULL; + } + buf << " 8["; + buf << width << " 0 0 -" << height << " 0 " << height << "]"; + buf << "currentfile/ASCII85Decode filter "; + if (filter) { + buf << filter; + } + buf << "false " << Bpp; + buf << " colorimage\n"; + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + WritePSBinary(output_buf, output_size); + FX_Free(output_buf); + } + OUTPUT_PS("\nQ\n"); + return TRUE; +} +void CFX_PSRenderer::SetColor(FX_DWORD color, + int alpha_flag, + void* pIccTransform) { + if (!CFX_GEModule::Get()->GetCodecModule() || + !CFX_GEModule::Get()->GetCodecModule()->GetIccModule()) { + pIccTransform = NULL; + } + FX_BOOL bCMYK = FALSE; + if (pIccTransform) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + color = FXGETFLAG_COLORTYPE(alpha_flag) ? FXCMYK_TODIB(color) + : FXARGB_TODIB(color); + uint8_t* pColor = (uint8_t*)&color; + pIccModule->TranslateScanline(pIccTransform, pColor, pColor, 1); + color = m_bCmykOutput ? FXCMYK_TODIB(color) : FXARGB_TODIB(color); + bCMYK = m_bCmykOutput; + } else { + bCMYK = FXGETFLAG_COLORTYPE(alpha_flag); + } + if (bCMYK != m_bCmykOutput || !m_bColorSet || m_LastColor != color) { + CFX_ByteTextBuf buf; + if (bCMYK) { + buf << FXSYS_GetCValue(color) / 255.0 << " " + << FXSYS_GetMValue(color) / 255.0 << " " + << FXSYS_GetYValue(color) / 255.0 << " " + << FXSYS_GetKValue(color) / 255.0 << " k\n"; + } else { + buf << FXARGB_R(color) / 255.0 << " " << FXARGB_G(color) / 255.0 << " " + << FXARGB_B(color) / 255.0 << " rg\n"; + } + if (bCMYK == m_bCmykOutput) { + m_bColorSet = TRUE; + m_LastColor = color; + } + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + } +} +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 << "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 << "/X" << m_PSFontList.GetSize() - 1 << " exch definefont pop\n"; + m_pOutput->OutputPS((const FX_CHAR*)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_Matrix 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) { + return; + } + CFX_PathData TransformedPath(*pPathData); + if (charpos.m_bGlyphAdjust) { + TransformedPath.Transform(&matrix); + } + CFX_ByteTextBuf buf; + buf << "/X" << ps_fontnum << " Ff/CharProcs get begin/" << ps_glyphindex + << "{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 << " " << y << " m\n"; + break; + } + case FXPT_LINETO: { + buf << x << " " << y << " l\n"; + break; + } + case FXPT_BEZIERTO: { + buf << x << " " << y << " " << TransformedPath.GetPointX(p + 1) << " " + << TransformedPath.GetPointY(p + 1) << " " + << TransformedPath.GetPointX(p + 2) << " " + << TransformedPath.GetPointY(p + 2) << " c\n"; + p += 2; + break; + } + } + } + buf << "f}bind def end\n"; + buf << "/X" << ps_fontnum << " Ff/Encoding get " << ps_glyphindex << "/" + << ps_glyphindex << " put\n"; + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); +} +FX_BOOL CFX_PSRenderer::DrawText(int nChars, + const FXTEXT_CHARPOS* pCharPos, + CFX_Font* pFont, + CFX_FontCache* pCache, + const CFX_Matrix* pObject2Device, + FX_FLOAT font_size, + FX_DWORD color, + int alpha_flag, + void* pIccTransform) { + StartRendering(); + int alpha = FXGETFLAG_COLORTYPE(alpha_flag) ? FXGETFLAG_ALPHA_FILL(alpha_flag) + : FXARGB_A(color); + if (alpha < 255) { + return FALSE; + } + if ((pObject2Device->a == 0 && pObject2Device->b == 0) || + (pObject2Device->c == 0 && pObject2Device->d == 0)) { + return TRUE; + } + SetColor(color, alpha_flag, pIccTransform); + CFX_ByteTextBuf buf; + buf << "q[" << pObject2Device->a << " " << pObject2Device->b << " " + << pObject2Device->c << " " << pObject2Device->d << " " + << pObject2Device->e << " " << pObject2Device->f << "]cm\n"; + if (!pCache) { + pCache = CFX_GEModule::Get()->GetFontCache(); + } + CFX_FaceCache* pFaceCache = pCache->GetCachedFace(pFont); + FX_FONTCACHE_DEFINE(pCache, pFont); + int last_fontnum = -1; + for (int i = 0; i < nChars; i++) { + int ps_fontnum, ps_glyphindex; + FindPSFontGlyph(pFaceCache, pFont, pCharPos[i], ps_fontnum, ps_glyphindex); + if (last_fontnum != ps_fontnum) { + buf << "/X" << ps_fontnum << " Ff " << font_size << " Fs Sf "; + last_fontnum = ps_fontnum; + } + buf << pCharPos[i].m_OriginX << " " << pCharPos[i].m_OriginY << " m"; + CFX_ByteString hex; + hex.Format("<%02X>", ps_glyphindex); + buf << hex << "Tj\n"; + } + buf << "Q\n"; + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + return TRUE; +} +void CFX_PSRenderer::WritePSBinary(const uint8_t* data, int len) { + uint8_t* dest_buf; + FX_DWORD dest_size; + CCodec_ModuleMgr* pEncoders = CFX_GEModule::Get()->GetCodecModule(); + if (pEncoders && + pEncoders->GetBasicModule()->A85Encode(data, len, dest_buf, dest_size)) { + m_pOutput->OutputPS((const FX_CHAR*)dest_buf, dest_size); + FX_Free(dest_buf); + } else { + m_pOutput->OutputPS((const FX_CHAR*)data, len); + } +} diff --git a/core/fxge/ge/fx_ge_text.cpp b/core/fxge/ge/fx_ge_text.cpp new file mode 100644 index 0000000000..3f001d2f96 --- /dev/null +++ b/core/fxge/ge/fx_ge_text.cpp @@ -0,0 +1,1872 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxge/ge/fx_text_int.h" +#include "core/include/fxcodec/fx_codec.h" +#include "core/include/fxge/fx_freetype.h" +#include "core/include/fxge/fx_ge.h" + +#undef FX_GAMMA +#undef FX_GAMMA_INVERSE +#define FX_GAMMA(value) (value) +#define FX_GAMMA_INVERSE(value) (value) + +namespace { + +void ResetTransform(FT_Face face) { + FXFT_Matrix matrix; + matrix.xx = 0x10000L; + matrix.xy = 0; + matrix.yx = 0; + matrix.yy = 0x10000L; + FXFT_Set_Transform(face, &matrix, 0); +} + +// Sets the given transform on the font, and resets it to the identity when it +// goes out of scope. +class ScopedFontTransform { + public: + ScopedFontTransform(FT_Face face, FXFT_Matrix* matrix) : m_Face(face) { + FXFT_Set_Transform(m_Face, matrix, 0); + } + + ~ScopedFontTransform() { ResetTransform(m_Face); } + + private: + FT_Face m_Face; +}; + +} // namespace + +FX_RECT FXGE_GetGlyphsBBox(FXTEXT_GLYPHPOS* pGlyphAndPos, + int nChars, + int anti_alias, + FX_FLOAT retinaScaleX, + FX_FLOAT retinaScaleY) { + FX_RECT rect(0, 0, 0, 0); + FX_BOOL bStarted = FALSE; + for (int iChar = 0; iChar < nChars; iChar++) { + FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar]; + const CFX_GlyphBitmap* pGlyph = glyph.m_pGlyph; + if (!pGlyph) { + continue; + } + int char_left = glyph.m_OriginX + pGlyph->m_Left; + int char_width = (int)(pGlyph->m_Bitmap.GetWidth() / retinaScaleX); + if (anti_alias == FXFT_RENDER_MODE_LCD) { + char_width /= 3; + } + int char_right = char_left + char_width; + int char_top = glyph.m_OriginY - pGlyph->m_Top; + int char_bottom = + char_top + (int)(pGlyph->m_Bitmap.GetHeight() / retinaScaleY); + if (!bStarted) { + rect.left = char_left; + rect.right = char_right; + rect.top = char_top; + rect.bottom = char_bottom; + bStarted = TRUE; + } else { + if (rect.left > char_left) { + rect.left = char_left; + } + if (rect.right < char_right) { + rect.right = char_right; + } + if (rect.top > char_top) { + rect.top = char_top; + } + if (rect.bottom < char_bottom) { + rect.bottom = char_bottom; + } + } + } + return rect; +} +static void _AdjustGlyphSpace(FXTEXT_GLYPHPOS* pGlyphAndPos, int nChars) { + ASSERT(nChars > 1); + FX_BOOL bVertical = FALSE; + if (pGlyphAndPos[nChars - 1].m_OriginX == pGlyphAndPos[0].m_OriginX) { + bVertical = TRUE; + } else if (pGlyphAndPos[nChars - 1].m_OriginY != pGlyphAndPos[0].m_OriginY) { + return; + } + int i = nChars - 1; + int* next_origin = + bVertical ? &pGlyphAndPos[i].m_OriginY : &pGlyphAndPos[i].m_OriginX; + FX_FLOAT next_origin_f = + bVertical ? pGlyphAndPos[i].m_fOriginY : pGlyphAndPos[i].m_fOriginX; + for (i--; i > 0; i--) { + int* this_origin = + bVertical ? &pGlyphAndPos[i].m_OriginY : &pGlyphAndPos[i].m_OriginX; + FX_FLOAT this_origin_f = + bVertical ? pGlyphAndPos[i].m_fOriginY : pGlyphAndPos[i].m_fOriginX; + int space = (*next_origin) - (*this_origin); + FX_FLOAT space_f = next_origin_f - this_origin_f; + FX_FLOAT error = + (FX_FLOAT)(FXSYS_fabs(space_f) - FXSYS_fabs((FX_FLOAT)(space))); + if (error > 0.5f) { + *this_origin += space > 0 ? -1 : 1; + } + next_origin = this_origin; + next_origin_f = this_origin_f; + } +} +static const uint8_t g_TextGammaAdjust[256] = { + 0, 2, 3, 4, 6, 7, 8, 10, 11, 12, 13, 15, 16, 17, 18, + 19, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, + 36, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, + 172, 173, 174, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 190, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, + 228, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 250, 251, 252, 253, 254, + 255, +}; +#define ADJUST_ALPHA(background, foreground, src_alpha, text_flags, a) \ + src_alpha = g_TextGammaAdjust[(uint8_t)src_alpha]; +void _Color2Argb(FX_ARGB& argb, + FX_DWORD color, + int alpha_flag, + void* pIccTransform) { + if (!pIccTransform && !FXGETFLAG_COLORTYPE(alpha_flag)) { + argb = color; + return; + } + if (!CFX_GEModule::Get()->GetCodecModule() || + !CFX_GEModule::Get()->GetCodecModule()->GetIccModule()) { + pIccTransform = NULL; + } + uint8_t bgra[4]; + if (pIccTransform) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + color = FXGETFLAG_COLORTYPE(alpha_flag) ? FXCMYK_TODIB(color) + : FXARGB_TODIB(color); + pIccModule->TranslateScanline(pIccTransform, bgra, (const uint8_t*)&color, + 1); + bgra[3] = FXGETFLAG_COLORTYPE(alpha_flag) + ? (alpha_flag >> 24) ? FXGETFLAG_ALPHA_FILL(alpha_flag) + : FXGETFLAG_ALPHA_STROKE(alpha_flag) + : FXARGB_A(color); + argb = FXARGB_MAKE(bgra[3], bgra[2], bgra[1], bgra[0]); + return; + } + AdobeCMYK_to_sRGB1(FXSYS_GetCValue(color), FXSYS_GetMValue(color), + FXSYS_GetYValue(color), FXSYS_GetKValue(color), bgra[2], + bgra[1], bgra[0]); + bgra[3] = (alpha_flag >> 24) ? FXGETFLAG_ALPHA_FILL(alpha_flag) + : FXGETFLAG_ALPHA_STROKE(alpha_flag); + argb = FXARGB_MAKE(bgra[3], bgra[2], bgra[1], bgra[0]); +} +FX_BOOL CFX_RenderDevice::DrawNormalText(int nChars, + const FXTEXT_CHARPOS* pCharPos, + CFX_Font* pFont, + CFX_FontCache* pCache, + FX_FLOAT font_size, + const CFX_Matrix* pText2Device, + FX_DWORD fill_color, + FX_DWORD text_flags, + int alpha_flag, + void* pIccTransform) { + int nativetext_flags = text_flags; + if (m_DeviceClass != FXDC_DISPLAY) { + if (!(text_flags & FXTEXT_PRINTGRAPHICTEXT)) { + bool should_call_draw_device_text = true; +#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ + if ((text_flags & FXFONT_CIDFONT) || + (pFont->GetPsName().Find(CFX_WideString::FromLocal("+ZJHL")) != -1) || + (pFont->GetPsName() == CFX_WideString::FromLocal("CNAAJI+cmex10"))) { + should_call_draw_device_text = false; + } +#endif + if (should_call_draw_device_text && + m_pDeviceDriver->DrawDeviceText(nChars, pCharPos, pFont, pCache, + pText2Device, font_size, fill_color, + alpha_flag, pIccTransform)) { + return TRUE; + } + } + int alpha = FXGETFLAG_COLORTYPE(alpha_flag) + ? FXGETFLAG_ALPHA_FILL(alpha_flag) + : FXARGB_A(fill_color); + if (alpha < 255) { + return FALSE; + } + } else if (!(text_flags & FXTEXT_NO_NATIVETEXT)) { + bool should_call_draw_device_text = true; +#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ + if ((text_flags & FXFONT_CIDFONT) || + (pFont->GetPsName() == CFX_WideString::FromLocal("CNAAJI+cmex10"))) { + should_call_draw_device_text = false; + } +#endif + if (should_call_draw_device_text && + m_pDeviceDriver->DrawDeviceText(nChars, pCharPos, pFont, pCache, + pText2Device, font_size, fill_color, + alpha_flag, pIccTransform)) { + return TRUE; + } + } + CFX_Matrix char2device, deviceCtm, text2Device; + if (pText2Device) { + char2device = *pText2Device; + text2Device = *pText2Device; + } + char2device.Scale(font_size, -font_size); + if (FXSYS_fabs(char2device.a) + FXSYS_fabs(char2device.b) > 50 * 1.0f || + ((m_DeviceClass == FXDC_PRINTER && !m_pDeviceDriver->IsPSPrintDriver()) && + !(text_flags & FXTEXT_PRINTIMAGETEXT))) { + if (pFont->GetFace() || + (pFont->GetSubstFont()->m_SubstFlags & FXFONT_SUBST_GLYPHPATH)) { + int nPathFlags = + (text_flags & FXTEXT_NOSMOOTH) == 0 ? 0 : FXFILL_NOPATHSMOOTH; + return DrawTextPath(nChars, pCharPos, pFont, pCache, font_size, + pText2Device, NULL, NULL, fill_color, 0, NULL, + nPathFlags, alpha_flag, pIccTransform); + } + } + int anti_alias = FXFT_RENDER_MODE_MONO; + FX_BOOL bNormal = FALSE; + if ((text_flags & FXTEXT_NOSMOOTH) == 0) { + if (m_DeviceClass == FXDC_DISPLAY && m_bpp > 1) { + FX_BOOL bClearType; + if (!pFont->GetFace() && + !(pFont->GetSubstFont()->m_SubstFlags & FXFONT_SUBST_CLEARTYPE)) { + bClearType = FALSE; + } else { + bClearType = text_flags & FXTEXT_CLEARTYPE; + } + if ((m_RenderCaps & (FXRC_ALPHA_OUTPUT | FXRC_CMYK_OUTPUT))) { + anti_alias = FXFT_RENDER_MODE_LCD; + bNormal = TRUE; + } else if (m_bpp < 16) { + anti_alias = FXFT_RENDER_MODE_NORMAL; + } else { + if (bClearType == FALSE) { + anti_alias = FXFT_RENDER_MODE_LCD; + bNormal = TRUE; + } else { + anti_alias = FXFT_RENDER_MODE_LCD; + } + } + } + } + if (!pCache) { + pCache = CFX_GEModule::Get()->GetFontCache(); + } + CFX_FaceCache* pFaceCache = pCache->GetCachedFace(pFont); + FX_FONTCACHE_DEFINE(pCache, pFont); + FXTEXT_GLYPHPOS* pGlyphAndPos = FX_Alloc(FXTEXT_GLYPHPOS, nChars); + int iChar; + deviceCtm = char2device; + CFX_Matrix matrixCTM = GetCTM(); + FX_FLOAT scale_x = FXSYS_fabs(matrixCTM.a); + FX_FLOAT scale_y = FXSYS_fabs(matrixCTM.d); + deviceCtm.Concat(scale_x, 0, 0, scale_y, 0, 0); + text2Device.Concat(scale_x, 0, 0, scale_y, 0, 0); + for (iChar = 0; iChar < nChars; iChar++) { + FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar]; + const FXTEXT_CHARPOS& charpos = pCharPos[iChar]; + glyph.m_fOriginX = charpos.m_OriginX; + glyph.m_fOriginY = charpos.m_OriginY; + text2Device.Transform(glyph.m_fOriginX, glyph.m_fOriginY); + if (anti_alias < FXFT_RENDER_MODE_LCD) { + glyph.m_OriginX = FXSYS_round(glyph.m_fOriginX); + } else { + glyph.m_OriginX = (int)FXSYS_floor(glyph.m_fOriginX); + } + glyph.m_OriginY = FXSYS_round(glyph.m_fOriginY); + if (charpos.m_bGlyphAdjust) { + CFX_Matrix new_matrix( + charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1], + charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0); + new_matrix.Concat(deviceCtm); + glyph.m_pGlyph = pFaceCache->LoadGlyphBitmap( + pFont, charpos.m_GlyphIndex, charpos.m_bFontStyle, &new_matrix, + charpos.m_FontCharWidth, anti_alias, nativetext_flags); + } else { + glyph.m_pGlyph = pFaceCache->LoadGlyphBitmap( + pFont, charpos.m_GlyphIndex, charpos.m_bFontStyle, &deviceCtm, + charpos.m_FontCharWidth, anti_alias, nativetext_flags); + } + } + if (anti_alias < FXFT_RENDER_MODE_LCD && nChars > 1) { + _AdjustGlyphSpace(pGlyphAndPos, nChars); + } + FX_RECT bmp_rect1 = FXGE_GetGlyphsBBox(pGlyphAndPos, nChars, anti_alias); + if (scale_x > 1 && scale_y > 1) { + bmp_rect1.left--; + bmp_rect1.top--; + bmp_rect1.right++; + bmp_rect1.bottom++; + } + FX_RECT bmp_rect(FXSYS_round((FX_FLOAT)(bmp_rect1.left) / scale_x), + FXSYS_round((FX_FLOAT)(bmp_rect1.top) / scale_y), + FXSYS_round((FX_FLOAT)bmp_rect1.right / scale_x), + FXSYS_round((FX_FLOAT)bmp_rect1.bottom / scale_y)); + bmp_rect.Intersect(m_ClipBox); + if (bmp_rect.IsEmpty()) { + FX_Free(pGlyphAndPos); + return TRUE; + } + int pixel_width = FXSYS_round(bmp_rect.Width() * scale_x); + int pixel_height = FXSYS_round(bmp_rect.Height() * scale_y); + int pixel_left = FXSYS_round(bmp_rect.left * scale_x); + int pixel_top = FXSYS_round(bmp_rect.top * scale_y); + if (anti_alias == FXFT_RENDER_MODE_MONO) { + CFX_DIBitmap bitmap; + if (!bitmap.Create(pixel_width, pixel_height, FXDIB_1bppMask)) { + FX_Free(pGlyphAndPos); + return FALSE; + } + bitmap.Clear(0); + for (iChar = 0; iChar < nChars; iChar++) { + FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar]; + if (!glyph.m_pGlyph) { + continue; + } + const CFX_DIBitmap* pGlyph = &glyph.m_pGlyph->m_Bitmap; + bitmap.TransferBitmap( + glyph.m_OriginX + glyph.m_pGlyph->m_Left - pixel_left, + glyph.m_OriginY - glyph.m_pGlyph->m_Top - pixel_top, + pGlyph->GetWidth(), pGlyph->GetHeight(), pGlyph, 0, 0); + } + FX_Free(pGlyphAndPos); + return SetBitMask(&bitmap, bmp_rect.left, bmp_rect.top, fill_color); + } + CFX_DIBitmap bitmap; + if (m_bpp == 8) { + if (!bitmap.Create(pixel_width, pixel_height, FXDIB_8bppMask)) { + FX_Free(pGlyphAndPos); + return FALSE; + } + } else { + if (!CreateCompatibleBitmap(&bitmap, pixel_width, pixel_height)) { + FX_Free(pGlyphAndPos); + return FALSE; + } + } + if (!bitmap.HasAlpha() && !bitmap.IsAlphaMask()) { + bitmap.Clear(0xFFFFFFFF); + if (!GetDIBits(&bitmap, bmp_rect.left, bmp_rect.top)) { + FX_Free(pGlyphAndPos); + return FALSE; + } + } else { + bitmap.Clear(0); + if (bitmap.m_pAlphaMask) { + bitmap.m_pAlphaMask->Clear(0); + } + } + int dest_width = pixel_width; + uint8_t* dest_buf = bitmap.GetBuffer(); + int dest_pitch = bitmap.GetPitch(); + int Bpp = bitmap.GetBPP() / 8; + int a, r, g, b; + if (anti_alias == FXFT_RENDER_MODE_LCD) { + _Color2Argb(fill_color, fill_color, alpha_flag | (1 << 24), pIccTransform); + ArgbDecode(fill_color, a, r, g, b); + r = FX_GAMMA(r); + g = FX_GAMMA(g); + b = FX_GAMMA(b); + } + for (iChar = 0; iChar < nChars; iChar++) { + FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar]; + if (!glyph.m_pGlyph) { + continue; + } + const CFX_DIBitmap* pGlyph = &glyph.m_pGlyph->m_Bitmap; + int left = glyph.m_OriginX + glyph.m_pGlyph->m_Left - pixel_left; + int top = glyph.m_OriginY - glyph.m_pGlyph->m_Top - pixel_top; + int ncols = pGlyph->GetWidth(); + int nrows = pGlyph->GetHeight(); + if (anti_alias == FXFT_RENDER_MODE_NORMAL) { + if (!bitmap.CompositeMask(left, top, ncols, nrows, pGlyph, fill_color, 0, + 0, FXDIB_BLEND_NORMAL, NULL, FALSE, alpha_flag, + pIccTransform)) { + FX_Free(pGlyphAndPos); + return FALSE; + } + continue; + } + FX_BOOL bBGRStripe = text_flags & FXTEXT_BGR_STRIPE; + ncols /= 3; + int x_subpixel = (int)(glyph.m_fOriginX * 3) % 3; + uint8_t* src_buf = pGlyph->GetBuffer(); + int src_pitch = pGlyph->GetPitch(); + int start_col = left; + if (start_col < 0) { + start_col = 0; + } + int end_col = left + ncols; + if (end_col > dest_width) { + end_col = dest_width; + } + if (start_col >= end_col) { + continue; + } + if (bitmap.GetFormat() == FXDIB_Argb) { + for (int row = 0; row < nrows; row++) { + int dest_row = row + top; + if (dest_row < 0 || dest_row >= bitmap.GetHeight()) { + continue; + } + uint8_t* src_scan = src_buf + row * src_pitch + (start_col - left) * 3; + uint8_t* dest_scan = + dest_buf + dest_row * dest_pitch + (start_col << 2); + if (bBGRStripe) { + if (x_subpixel == 0) { + for (int col = start_col; col < end_col; col++) { + int src_alpha = src_scan[2]; + src_alpha = src_alpha * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha)); + src_alpha = src_scan[1]; + src_alpha = src_alpha * a / 255; + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha)); + src_alpha = src_scan[0]; + src_alpha = src_alpha * a / 255; + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha)); + dest_scan[3] = 255; + dest_scan += 4; + src_scan += 3; + } + } else if (x_subpixel == 1) { + int src_alpha = src_scan[1]; + ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha)); + src_alpha = src_scan[0]; + ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha)); + if (start_col > left) { + src_alpha = src_scan[-1]; + ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha)); + } + dest_scan[3] = 255; + dest_scan += 4; + src_scan += 3; + for (int col = start_col + 1; col < end_col - 1; col++) { + int src_alpha = src_scan[1]; + ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha)); + src_alpha = src_scan[0]; + ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha)); + src_alpha = src_scan[-1]; + ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha)); + dest_scan[3] = 255; + dest_scan += 4; + src_scan += 3; + } + } else { + int src_alpha = src_scan[0]; + ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha)); + if (start_col > left) { + src_alpha = src_scan[-1]; + ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha)); + src_alpha = src_scan[-2]; + ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha)); + } + dest_scan[3] = 255; + dest_scan += 4; + src_scan += 3; + for (int col = start_col + 1; col < end_col - 1; col++) { + int src_alpha = src_scan[0]; + ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha)); + src_alpha = src_scan[-1]; + ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha)); + src_alpha = src_scan[-2]; + ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha)); + dest_scan[3] = 255; + dest_scan += 4; + src_scan += 3; + } + } + } else { + if (x_subpixel == 0) { + for (int col = start_col; col < end_col; col++) { + if (bNormal) { + int src_alpha1 = (src_scan[0] + src_scan[1] + src_scan[2]) / 3; + ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a); + src_alpha1 = src_alpha1 * a / 255; + uint8_t back_alpha = dest_scan[3]; + if (back_alpha == 0) { + FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b)); + dest_scan += 4; + src_scan += 3; + continue; + } + if (src_alpha1 == 0) { + dest_scan += 4; + src_scan += 3; + continue; + } + uint8_t dest_alpha = + back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha1 * 255 / dest_alpha; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio)); + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio)); + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio)); + dest_scan += 4; + src_scan += 3; + continue; + } + int src_alpha = src_scan[0]; + ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha)); + src_alpha = src_scan[1]; + ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha)); + src_alpha = src_scan[2]; + ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha)); + dest_scan[3] = 255; + dest_scan += 4; + src_scan += 3; + } + } else if (x_subpixel == 1) { + if (bNormal) { + int src_alpha1 = + start_col > left + ? ((src_scan[-1] + src_scan[0] + src_scan[1]) / 3) + : ((src_scan[0] + src_scan[1]) / 3); + ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a); + src_alpha1 = src_alpha1 * a / 255; + if (src_alpha1 == 0) { + dest_scan += 4; + src_scan += 3; + } else { + uint8_t back_alpha = dest_scan[3]; + if (back_alpha == 0) { + FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b)); + } else { + uint8_t dest_alpha = + back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha1 * 255 / dest_alpha; + dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE( + FX_GAMMA(dest_scan[2]), r, alpha_ratio)); + dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE( + FX_GAMMA(dest_scan[1]), g, alpha_ratio)); + dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE( + FX_GAMMA(dest_scan[0]), b, alpha_ratio)); + } + dest_scan += 4; + src_scan += 3; + } + } else { + if (start_col > left) { + int src_alpha = src_scan[-1]; + ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha)); + } + int src_alpha = src_scan[0]; + ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha)); + src_alpha = src_scan[1]; + ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha)); + dest_scan[3] = 255; + dest_scan += 4; + src_scan += 3; + } + for (int col = start_col + 1; col < end_col; col++) { + if (bNormal) { + int src_alpha1 = (src_scan[-1] + src_scan[0] + src_scan[1]) / 3; + ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a); + src_alpha1 = src_alpha1 * a / 255; + uint8_t back_alpha = dest_scan[3]; + if (back_alpha == 0) { + FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b)); + dest_scan += 4; + src_scan += 3; + continue; + } + if (src_alpha1 == 0) { + dest_scan += 4; + src_scan += 3; + continue; + } + uint8_t dest_alpha = + back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha1 * 255 / dest_alpha; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio)); + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio)); + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio)); + dest_scan += 4; + src_scan += 3; + continue; + } + int src_alpha = src_scan[-1]; + ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha)); + src_alpha = src_scan[0]; + ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha)); + src_alpha = src_scan[1]; + ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha)); + dest_scan[3] = 255; + dest_scan += 4; + src_scan += 3; + } + } else { + if (bNormal) { + int src_alpha1 = + start_col > left + ? ((src_scan[-2] + src_scan[-1] + src_scan[0]) / 3) + : ((src_scan[0]) / 3); + ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a); + src_alpha1 = src_alpha1 * a / 255; + if (src_alpha1 == 0) { + dest_scan += 4; + src_scan += 3; + } else { + uint8_t back_alpha = dest_scan[3]; + if (back_alpha == 0) { + FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b)); + } else { + uint8_t dest_alpha = + back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha1 * 255 / dest_alpha; + dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE( + FX_GAMMA(dest_scan[2]), r, alpha_ratio)); + dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE( + FX_GAMMA(dest_scan[1]), g, alpha_ratio)); + dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE( + FX_GAMMA(dest_scan[0]), b, alpha_ratio)); + } + dest_scan += 4; + src_scan += 3; + } + } else { + if (start_col > left) { + int src_alpha = src_scan[-2]; + ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha)); + src_alpha = src_scan[-1]; + ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha)); + } + int src_alpha = src_scan[0]; + ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha)); + dest_scan[3] = 255; + dest_scan += 4; + src_scan += 3; + } + for (int col = start_col + 1; col < end_col; col++) { + if (bNormal) { + int src_alpha1 = + (src_scan[-2] + src_scan[-1] + src_scan[0]) / 3; + ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a); + src_alpha1 = src_alpha1 * a / 255; + uint8_t back_alpha = dest_scan[3]; + if (back_alpha == 0) { + FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b)); + dest_scan += 4; + src_scan += 3; + continue; + } + if (src_alpha1 == 0) { + dest_scan += 4; + src_scan += 3; + continue; + } + uint8_t dest_alpha = + back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha1 * 255 / dest_alpha; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio)); + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio)); + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio)); + dest_scan += 4; + src_scan += 3; + continue; + } + int src_alpha = src_scan[-2]; + ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha)); + src_alpha = src_scan[-1]; + ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha)); + src_alpha = src_scan[0]; + ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha)); + dest_scan[3] = 255; + dest_scan += 4; + src_scan += 3; + } + } + } + } + } else { + for (int row = 0; row < nrows; row++) { + int dest_row = row + top; + if (dest_row < 0 || dest_row >= bitmap.GetHeight()) { + continue; + } + uint8_t* src_scan = src_buf + row * src_pitch + (start_col - left) * 3; + uint8_t* dest_scan = dest_buf + dest_row * dest_pitch + start_col * Bpp; + if (bBGRStripe) { + if (x_subpixel == 0) { + for (int col = start_col; col < end_col; col++) { + int src_alpha = src_scan[2]; + ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha)); + src_alpha = src_scan[1]; + ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha)); + src_alpha = src_scan[0]; + ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha)); + dest_scan += Bpp; + src_scan += 3; + } + } else if (x_subpixel == 1) { + int src_alpha = src_scan[1]; + ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha)); + src_alpha = src_scan[0]; + ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha)); + if (start_col > left) { + src_alpha = src_scan[-1]; + ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha)); + } + dest_scan += Bpp; + src_scan += 3; + for (int col = start_col + 1; col < end_col - 1; col++) { + int src_alpha = src_scan[1]; + ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha)); + src_alpha = src_scan[0]; + ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha)); + src_alpha = src_scan[-1]; + ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha)); + dest_scan += Bpp; + src_scan += 3; + } + } else { + int src_alpha = src_scan[0]; + ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha)); + if (start_col > left) { + src_alpha = src_scan[-1]; + ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha)); + src_alpha = src_scan[-2]; + ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha)); + } + dest_scan += Bpp; + src_scan += 3; + for (int col = start_col + 1; col < end_col - 1; col++) { + int src_alpha = src_scan[0]; + ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha)); + src_alpha = src_scan[-1]; + ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha)); + src_alpha = src_scan[-2]; + ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha)); + dest_scan += Bpp; + src_scan += 3; + } + } + } else { + if (x_subpixel == 0) { + for (int col = start_col; col < end_col; col++) { + if (bNormal) { + int src_alpha1 = (src_scan[0] + src_scan[1] + src_scan[2]) / 3; + ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a); + src_alpha1 = src_alpha1 * a / 255; + if (src_alpha1 == 0) { + dest_scan += Bpp; + src_scan += 3; + continue; + } + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1)); + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1)); + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1)); + dest_scan += Bpp; + src_scan += 3; + continue; + } + int src_alpha = src_scan[0]; + ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha)); + src_alpha = src_scan[1]; + ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha)); + src_alpha = src_scan[2]; + ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha)); + dest_scan += Bpp; + src_scan += 3; + } + } else if (x_subpixel == 1) { + if (bNormal) { + int src_alpha1 = + start_col > left + ? (src_scan[0] + src_scan[1] + src_scan[-1]) / 3 + : (src_scan[0] + src_scan[1]) / 3; + ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a); + src_alpha1 = src_alpha1 * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1)); + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1)); + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1)); + dest_scan += Bpp; + src_scan += 3; + } else { + if (start_col > left) { + int src_alpha = src_scan[-1]; + ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha)); + } + int src_alpha = src_scan[0]; + ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha)); + src_alpha = src_scan[1]; + ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha)); + dest_scan += Bpp; + src_scan += 3; + } + for (int col = start_col + 1; col < end_col; col++) { + if (bNormal) { + int src_alpha1 = (src_scan[0] + src_scan[1] + src_scan[-1]) / 3; + ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a); + src_alpha1 = src_alpha1 * a / 255; + if (src_alpha1 == 0) { + dest_scan += Bpp; + src_scan += 3; + continue; + } + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1)); + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1)); + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1)); + dest_scan += Bpp; + src_scan += 3; + continue; + } + int src_alpha = src_scan[-1]; + ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha)); + src_alpha = src_scan[0]; + ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha)); + src_alpha = src_scan[1]; + ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha)); + dest_scan += Bpp; + src_scan += 3; + } + } else { + if (bNormal) { + int src_alpha1 = + start_col > left + ? (src_scan[0] + src_scan[-2] + src_scan[-1]) / 3 + : src_scan[0] / 3; + ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a); + src_alpha1 = src_alpha1 * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1)); + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1)); + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1)); + dest_scan += Bpp; + src_scan += 3; + } else { + if (start_col > left) { + int src_alpha = src_scan[-2]; + ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha)); + src_alpha = src_scan[-1]; + ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha)); + } + int src_alpha = src_scan[0]; + ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha)); + dest_scan += Bpp; + src_scan += 3; + } + for (int col = start_col + 1; col < end_col; col++) { + if (bNormal) { + int src_alpha1 = ((int)(src_scan[0]) + (int)(src_scan[-2]) + + (int)(src_scan[-1])) / + 3; + ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a); + src_alpha1 = src_alpha1 * a / 255; + if (src_alpha1 == 0) { + dest_scan += Bpp; + src_scan += 3; + continue; + } + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1)); + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1)); + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1)); + dest_scan += Bpp; + src_scan += 3; + continue; + } + int src_alpha = src_scan[-2]; + ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha)); + src_alpha = src_scan[-1]; + ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha)); + src_alpha = src_scan[0]; + ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a); + src_alpha = src_alpha * a / 255; + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha)); + dest_scan += Bpp; + src_scan += 3; + } + } + } + } + } + } + if (bitmap.IsAlphaMask()) { + SetBitMask(&bitmap, bmp_rect.left, bmp_rect.top, fill_color, alpha_flag, + pIccTransform); + } else { + SetDIBits(&bitmap, bmp_rect.left, bmp_rect.top); + } + FX_Free(pGlyphAndPos); + return TRUE; +} +FX_BOOL CFX_RenderDevice::DrawTextPath(int nChars, + const FXTEXT_CHARPOS* pCharPos, + CFX_Font* pFont, + CFX_FontCache* pCache, + FX_FLOAT font_size, + const CFX_Matrix* pText2User, + const CFX_Matrix* pUser2Device, + const CFX_GraphStateData* pGraphState, + FX_DWORD fill_color, + FX_ARGB stroke_color, + CFX_PathData* pClippingPath, + int nFlag, + int alpha_flag, + void* pIccTransform, + int blend_type) { + if (!pCache) { + pCache = CFX_GEModule::Get()->GetFontCache(); + } + CFX_FaceCache* pFaceCache = pCache->GetCachedFace(pFont); + FX_FONTCACHE_DEFINE(pCache, pFont); + for (int iChar = 0; iChar < nChars; iChar++) { + const FXTEXT_CHARPOS& charpos = pCharPos[iChar]; + CFX_Matrix 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); + const CFX_PathData* pPath = pFaceCache->LoadGlyphPath( + pFont, charpos.m_GlyphIndex, charpos.m_FontCharWidth); + if (!pPath) { + continue; + } + matrix.Concat(*pText2User); + CFX_PathData TransformedPath(*pPath); + TransformedPath.Transform(&matrix); + FX_BOOL bHasAlpha = FXGETFLAG_COLORTYPE(alpha_flag) + ? (FXGETFLAG_ALPHA_FILL(alpha_flag) || + FXGETFLAG_ALPHA_STROKE(alpha_flag)) + : (fill_color || stroke_color); + if (bHasAlpha) { + int fill_mode = nFlag; + if (FXGETFLAG_COLORTYPE(alpha_flag)) { + if (FXGETFLAG_ALPHA_FILL(alpha_flag)) { + fill_mode |= FXFILL_WINDING; + } + } else { + if (fill_color) { + fill_mode |= FXFILL_WINDING; + } + } + fill_mode |= FX_FILL_TEXT_MODE; + if (!DrawPath(&TransformedPath, pUser2Device, pGraphState, fill_color, + stroke_color, fill_mode, alpha_flag, pIccTransform, + blend_type)) { + return FALSE; + } + } + if (pClippingPath) { + pClippingPath->Append(&TransformedPath, pUser2Device); + } + } + return TRUE; +} + +CFX_FontCache::CFX_FontCache() {} + +CFX_FontCache::~CFX_FontCache() { + FreeCache(TRUE); +} + +CFX_FaceCache* CFX_FontCache::GetCachedFace(CFX_Font* pFont) { + FXFT_Face internal_face = pFont->GetFace(); + const bool bExternal = !internal_face; + FXFT_Face face = + bExternal ? (FXFT_Face)pFont->GetSubstFont()->m_ExtHandle : internal_face; + CFX_FTCacheMap& map = bExternal ? m_ExtFaceMap : m_FTFaceMap; + auto it = map.find(face); + if (it != map.end()) { + CFX_CountedFaceCache* counted_face_cache = it->second; + counted_face_cache->m_nCount++; + return counted_face_cache->m_Obj; + } + + CFX_FaceCache* face_cache = new CFX_FaceCache(bExternal ? nullptr : face); + CFX_CountedFaceCache* counted_face_cache = new CFX_CountedFaceCache; + counted_face_cache->m_nCount = 2; + counted_face_cache->m_Obj = face_cache; + map[face] = counted_face_cache; + return face_cache; +} + +void CFX_FontCache::ReleaseCachedFace(CFX_Font* pFont) { + FXFT_Face internal_face = pFont->GetFace(); + const bool bExternal = !internal_face; + FXFT_Face face = + bExternal ? (FXFT_Face)pFont->GetSubstFont()->m_ExtHandle : internal_face; + CFX_FTCacheMap& map = bExternal ? m_ExtFaceMap : m_FTFaceMap; + + auto it = map.find(face); + if (it == map.end()) + return; + + CFX_CountedFaceCache* counted_face_cache = it->second; + if (counted_face_cache->m_nCount > 1) { + counted_face_cache->m_nCount--; + } +} + +void CFX_FontCache::FreeCache(FX_BOOL bRelease) { + for (auto it = m_FTFaceMap.begin(); it != m_FTFaceMap.end();) { + auto curr_it = it++; + CFX_CountedFaceCache* cache = curr_it->second; + if (bRelease || cache->m_nCount < 2) { + delete cache->m_Obj; + delete cache; + m_FTFaceMap.erase(curr_it); + } + } + + for (auto it = m_ExtFaceMap.begin(); it != m_ExtFaceMap.end();) { + auto curr_it = it++; + CFX_CountedFaceCache* cache = curr_it->second; + if (bRelease || cache->m_nCount < 2) { + delete cache->m_Obj; + delete cache; + m_ExtFaceMap.erase(curr_it); + } + } +} + +CFX_FaceCache::CFX_FaceCache(FXFT_Face face) : m_Face(face) {} + +CFX_FaceCache::~CFX_FaceCache() { + for (const auto& pair : m_SizeMap) { + delete pair.second; + } + m_SizeMap.clear(); + for (const auto& pair : m_PathMap) { + delete pair.second; + } + m_PathMap.clear(); +} +#if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_ +void CFX_FaceCache::InitPlatform() {} +#endif +CFX_GlyphBitmap* CFX_FaceCache::LookUpGlyphBitmap( + CFX_Font* pFont, + const CFX_Matrix* pMatrix, + CFX_ByteStringC& FaceGlyphsKey, + FX_DWORD glyph_index, + FX_BOOL bFontStyle, + int dest_width, + int anti_alias) { + CFX_SizeGlyphCache* pSizeCache; + auto it = m_SizeMap.find(FaceGlyphsKey); + if (it == m_SizeMap.end()) { + pSizeCache = new CFX_SizeGlyphCache; + m_SizeMap[FaceGlyphsKey] = pSizeCache; + } else { + pSizeCache = it->second; + } + auto it2 = pSizeCache->m_GlyphMap.find(glyph_index); + if (it2 != pSizeCache->m_GlyphMap.end()) + return it2->second; + + CFX_GlyphBitmap* pGlyphBitmap = RenderGlyph(pFont, glyph_index, bFontStyle, + pMatrix, dest_width, anti_alias); + if (!pGlyphBitmap) + return nullptr; + + pSizeCache->m_GlyphMap[glyph_index] = pGlyphBitmap; + return pGlyphBitmap; +} +const CFX_GlyphBitmap* CFX_FaceCache::LoadGlyphBitmap(CFX_Font* pFont, + FX_DWORD glyph_index, + FX_BOOL bFontStyle, + const CFX_Matrix* pMatrix, + int dest_width, + int anti_alias, + int& text_flags) { + if (glyph_index == (FX_DWORD)-1) { + return NULL; + } + _CFX_UniqueKeyGen keygen; +#if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_ + if (pFont->GetSubstFont()) + keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000), + (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), + dest_width, anti_alias, pFont->GetSubstFont()->m_Weight, + pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical()); + else + keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000), + (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), + dest_width, anti_alias); +#else + if (text_flags & FXTEXT_NO_NATIVETEXT) { + if (pFont->GetSubstFont()) + keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000), + (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), + dest_width, anti_alias, pFont->GetSubstFont()->m_Weight, + pFont->GetSubstFont()->m_ItalicAngle, + pFont->IsVertical()); + else + keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000), + (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), + dest_width, anti_alias); + } else { + if (pFont->GetSubstFont()) + keygen.Generate(10, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000), + (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), + dest_width, anti_alias, pFont->GetSubstFont()->m_Weight, + pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical(), + 3); + else + keygen.Generate(7, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000), + (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), + dest_width, anti_alias, 3); + } +#endif + CFX_ByteStringC FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen); +#if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_ + return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index, + bFontStyle, dest_width, anti_alias); +#else + if (text_flags & FXTEXT_NO_NATIVETEXT) { + return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index, + bFontStyle, dest_width, anti_alias); + } + CFX_GlyphBitmap* pGlyphBitmap; + auto it = m_SizeMap.find(FaceGlyphsKey); + if (it != m_SizeMap.end()) { + CFX_SizeGlyphCache* pSizeCache = it->second; + auto it2 = pSizeCache->m_GlyphMap.find(glyph_index); + if (it2 != pSizeCache->m_GlyphMap.end()) + return it2->second; + + pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix, + dest_width, anti_alias); + if (pGlyphBitmap) { + pSizeCache->m_GlyphMap[glyph_index] = pGlyphBitmap; + return pGlyphBitmap; + } + } else { + pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix, + dest_width, anti_alias); + if (pGlyphBitmap) { + CFX_SizeGlyphCache* pSizeCache = new CFX_SizeGlyphCache; + m_SizeMap[FaceGlyphsKey] = pSizeCache; + pSizeCache->m_GlyphMap[glyph_index] = pGlyphBitmap; + return pGlyphBitmap; + } + } + if (pFont->GetSubstFont()) + keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000), + (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), + dest_width, anti_alias, pFont->GetSubstFont()->m_Weight, + pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical()); + else + keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000), + (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), + dest_width, anti_alias); + CFX_ByteStringC FaceGlyphsKey2(keygen.m_Key, keygen.m_KeyLen); + text_flags |= FXTEXT_NO_NATIVETEXT; + return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey2, glyph_index, + bFontStyle, dest_width, anti_alias); +#endif +} +CFX_SizeGlyphCache::~CFX_SizeGlyphCache() { + for (const auto& pair : m_GlyphMap) { + delete pair.second; + } + m_GlyphMap.clear(); +} +#define CONTRAST_RAMP_STEP 1 +void CFX_Font::AdjustMMParams(int glyph_index, int dest_width, int weight) { + FXFT_MM_Var pMasters = NULL; + FXFT_Get_MM_Var(m_Face, &pMasters); + if (!pMasters) { + return; + } + long coords[2]; + if (weight == 0) { + coords[0] = FXFT_Get_MM_Axis_Def(FXFT_Get_MM_Axis(pMasters, 0)) / 65536; + } else { + coords[0] = weight; + } + if (dest_width == 0) { + coords[1] = FXFT_Get_MM_Axis_Def(FXFT_Get_MM_Axis(pMasters, 1)) / 65536; + } else { + int min_param = FXFT_Get_MM_Axis_Min(FXFT_Get_MM_Axis(pMasters, 1)) / 65536; + int max_param = FXFT_Get_MM_Axis_Max(FXFT_Get_MM_Axis(pMasters, 1)) / 65536; + coords[1] = min_param; + (void)FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords); + (void)FXFT_Load_Glyph( + m_Face, glyph_index, + FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH); + int min_width = FXFT_Get_Glyph_HoriAdvance(m_Face) * 1000 / + FXFT_Get_Face_UnitsPerEM(m_Face); + coords[1] = max_param; + (void)FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords); + (void)FXFT_Load_Glyph( + m_Face, glyph_index, + FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH); + int max_width = FXFT_Get_Glyph_HoriAdvance(m_Face) * 1000 / + FXFT_Get_Face_UnitsPerEM(m_Face); + if (max_width == min_width) { + FXFT_Free(m_Face, pMasters); + return; + } + int param = min_param + + (max_param - min_param) * (dest_width - min_width) / + (max_width - min_width); + coords[1] = param; + } + FXFT_Free(m_Face, pMasters); + FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords); +} +static const size_t ANGLESKEW_ARRAY_SIZE = 30; +static const char g_AngleSkew[ANGLESKEW_ARRAY_SIZE] = { + 0, 2, 3, 5, 7, 9, 11, 12, 14, 16, 18, 19, 21, 23, 25, + 27, 29, 31, 32, 34, 36, 38, 40, 42, 45, 47, 49, 51, 53, 55, +}; +static const size_t WEIGHTPOW_ARRAY_SIZE = 100; +static const uint8_t g_WeightPow[WEIGHTPOW_ARRAY_SIZE] = { + 0, 3, 6, 7, 8, 9, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 35, 36, 36, 37, + 37, 37, 38, 38, 38, 39, 39, 39, 40, 40, 40, 41, 41, 41, 42, 42, 42, + 42, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, + 47, 47, 47, 48, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 50, + 51, 51, 51, 51, 51, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, +}; +static const uint8_t g_WeightPow_11[WEIGHTPOW_ARRAY_SIZE] = { + 0, 4, 7, 8, 9, 10, 12, 13, 15, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 39, 40, 40, 41, + 41, 41, 42, 42, 42, 43, 43, 43, 44, 44, 44, 45, 45, 45, 46, 46, 46, + 46, 43, 47, 47, 48, 48, 48, 48, 45, 50, 50, 50, 46, 51, 51, 51, 52, + 52, 52, 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 55, + 56, 56, 56, 56, 56, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58, +}; +static const uint8_t g_WeightPow_SHIFTJIS[WEIGHTPOW_ARRAY_SIZE] = { + 0, 0, 1, 2, 3, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 21, + 22, 24, 26, 28, 30, 32, 33, 35, 37, 39, 41, 43, 45, 48, 48, 48, 48, + 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 52, 53, + 53, 53, 53, 53, 54, 54, 54, 54, 54, 55, 55, 55, 55, 55, 56, 56, 56, + 56, 56, 56, 57, 57, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58, 58, 58, + 59, 59, 59, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 60, 60, +}; +static void _GammaAdjust(uint8_t* pData, + int nWid, + int nHei, + int src_pitch, + const uint8_t* gammaTable) { + int count = nHei * src_pitch; + for (int i = 0; i < count; i++) { + pData[i] = gammaTable[pData[i]]; + } +} +static void _ContrastAdjust(uint8_t* pDataIn, + uint8_t* pDataOut, + int nWid, + int nHei, + int nSrcRowBytes, + int nDstRowBytes) { + int col, row, temp; + int max = 0, min = 255; + FX_FLOAT rate; + for (row = 0; row < nHei; row++) { + uint8_t* pRow = pDataIn + row * nSrcRowBytes; + for (col = 0; col < nWid; col++) { + temp = *pRow++; + if (temp > max) { + max = temp; + } + if (temp < min) { + min = temp; + } + } + } + temp = max - min; + if (0 == temp || 255 == temp) { + int rowbytes = FXSYS_abs(nSrcRowBytes) > nDstRowBytes + ? nDstRowBytes + : FXSYS_abs(nSrcRowBytes); + for (row = 0; row < nHei; row++) { + FXSYS_memcpy(pDataOut + row * nDstRowBytes, pDataIn + row * nSrcRowBytes, + rowbytes); + } + return; + } + rate = 255.f / temp; + for (row = 0; row < nHei; row++) { + uint8_t* pSrcRow = pDataIn + row * nSrcRowBytes; + uint8_t* pDstRow = pDataOut + row * nDstRowBytes; + for (col = 0; col < nWid; col++) { + temp = (int)((*(pSrcRow++) - min) * rate + 0.5); + if (temp > 255) { + temp = 255; + } else if (temp < 0) { + temp = 0; + } + *pDstRow++ = (uint8_t)temp; + } + } +} +CFX_GlyphBitmap* CFX_FaceCache::RenderGlyph(CFX_Font* pFont, + FX_DWORD glyph_index, + FX_BOOL bFontStyle, + const CFX_Matrix* pMatrix, + int dest_width, + int anti_alias) { + if (!m_Face) { + return NULL; + } + FXFT_Matrix ft_matrix; + ft_matrix.xx = (signed long)(pMatrix->GetA() / 64 * 65536); + ft_matrix.xy = (signed long)(pMatrix->GetC() / 64 * 65536); + ft_matrix.yx = (signed long)(pMatrix->GetB() / 64 * 65536); + ft_matrix.yy = (signed long)(pMatrix->GetD() / 64 * 65536); + FX_BOOL bUseCJKSubFont = FALSE; + const CFX_SubstFont* pSubstFont = pFont->GetSubstFont(); + if (pSubstFont) { + bUseCJKSubFont = pSubstFont->m_bSubstOfCJK && bFontStyle; + int skew = 0; + if (bUseCJKSubFont) { + skew = pSubstFont->m_bItlicCJK ? -15 : 0; + } else { + skew = pSubstFont->m_ItalicAngle; + } + if (skew) { + skew = skew <= -ANGLESKEW_ARRAY_SIZE ? -58 : -g_AngleSkew[-skew]; + if (pFont->IsVertical()) { + ft_matrix.yx += ft_matrix.yy * skew / 100; + } else { + ft_matrix.xy += -ft_matrix.xx * skew / 100; + } + } + if (pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) { + pFont->AdjustMMParams(glyph_index, dest_width, + pFont->GetSubstFont()->m_Weight); + } + } + ScopedFontTransform scoped_transform(m_Face, &ft_matrix); + int load_flags = (m_Face->face_flags & FT_FACE_FLAG_SFNT) + ? FXFT_LOAD_NO_BITMAP + : (FXFT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); + int error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags); + if (error) { + // if an error is returned, try to reload glyphs without hinting. + if (load_flags & FT_LOAD_NO_HINTING || load_flags & FT_LOAD_NO_SCALE) { + return NULL; + } + + load_flags |= FT_LOAD_NO_HINTING; + error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags); + + if (error) { + return NULL; + } + } + int weight = 0; + if (bUseCJKSubFont) { + weight = pSubstFont->m_WeightCJK; + } else { + weight = pSubstFont ? pSubstFont->m_Weight : 0; + } + if (pSubstFont && !(pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) && + weight > 400) { + int index = (weight - 400) / 10; + if (index >= WEIGHTPOW_ARRAY_SIZE) { + return NULL; + } + int level = 0; + if (pSubstFont->m_Charset == FXFONT_SHIFTJIS_CHARSET) { + level = + g_WeightPow_SHIFTJIS[index] * 2 * + (FXSYS_abs((int)(ft_matrix.xx)) + FXSYS_abs((int)(ft_matrix.xy))) / + 36655; + } else { + level = g_WeightPow_11[index] * (FXSYS_abs((int)(ft_matrix.xx)) + + FXSYS_abs((int)(ft_matrix.xy))) / + 36655; + } + FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level); + } + FXFT_Library_SetLcdFilter(CFX_GEModule::Get()->GetFontMgr()->GetFTLibrary(), + FT_LCD_FILTER_DEFAULT); + error = FXFT_Render_Glyph(m_Face, anti_alias); + if (error) { + return NULL; + } + int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(m_Face)); + int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(m_Face)); + if (bmwidth > 2048 || bmheight > 2048) { + return NULL; + } + int dib_width = bmwidth; + CFX_GlyphBitmap* pGlyphBitmap = new CFX_GlyphBitmap; + pGlyphBitmap->m_Bitmap.Create( + dib_width, bmheight, + anti_alias == FXFT_RENDER_MODE_MONO ? FXDIB_1bppMask : FXDIB_8bppMask); + pGlyphBitmap->m_Left = FXFT_Get_Glyph_BitmapLeft(m_Face); + pGlyphBitmap->m_Top = FXFT_Get_Glyph_BitmapTop(m_Face); + int dest_pitch = pGlyphBitmap->m_Bitmap.GetPitch(); + int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(m_Face)); + uint8_t* pDestBuf = pGlyphBitmap->m_Bitmap.GetBuffer(); + uint8_t* pSrcBuf = + (uint8_t*)FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(m_Face)); + if (anti_alias != FXFT_RENDER_MODE_MONO && + FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) == + FXFT_PIXEL_MODE_MONO) { + int bytes = anti_alias == FXFT_RENDER_MODE_LCD ? 3 : 1; + for (int i = 0; i < bmheight; i++) + for (int n = 0; n < bmwidth; n++) { + uint8_t data = + (pSrcBuf[i * src_pitch + n / 8] & (0x80 >> (n % 8))) ? 255 : 0; + for (int b = 0; b < bytes; b++) { + pDestBuf[i * dest_pitch + n * bytes + b] = data; + } + } + } else { + FXSYS_memset(pDestBuf, 0, dest_pitch * bmheight); + if (anti_alias == FXFT_RENDER_MODE_MONO && + FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) == + FXFT_PIXEL_MODE_MONO) { + int rowbytes = + FXSYS_abs(src_pitch) > dest_pitch ? dest_pitch : FXSYS_abs(src_pitch); + for (int row = 0; row < bmheight; row++) { + FXSYS_memcpy(pDestBuf + row * dest_pitch, pSrcBuf + row * src_pitch, + rowbytes); + } + } else { + _ContrastAdjust(pSrcBuf, pDestBuf, bmwidth, bmheight, src_pitch, + dest_pitch); + _GammaAdjust(pDestBuf, bmwidth, bmheight, dest_pitch, + CFX_GEModule::Get()->GetTextGammaTable()); + } + } + return pGlyphBitmap; +} +const CFX_PathData* CFX_FaceCache::LoadGlyphPath(CFX_Font* pFont, + FX_DWORD glyph_index, + int dest_width) { + if (!m_Face || glyph_index == (FX_DWORD)-1) + return nullptr; + + FX_DWORD key = glyph_index; + if (pFont->GetSubstFont()) { + key += (((pFont->GetSubstFont()->m_Weight / 16) << 15) + + ((pFont->GetSubstFont()->m_ItalicAngle / 2) << 21) + + ((dest_width / 16) << 25) + (pFont->IsVertical() << 31)); + } + auto it = m_PathMap.find(key); + if (it != m_PathMap.end()) + return it->second; + + CFX_PathData* pGlyphPath = pFont->LoadGlyphPath(glyph_index, dest_width); + m_PathMap[key] = pGlyphPath; + return pGlyphPath; +} +typedef struct { + FX_BOOL m_bCount; + int m_PointCount; + FX_PATHPOINT* m_pPoints; + int m_CurX; + int m_CurY; + FX_FLOAT m_CoordUnit; +} OUTLINE_PARAMS; +void _Outline_CheckEmptyContour(OUTLINE_PARAMS* param) { + if (param->m_PointCount >= 2 && + param->m_pPoints[param->m_PointCount - 2].m_Flag == FXPT_MOVETO && + param->m_pPoints[param->m_PointCount - 2].m_PointX == + param->m_pPoints[param->m_PointCount - 1].m_PointX && + param->m_pPoints[param->m_PointCount - 2].m_PointY == + param->m_pPoints[param->m_PointCount - 1].m_PointY) { + param->m_PointCount -= 2; + } + if (param->m_PointCount >= 4 && + param->m_pPoints[param->m_PointCount - 4].m_Flag == FXPT_MOVETO && + param->m_pPoints[param->m_PointCount - 3].m_Flag == FXPT_BEZIERTO && + param->m_pPoints[param->m_PointCount - 3].m_PointX == + param->m_pPoints[param->m_PointCount - 4].m_PointX && + param->m_pPoints[param->m_PointCount - 3].m_PointY == + param->m_pPoints[param->m_PointCount - 4].m_PointY && + param->m_pPoints[param->m_PointCount - 2].m_PointX == + param->m_pPoints[param->m_PointCount - 4].m_PointX && + param->m_pPoints[param->m_PointCount - 2].m_PointY == + param->m_pPoints[param->m_PointCount - 4].m_PointY && + param->m_pPoints[param->m_PointCount - 1].m_PointX == + param->m_pPoints[param->m_PointCount - 4].m_PointX && + param->m_pPoints[param->m_PointCount - 1].m_PointY == + param->m_pPoints[param->m_PointCount - 4].m_PointY) { + param->m_PointCount -= 4; + } +} +extern "C" { +static int _Outline_MoveTo(const FXFT_Vector* to, void* user) { + OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user; + if (!param->m_bCount) { + _Outline_CheckEmptyContour(param); + param->m_pPoints[param->m_PointCount].m_PointX = to->x / param->m_CoordUnit; + param->m_pPoints[param->m_PointCount].m_PointY = to->y / param->m_CoordUnit; + param->m_pPoints[param->m_PointCount].m_Flag = FXPT_MOVETO; + param->m_CurX = to->x; + param->m_CurY = to->y; + if (param->m_PointCount) { + param->m_pPoints[param->m_PointCount - 1].m_Flag |= FXPT_CLOSEFIGURE; + } + } + param->m_PointCount++; + return 0; +} +}; +extern "C" { +static int _Outline_LineTo(const FXFT_Vector* to, void* user) { + OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user; + if (!param->m_bCount) { + param->m_pPoints[param->m_PointCount].m_PointX = to->x / param->m_CoordUnit; + param->m_pPoints[param->m_PointCount].m_PointY = to->y / param->m_CoordUnit; + param->m_pPoints[param->m_PointCount].m_Flag = FXPT_LINETO; + param->m_CurX = to->x; + param->m_CurY = to->y; + } + param->m_PointCount++; + return 0; +} +}; +extern "C" { +static int _Outline_ConicTo(const FXFT_Vector* control, + const FXFT_Vector* to, + void* user) { + OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user; + if (!param->m_bCount) { + param->m_pPoints[param->m_PointCount].m_PointX = + (param->m_CurX + (control->x - param->m_CurX) * 2 / 3) / + param->m_CoordUnit; + param->m_pPoints[param->m_PointCount].m_PointY = + (param->m_CurY + (control->y - param->m_CurY) * 2 / 3) / + param->m_CoordUnit; + param->m_pPoints[param->m_PointCount].m_Flag = FXPT_BEZIERTO; + param->m_pPoints[param->m_PointCount + 1].m_PointX = + (control->x + (to->x - control->x) / 3) / param->m_CoordUnit; + param->m_pPoints[param->m_PointCount + 1].m_PointY = + (control->y + (to->y - control->y) / 3) / param->m_CoordUnit; + param->m_pPoints[param->m_PointCount + 1].m_Flag = FXPT_BEZIERTO; + param->m_pPoints[param->m_PointCount + 2].m_PointX = + to->x / param->m_CoordUnit; + param->m_pPoints[param->m_PointCount + 2].m_PointY = + to->y / param->m_CoordUnit; + param->m_pPoints[param->m_PointCount + 2].m_Flag = FXPT_BEZIERTO; + param->m_CurX = to->x; + param->m_CurY = to->y; + } + param->m_PointCount += 3; + return 0; +} +}; +extern "C" { +static int _Outline_CubicTo(const FXFT_Vector* control1, + const FXFT_Vector* control2, + const FXFT_Vector* to, + void* user) { + OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user; + if (!param->m_bCount) { + param->m_pPoints[param->m_PointCount].m_PointX = + control1->x / param->m_CoordUnit; + param->m_pPoints[param->m_PointCount].m_PointY = + control1->y / param->m_CoordUnit; + param->m_pPoints[param->m_PointCount].m_Flag = FXPT_BEZIERTO; + param->m_pPoints[param->m_PointCount + 1].m_PointX = + control2->x / param->m_CoordUnit; + param->m_pPoints[param->m_PointCount + 1].m_PointY = + control2->y / param->m_CoordUnit; + param->m_pPoints[param->m_PointCount + 1].m_Flag = FXPT_BEZIERTO; + param->m_pPoints[param->m_PointCount + 2].m_PointX = + to->x / param->m_CoordUnit; + param->m_pPoints[param->m_PointCount + 2].m_PointY = + to->y / param->m_CoordUnit; + param->m_pPoints[param->m_PointCount + 2].m_Flag = FXPT_BEZIERTO; + param->m_CurX = to->x; + param->m_CurY = to->y; + } + param->m_PointCount += 3; + return 0; +} +}; +CFX_PathData* CFX_Font::LoadGlyphPath(FX_DWORD glyph_index, int dest_width) { + if (!m_Face) { + return NULL; + } + FXFT_Set_Pixel_Sizes(m_Face, 0, 64); + FXFT_Matrix ft_matrix = {65536, 0, 0, 65536}; + if (m_pSubstFont) { + if (m_pSubstFont->m_ItalicAngle) { + int skew = m_pSubstFont->m_ItalicAngle; + skew = skew <= -ANGLESKEW_ARRAY_SIZE ? -58 : -g_AngleSkew[-skew]; + if (m_bVertical) { + ft_matrix.yx += ft_matrix.yy * skew / 100; + } else { + ft_matrix.xy += -ft_matrix.xx * skew / 100; + } + } + if (m_pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) { + AdjustMMParams(glyph_index, dest_width, m_pSubstFont->m_Weight); + } + } + ScopedFontTransform scoped_transform(m_Face, &ft_matrix); + int load_flags = FXFT_LOAD_NO_BITMAP; + if (!(m_Face->face_flags & FT_FACE_FLAG_SFNT) || !FT_IS_TRICKY(m_Face)) { + load_flags |= FT_LOAD_NO_HINTING; + } + int error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags); + if (error) { + return NULL; + } + if (m_pSubstFont && !(m_pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) && + m_pSubstFont->m_Weight > 400) { + int index = (m_pSubstFont->m_Weight - 400) / 10; + if (index >= WEIGHTPOW_ARRAY_SIZE) + index = WEIGHTPOW_ARRAY_SIZE - 1; + int level = 0; + if (m_pSubstFont->m_Charset == FXFONT_SHIFTJIS_CHARSET) { + level = g_WeightPow_SHIFTJIS[index] * 2 * 65536 / 36655; + } else { + level = g_WeightPow[index] * 2; + } + FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level); + } + FXFT_Outline_Funcs funcs; + funcs.move_to = _Outline_MoveTo; + funcs.line_to = _Outline_LineTo; + funcs.conic_to = _Outline_ConicTo; + funcs.cubic_to = _Outline_CubicTo; + funcs.shift = 0; + funcs.delta = 0; + OUTLINE_PARAMS params; + params.m_bCount = TRUE; + params.m_PointCount = 0; + FXFT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face), &funcs, ¶ms); + if (params.m_PointCount == 0) { + return NULL; + } + CFX_PathData* pPath = new CFX_PathData; + pPath->SetPointCount(params.m_PointCount); + params.m_bCount = FALSE; + params.m_PointCount = 0; + params.m_pPoints = pPath->GetPoints(); + params.m_CurX = params.m_CurY = 0; + params.m_CoordUnit = 64 * 64.0; + FXFT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face), &funcs, ¶ms); + _Outline_CheckEmptyContour(¶ms); + pPath->TrimPoints(params.m_PointCount); + if (params.m_PointCount) { + pPath->GetPoints()[params.m_PointCount - 1].m_Flag |= FXPT_CLOSEFIGURE; + } + return pPath; +} +void _CFX_UniqueKeyGen::Generate(int count, ...) { + va_list argList; + va_start(argList, count); + for (int i = 0; i < count; i++) { + int p = va_arg(argList, int); + ((FX_DWORD*)m_Key)[i] = p; + } + va_end(argList); + m_KeyLen = count * sizeof(FX_DWORD); +} diff --git a/core/fxge/ge/fx_text_int.h b/core/fxge/ge/fx_text_int.h new file mode 100644 index 0000000000..d88b2a7cb9 --- /dev/null +++ b/core/fxge/ge/fx_text_int.h @@ -0,0 +1,84 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXGE_GE_FX_TEXT_INT_H_ +#define CORE_FXGE_GE_FX_TEXT_INT_H_ + +#include <map> + +#include "core/include/fxge/fx_font.h" +#include "core/include/fxge/fx_freetype.h" + +struct _CFX_UniqueKeyGen { + void Generate(int count, ...); + FX_CHAR m_Key[128]; + int m_KeyLen; +}; +class CFX_SizeGlyphCache { + public: + CFX_SizeGlyphCache() {} + ~CFX_SizeGlyphCache(); + std::map<FX_DWORD, CFX_GlyphBitmap*> m_GlyphMap; +}; +class CTTFontDesc { + public: + CTTFontDesc() { + m_Type = 0; + m_pFontData = NULL; + m_RefCount = 0; + } + ~CTTFontDesc(); + // ret < 0, releaseface not appropriate for this object. + // ret == 0, object released + // ret > 0, object still alive, other referrers. + int ReleaseFace(FXFT_Face face); + int m_Type; + union { + struct { + FX_BOOL m_bItalic; + FX_BOOL m_bBold; + FXFT_Face m_pFace; + } m_SingleFace; + struct { + FXFT_Face m_pFaces[16]; + } m_TTCFace; + }; + uint8_t* m_pFontData; + int m_RefCount; +}; + +#define CHARSET_FLAG_ANSI 1 +#define CHARSET_FLAG_SYMBOL 2 +#define CHARSET_FLAG_SHIFTJIS 4 +#define CHARSET_FLAG_BIG5 8 +#define CHARSET_FLAG_GB 16 +#define CHARSET_FLAG_KOREAN 32 + +class CFX_FontFaceInfo { + public: + CFX_FontFaceInfo(CFX_ByteString filePath, + CFX_ByteString faceName, + CFX_ByteString fontTables, + FX_DWORD fontOffset, + FX_DWORD fileSize) + : m_FilePath(filePath), + m_FaceName(faceName), + m_FontTables(fontTables), + m_FontOffset(fontOffset), + m_FileSize(fileSize), + m_Styles(0), + m_Charsets(0) {} + + const CFX_ByteString m_FilePath; + const CFX_ByteString m_FaceName; + const CFX_ByteString m_FontTables; + const FX_DWORD m_FontOffset; + const FX_DWORD m_FileSize; + FX_DWORD m_Styles; + FX_DWORD m_Charsets; +}; + +#endif // CORE_FXGE_GE_FX_TEXT_INT_H_ |