diff options
Diffstat (limited to 'core/fxge/apple')
-rw-r--r-- | core/fxge/apple/apple_int.h | 271 | ||||
-rw-r--r-- | core/fxge/apple/fx_apple_platform.cpp | 173 | ||||
-rw-r--r-- | core/fxge/apple/fx_mac_imp.cpp | 113 | ||||
-rw-r--r-- | core/fxge/apple/fx_quartz_device.cpp | 1048 |
4 files changed, 1605 insertions, 0 deletions
diff --git a/core/fxge/apple/apple_int.h b/core/fxge/apple/apple_int.h new file mode 100644 index 0000000000..6fc665e8c3 --- /dev/null +++ b/core/fxge/apple/apple_int.h @@ -0,0 +1,271 @@ +// 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_APPLE_APPLE_INT_H_ +#define CORE_FXGE_APPLE_APPLE_INT_H_ + +#include "core/include/fxcrt/fx_system.h" + +#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ + +#include "core/include/fxge/fx_ge.h" + +#if _FX_OS_ == _FX_MACOSX_ +#include <Carbon/Carbon.h> +#endif + +typedef enum eFXIOSFONTCHARSET { + eFXFontCharsetDEFAULT = 0, + eFXFontCharsetANSI = 1, + eFXFontCharsetSYMBOL = 1 << 1, + eFXFontCharsetSHIFTJIS = 1 << 2, + eFXFontCharsetHANGEUL = 1 << 3, + eFXFontCharsetGB2312 = 1 << 4, + eFXFontCharsetCHINESEBIG5 = 1 << 5, + eFXFontCharsetTHAI = 1 << 6, + eFXFontCharsetEASTEUROPE = 1 << 7, + eFXFontCharsetRUSSIAN = 1 << 8, + eFXFontCharsetGREEK = 1 << 9, + eFXFontCharsetTURKISH = 1 << 10, + eFXFontCharsetHEBREW = 1 << 11, + eFXFontCharsetARABIC = 1 << 12, + eFXFontCharsetBALTIC = 1 << 13, +} FX_IOSCHARSET; +FX_IOSCHARSET FX_GetiOSCharset(int charset); +typedef enum eFXIOSFONTFLAG { + eFXFontFlagBold = 1, + eFXFontFlagItalic = 1 << 1, + eFXFontFlagFixedPitch = 1 << 2, + eFXFontFlagSerif = 1 << 3, + eFXFontFlagScript = 1 << 4, +} FX_IOSFONTFLAG; +typedef struct IOS_FONTDATA_ { + FX_DWORD nHashCode; + const char* psName; + FX_DWORD charsets; + FX_DWORD styles; +} IOS_FONTDATA; +class CQuartz2D { + public: + void* createGraphics(CFX_DIBitmap* bitmap); + void destroyGraphics(void* graphics); + + void* CreateFont(const uint8_t* pFontData, FX_DWORD dwFontSize); + void DestroyFont(void* pFont); + void setGraphicsTextMatrix(void* graphics, CFX_Matrix* matrix); + FX_BOOL drawGraphicsString(void* graphics, + void* font, + FX_FLOAT fontSize, + FX_WORD* glyphIndices, + CGPoint* glyphPositions, + int32_t chars, + FX_ARGB argb, + CFX_Matrix* matrix = NULL); + void saveGraphicsState(void* graphics); + void restoreGraphicsState(void* graphics); +}; +class CApplePlatform { + public: + CApplePlatform() {} + ~CApplePlatform() {} + + CQuartz2D _quartz2d; +}; + +class CFX_QuartzDeviceDriver : public IFX_RenderDeviceDriver { + public: + CFX_QuartzDeviceDriver(CGContextRef context, int32_t deviceClass); + ~CFX_QuartzDeviceDriver() override; + + // IFX_RenderDeviceDriver + int GetDeviceCaps(int caps_id) override; + CFX_Matrix GetCTM() const override; + FX_BOOL IsPSPrintDriver() override { return FALSE; } + FX_BOOL StartRendering() override { return TRUE; } + void EndRendering() override {} + void SaveState() override; + void RestoreState(FX_BOOL bKeepSaved) override; + FX_BOOL SetClip_PathFill(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + int fill_mode) override; + FX_BOOL SetClip_PathStroke(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState) override; + FX_BOOL 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 = 0, + void* pIccTransform = NULL, + int blend_type = FXDIB_BLEND_NORMAL) override; + FX_BOOL SetPixel(int x, + int y, + FX_DWORD color, + int alpha_flag = 0, + void* pIccTransform = NULL) override { + return FALSE; + } + FX_BOOL FillRect(const FX_RECT* pRect, + FX_DWORD fill_color, + int alpha_flag = 0, + void* pIccTransform = NULL, + int blend_type = FXDIB_BLEND_NORMAL) override; + FX_BOOL DrawCosmeticLine(FX_FLOAT x1, + FX_FLOAT y1, + FX_FLOAT x2, + FX_FLOAT y2, + FX_DWORD color, + int alpha_flag = 0, + void* pIccTransform = NULL, + int blend_type = FXDIB_BLEND_NORMAL) override; + FX_BOOL GetClipBox(FX_RECT* pRect) override; + FX_BOOL GetDIBits(CFX_DIBitmap* pBitmap, + int left, + int top, + void* pIccTransform = NULL, + FX_BOOL bDEdge = FALSE) override; + CFX_DIBitmap* GetBackDrop() override { return NULL; } + FX_BOOL SetDIBits(const CFX_DIBSource* pBitmap, + FX_DWORD color, + const FX_RECT* pSrcRect, + int dest_left, + int dest_top, + int blend_type, + int alpha_flag = 0, + void* pIccTransform = NULL) override; + FX_BOOL StretchDIBits(const CFX_DIBSource* pBitmap, + FX_DWORD color, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + const FX_RECT* pClipRect, + FX_DWORD flags, + int alpha_flag = 0, + void* pIccTransform = NULL, + int blend_type = FXDIB_BLEND_NORMAL) override; + FX_BOOL StartDIBits(const CFX_DIBSource* pBitmap, + int bitmap_alpha, + FX_DWORD color, + const CFX_Matrix* pMatrix, + FX_DWORD flags, + void*& handle, + int alpha_flag = 0, + void* pIccTransform = NULL, + int blend_type = FXDIB_BLEND_NORMAL) override { + return FALSE; + } + FX_BOOL ContinueDIBits(void* handle, IFX_Pause* pPause) override { + return FALSE; + } + void CancelDIBits(void* handle) override {} + FX_BOOL DrawDeviceText(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 = 0, + void* pIccTransform = NULL) override; + void* GetPlatformSurface() override { return NULL; } + void ClearDriver() override; + + protected: + void setStrokeInfo(const CFX_GraphStateData* graphState, + FX_ARGB argb, + FX_FLOAT lineWidth); + void setFillInfo(FX_ARGB argb); + void setPathToContext(const CFX_PathData* pathData); + FX_FLOAT getLineWidth(const CFX_GraphStateData* graphState, + CGAffineTransform ctm); + FX_BOOL CG_DrawGlypRun(int nChars, + const FXTEXT_CHARPOS* pCharPos, + CFX_Font* pFont, + CFX_FontCache* pCache, + const CFX_Matrix* pGlyphMatrix, + const CFX_Matrix* pObject2Device, + FX_FLOAT font_size, + FX_DWORD argb, + int alpha_flag, + void* pIccTransform); + void CG_SetImageTransform(int dest_left, + int dest_top, + int dest_width, + int dest_height, + CGRect* rect = NULL); + + protected: + CGContextRef _context; + CGAffineTransform _foxitDevice2User; + CGAffineTransform _user2FoxitDevice; + int32_t m_saveCount; + + int32_t _width; + int32_t _height; + int32_t _bitsPerPixel; + int32_t _deviceClass; + int32_t _renderCaps; + int32_t _horzSize; + int32_t _vertSize; +}; + +class CFX_FontProvider final : public IFX_FileRead { + public: + // IFX_FileRead + void Release() override { delete this; } + FX_FILESIZE GetSize() override { return (FX_FILESIZE)_totalSize; } + FX_BOOL IsEOF() override { return _offSet == _totalSize; } + FX_FILESIZE GetPosition() override { return (FX_FILESIZE)_offSet; } + FX_BOOL ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) override; + size_t ReadBlock(void* buffer, size_t size) override; + + public: + CFX_FontProvider(CGFontRef cgFont); + ~CFX_FontProvider() override; + void InitTableOffset(); + unsigned long Read(unsigned long offset, + unsigned char* buffer, + unsigned long count); + + protected: + uint32_t CalcTableCheckSum(const uint32_t* table, + uint32_t numberOfBytesInTable); + uint32_t CalcTableDataRefCheckSum(CFDataRef dataRef); + + private: + CGFontRef m_cgFont; + UInt32 m_iTableSize; + size_t _offSet; + typedef struct FontHeader { + int32_t fVersion; + uint16_t fNumTables; + uint16_t fSearchRange; + uint16_t fEntrySelector; + uint16_t fRangeShift; + } FontHeader; + typedef struct TableEntry { + uint32_t fTag; + uint32_t fCheckSum; + uint32_t fOffset; + uint32_t fLength; + } TableEntry; + FontHeader _fontHeader; + unsigned char* _tableEntries; + size_t* _tableOffsets; + int _tableCount; + int _totalSize; +}; + +uint32_t FX_GetHashCode(const FX_CHAR* pStr); +FX_DWORD FX_IOSGetMatchFamilyNameHashcode(const FX_CHAR* pFontName); +uint32_t FX_IOSGetFamilyNamesCount(); +const FX_CHAR* FX_IOSGetFamilyName(uint32_t uIndex); +#endif + +#endif // CORE_FXGE_APPLE_APPLE_INT_H_ diff --git a/core/fxge/apple/fx_apple_platform.cpp b/core/fxge/apple/fx_apple_platform.cpp new file mode 100644 index 0000000000..098e9261ae --- /dev/null +++ b/core/fxge/apple/fx_apple_platform.cpp @@ -0,0 +1,173 @@ +// 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" + +#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ + +#include "core/fxge/agg/fx_agg_driver.h" +#include "core/fxge/apple/apple_int.h" +#include "core/fxge/dib/dib_int.h" +#include "core/fxge/ge/fx_text_int.h" +#include "core/include/fxge/fx_freetype.h" +#include "core/include/fxge/fx_ge_apple.h" + +void CFX_AggDeviceDriver::InitPlatform() { + CQuartz2D& quartz2d = + ((CApplePlatform*)CFX_GEModule::Get()->GetPlatformData())->_quartz2d; + m_pPlatformGraphics = quartz2d.createGraphics(m_pBitmap); +} +void CFX_AggDeviceDriver::DestroyPlatform() { + CQuartz2D& quartz2d = + ((CApplePlatform*)CFX_GEModule::Get()->GetPlatformData())->_quartz2d; + if (m_pPlatformGraphics) { + quartz2d.destroyGraphics(m_pPlatformGraphics); + m_pPlatformGraphics = NULL; + } +} +void CFX_FaceCache::InitPlatform() {} +void CFX_FaceCache::DestroyPlatform() {} +CFX_GlyphBitmap* CFX_FaceCache::RenderGlyph_Nativetext( + CFX_Font* pFont, + FX_DWORD glyph_index, + const CFX_Matrix* pMatrix, + int dest_width, + int anti_alias) { + return NULL; +} +static FX_BOOL _CGDrawGlyphRun(CGContextRef pContext, + int nChars, + const FXTEXT_CHARPOS* pCharPos, + CFX_Font* pFont, + CFX_FontCache* pCache, + const CFX_Matrix* pObject2Device, + FX_FLOAT font_size, + FX_DWORD argb, + int alpha_flag, + void* pIccTransform) { + if (nChars == 0) { + return TRUE; + } + CFX_Matrix new_matrix; + FX_BOOL bNegSize = font_size < 0; + if (bNegSize) { + font_size = -font_size; + } + FX_FLOAT ori_x = pCharPos[0].m_OriginX, ori_y = pCharPos[0].m_OriginY; + new_matrix.Transform(ori_x, ori_y); + if (pObject2Device) { + new_matrix.Concat(*pObject2Device); + } + CQuartz2D& quartz2d = + ((CApplePlatform*)CFX_GEModule::Get()->GetPlatformData())->_quartz2d; + if (!pFont->GetPlatformFont()) { + if (pFont->GetPsName() == CFX_WideString::FromLocal("DFHeiStd-W5")) { + return FALSE; + } + pFont->SetPlatformFont( + quartz2d.CreateFont(pFont->GetFontData(), pFont->GetSize())); + if (!pFont->GetPlatformFont()) { + return FALSE; + } + } + CFX_FixedBufGrow<FX_WORD, 32> glyph_indices(nChars); + CFX_FixedBufGrow<CGPoint, 32> glyph_positions(nChars); + for (int i = 0; i < nChars; i++) { + glyph_indices[i] = pCharPos[i].m_ExtGID; + if (bNegSize) { + glyph_positions[i].x = -pCharPos[i].m_OriginX; + } else { + glyph_positions[i].x = pCharPos[i].m_OriginX; + } + glyph_positions[i].y = pCharPos[i].m_OriginY; + } + if (bNegSize) { + new_matrix.a = -new_matrix.a; + } else { + new_matrix.b = -new_matrix.b; + new_matrix.d = -new_matrix.d; + } + quartz2d.setGraphicsTextMatrix(pContext, &new_matrix); + return quartz2d.drawGraphicsString(pContext, pFont->GetPlatformFont(), + font_size, glyph_indices, glyph_positions, + nChars, argb, NULL); +} +static void _DoNothing(void* info, const void* data, size_t size) {} +FX_BOOL CFX_AggDeviceDriver::DrawDeviceText(int nChars, + const FXTEXT_CHARPOS* pCharPos, + CFX_Font* pFont, + CFX_FontCache* pCache, + const CFX_Matrix* pObject2Device, + FX_FLOAT font_size, + FX_DWORD argb, + int alpha_flag, + void* pIccTransform) { + if (!pFont) { + return FALSE; + } + FX_BOOL bBold = pFont->IsBold(); + if (!bBold && pFont->GetSubstFont() && + pFont->GetSubstFont()->m_Weight >= 500 && + pFont->GetSubstFont()->m_Weight <= 600) { + return FALSE; + } + for (int i = 0; i < nChars; i++) { + if (pCharPos[i].m_bGlyphAdjust) { + return FALSE; + } + } + CGContextRef ctx = CGContextRef(m_pPlatformGraphics); + if (NULL == ctx) { + return FALSE; + } + CGContextSaveGState(ctx); + CGContextSetTextDrawingMode(ctx, kCGTextFillClip); + CGRect rect_cg; + CGImageRef pImageCG = NULL; + if (m_pClipRgn) { + rect_cg = + CGRectMake(m_pClipRgn->GetBox().left, m_pClipRgn->GetBox().top, + m_pClipRgn->GetBox().Width(), m_pClipRgn->GetBox().Height()); + const CFX_DIBitmap* pClipMask = m_pClipRgn->GetMask(); + if (pClipMask) { + CGDataProviderRef pClipMaskDataProvider = CGDataProviderCreateWithData( + NULL, pClipMask->GetBuffer(), + pClipMask->GetPitch() * pClipMask->GetHeight(), _DoNothing); + CGFloat decode_f[2] = {255.f, 0.f}; + pImageCG = CGImageMaskCreate( + pClipMask->GetWidth(), pClipMask->GetHeight(), 8, 8, + pClipMask->GetPitch(), pClipMaskDataProvider, decode_f, FALSE); + CGDataProviderRelease(pClipMaskDataProvider); + } + } else { + rect_cg = CGRectMake(0, 0, m_pBitmap->GetWidth(), m_pBitmap->GetHeight()); + } + rect_cg = CGContextConvertRectToDeviceSpace(ctx, rect_cg); + if (pImageCG) { + CGContextClipToMask(ctx, rect_cg, pImageCG); + } else { + CGContextClipToRect(ctx, rect_cg); + } + FX_BOOL ret = + _CGDrawGlyphRun(ctx, nChars, pCharPos, pFont, pCache, pObject2Device, + font_size, argb, alpha_flag, pIccTransform); + if (pImageCG) { + CGImageRelease(pImageCG); + } + CGContextRestoreGState(ctx); + return ret; +} +void CFX_Font::ReleasePlatformResource() { + if (m_pPlatformFont) { + CQuartz2D& quartz2d = + ((CApplePlatform*)CFX_GEModule::Get()->GetPlatformData())->_quartz2d; + quartz2d.DestroyFont(m_pPlatformFont); + m_pPlatformFont = NULL; + } +} + +#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ diff --git a/core/fxge/apple/fx_mac_imp.cpp b/core/fxge/apple/fx_mac_imp.cpp new file mode 100644 index 0000000000..db9f802d64 --- /dev/null +++ b/core/fxge/apple/fx_mac_imp.cpp @@ -0,0 +1,113 @@ +// 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/apple/apple_int.h" +#include "core/include/fxge/fx_ge.h" + +#if _FX_OS_ == _FX_MACOSX_ +static 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"}, +}; +class CFX_MacFontInfo : public CFX_FolderFontInfo { + public: + virtual void* MapFont(int weight, + FX_BOOL bItalic, + int charset, + int pitch_family, + const FX_CHAR* family, + int& iExact); +}; +#define JAPAN_GOTHIC "Hiragino Kaku Gothic Pro W6" +#define JAPAN_MINCHO "Hiragino Mincho Pro W6" +static void GetJapanesePreference(CFX_ByteString& face, + int weight, + int picth_family) { + if (face.Find("Gothic") >= 0) { + face = JAPAN_GOTHIC; + return; + } + if (!(picth_family & FXFONT_FF_ROMAN) && weight > 400) { + face = JAPAN_GOTHIC; + } else { + face = JAPAN_MINCHO; + } +} +void* CFX_MacFontInfo::MapFont(int weight, + FX_BOOL bItalic, + int charset, + int pitch_family, + const FX_CHAR* cstr_face, + int& iExact) { + CFX_ByteString face = cstr_face; + int iBaseFont; + for (iBaseFont = 0; iBaseFont < 12; iBaseFont++) + if (face == CFX_ByteStringC(Base14Substs[iBaseFont].m_pName)) { + face = Base14Substs[iBaseFont].m_pSubstName; + iExact = TRUE; + break; + } + if (iBaseFont < 12) { + return GetFont(face); + } + auto it = m_FontList.find(face); + if (it != m_FontList.end()) + return it->second; + + if (charset == FXFONT_ANSI_CHARSET && (pitch_family & FXFONT_FF_FIXEDPITCH)) { + return GetFont("Courier New"); + } + if (charset == FXFONT_ANSI_CHARSET || charset == FXFONT_SYMBOL_CHARSET) { + return NULL; + } + switch (charset) { + case FXFONT_SHIFTJIS_CHARSET: + GetJapanesePreference(face, weight, pitch_family); + break; + case FXFONT_GB2312_CHARSET: + face = "STSong"; + break; + case FXFONT_HANGEUL_CHARSET: + face = "AppleMyungjo"; + break; + case FXFONT_CHINESEBIG5_CHARSET: + face = "LiSong Pro Light"; + } + it = m_FontList.find(face); + if (it != m_FontList.end()) + return it->second; + + return NULL; +} +IFX_SystemFontInfo* IFX_SystemFontInfo::CreateDefault(const char** pUnused) { + CFX_MacFontInfo* pInfo = new CFX_MacFontInfo; + pInfo->AddPath("~/Library/Fonts"); + pInfo->AddPath("/Library/Fonts"); + pInfo->AddPath("/System/Library/Fonts"); + return pInfo; +} +void CFX_GEModule::InitPlatform() { + m_pPlatformData = new CApplePlatform; + m_pFontMgr->SetSystemFontInfo(IFX_SystemFontInfo::CreateDefault(nullptr)); +} +void CFX_GEModule::DestroyPlatform() { + delete (CApplePlatform*)m_pPlatformData; + m_pPlatformData = NULL; +} +#endif diff --git a/core/fxge/apple/fx_quartz_device.cpp b/core/fxge/apple/fx_quartz_device.cpp new file mode 100644 index 0000000000..c39ee5e795 --- /dev/null +++ b/core/fxge/apple/fx_quartz_device.cpp @@ -0,0 +1,1048 @@ +// 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/dib/dib_int.h" +#include "core/fxge/ge/fx_text_int.h" +#include "core/include/fxcrt/fx_ext.h" +#include "core/include/fxge/fx_freetype.h" +#include "core/include/fxge/fx_ge.h" + +#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ +#include "core/fxge/apple/apple_int.h" +#include "core/include/fxge/fx_ge_apple.h" +#ifndef CGFLOAT_IS_DOUBLE +#error Expected CGFLOAT_IS_DOUBLE to be defined by CoreGraphics headers +#endif + +void* CQuartz2D::createGraphics(CFX_DIBitmap* pBitmap) { + if (!pBitmap) { + return NULL; + } + CGBitmapInfo bmpInfo = kCGBitmapByteOrder32Little; + switch (pBitmap->GetFormat()) { + case FXDIB_Rgb32: + bmpInfo |= kCGImageAlphaNoneSkipFirst; + break; + case FXDIB_Argb: + default: + return NULL; + } + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = CGBitmapContextCreate( + pBitmap->GetBuffer(), pBitmap->GetWidth(), pBitmap->GetHeight(), 8, + pBitmap->GetPitch(), colorSpace, bmpInfo); + CGColorSpaceRelease(colorSpace); + return context; +} +void CQuartz2D::destroyGraphics(void* graphics) { + if (graphics) { + CGContextRelease((CGContextRef)graphics); + } +} +void* CQuartz2D::CreateFont(const uint8_t* pFontData, FX_DWORD dwFontSize) { + CGDataProviderRef pDataProvider = + CGDataProviderCreateWithData(NULL, pFontData, (size_t)dwFontSize, NULL); + if (NULL == pDataProvider) { + return NULL; + } + CGFontRef pCGFont = CGFontCreateWithDataProvider(pDataProvider); + CGDataProviderRelease(pDataProvider); + return pCGFont; +} +void CQuartz2D::DestroyFont(void* pFont) { + CGFontRelease((CGFontRef)pFont); +} +void CQuartz2D::setGraphicsTextMatrix(void* graphics, CFX_Matrix* matrix) { + if (!graphics || !matrix) { + return; + } + CGContextRef context = (CGContextRef)graphics; + CGFloat ty = CGBitmapContextGetHeight(context) - matrix->f; + CGContextSetTextMatrix( + context, CGAffineTransformMake(matrix->a, matrix->b, matrix->c, matrix->d, + matrix->e, ty)); +} +FX_BOOL CQuartz2D::drawGraphicsString(void* graphics, + void* font, + FX_FLOAT fontSize, + FX_WORD* glyphIndices, + CGPoint* glyphPositions, + int32_t charsCount, + FX_ARGB argb, + CFX_Matrix* matrix) { + if (!graphics) { + return FALSE; + } + CGContextRef context = (CGContextRef)graphics; + CGContextSetFont(context, (CGFontRef)font); + CGContextSetFontSize(context, fontSize); + if (matrix) { + CGAffineTransform m = CGContextGetTextMatrix(context); + m = CGAffineTransformConcat( + m, CGAffineTransformMake(matrix->a, matrix->b, matrix->c, matrix->d, + matrix->e, matrix->f)); + CGContextSetTextMatrix(context, m); + } + int32_t a, r, g, b; + ArgbDecode(argb, a, r, g, b); + CGContextSetRGBFillColor(context, r / 255.f, g / 255.f, b / 255.f, a / 255.f); + CGContextSaveGState(context); +#if CGFLOAT_IS_DOUBLE + CGPoint* glyphPositionsCG = new CGPoint[charsCount]; + for (int index = 0; index < charsCount; ++index) { + glyphPositionsCG[index].x = glyphPositions[index].x; + glyphPositionsCG[index].y = glyphPositions[index].y; + } +#else + CGPoint* glyphPositionsCG = (CGPoint*)glyphPositions; +#endif + CGContextShowGlyphsAtPositions(context, (CGGlyph*)glyphIndices, + glyphPositionsCG, charsCount); +#if CGFLOAT_IS_DOUBLE + delete[] glyphPositionsCG; +#endif + CGContextRestoreGState(context); + return TRUE; +} +void CQuartz2D::saveGraphicsState(void* graphics) { + if (graphics) { + CGContextSaveGState((CGContextRef)graphics); + } +} +void CQuartz2D::restoreGraphicsState(void* graphics) { + if (graphics) { + CGContextRestoreGState((CGContextRef)graphics); + } +} +static CGContextRef createContextWithBitmap(CFX_DIBitmap* pBitmap) { + if (!pBitmap || pBitmap->IsCmykImage() || pBitmap->GetBPP() < 32) { + return NULL; + } + CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little; + if (pBitmap->HasAlpha()) { + bitmapInfo |= kCGImageAlphaPremultipliedFirst; + } else { + bitmapInfo |= kCGImageAlphaNoneSkipFirst; + } + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = CGBitmapContextCreate( + pBitmap->GetBuffer(), pBitmap->GetWidth(), pBitmap->GetHeight(), 8, + pBitmap->GetPitch(), colorSpace, bitmapInfo); + CGColorSpaceRelease(colorSpace); + return context; +} +CFX_QuartzDeviceDriver::CFX_QuartzDeviceDriver(CGContextRef context, + int32_t deviceClass) { + m_saveCount = 0; + _context = context; + _deviceClass = deviceClass; + CGContextRetain(_context); + CGRect r = CGContextGetClipBoundingBox(context); + _width = FXSYS_round(r.size.width); + _height = FXSYS_round(r.size.height); + _renderCaps = FXRC_SOFT_CLIP | FXRC_BLEND_MODE | FXRC_ALPHA_PATH | + FXRC_ALPHA_IMAGE | FXRC_BIT_MASK | FXRC_ALPHA_MASK; + if (_deviceClass != FXDC_DISPLAY) { + } else { + CGImageRef image = CGBitmapContextCreateImage(_context); + if (image) { + _renderCaps |= FXRC_GET_BITS; + _width = CGImageGetWidth(image); + _height = CGImageGetHeight(image); + CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(image); + if (kCGImageAlphaPremultipliedFirst == alphaInfo || + kCGImageAlphaPremultipliedLast == alphaInfo || + kCGImageAlphaOnly == alphaInfo) { + _renderCaps |= FXRC_ALPHA_OUTPUT; + } + } + CGImageRelease(image); + } + CGAffineTransform ctm = CGContextGetCTM(_context); + CGContextSaveGState(_context); + m_saveCount++; + if (ctm.d >= 0) { + CGFloat offset_x, offset_y; + offset_x = ctm.tx; + offset_y = ctm.ty; + CGContextTranslateCTM(_context, -offset_x, -offset_y); + CGContextConcatCTM(_context, CGAffineTransformMake(1, 0, 0, -1, offset_x, + _height + offset_y)); + } + _foxitDevice2User = CGAffineTransformIdentity; + _user2FoxitDevice = CGAffineTransformInvert(_foxitDevice2User); +} +CFX_QuartzDeviceDriver::~CFX_QuartzDeviceDriver() { + CGContextRestoreGState(_context); + m_saveCount--; + for (int i = 0; i < m_saveCount; ++i) { + CGContextRestoreGState(_context); + } + if (_context) { + CGContextRelease(_context); + } +} +int CFX_QuartzDeviceDriver::GetDeviceCaps(int capsID) { + switch (capsID) { + case FXDC_DEVICE_CLASS: { + return _deviceClass; + } + case FXDC_PIXEL_WIDTH: { + return _width; + } + case FXDC_PIXEL_HEIGHT: { + return _height; + } + case FXDC_BITS_PIXEL: { + return 32; + } + case FXDC_RENDER_CAPS: { + return _renderCaps; + } + default: { return 0; } + } +} +CFX_Matrix CFX_QuartzDeviceDriver::GetCTM() const { + CGAffineTransform ctm = CGContextGetCTM(_context); + return CFX_Matrix(ctm.a, ctm.b, ctm.c, ctm.d, ctm.tx, ctm.ty); +} +void CFX_QuartzDeviceDriver::SaveState() { + CGContextSaveGState(_context); + m_saveCount++; +} +void CFX_QuartzDeviceDriver::RestoreState(FX_BOOL isKeepSaved) { + CGContextRestoreGState(_context); + if (isKeepSaved) { + CGContextSaveGState(_context); + } else { + m_saveCount--; + } +} +FX_BOOL CFX_QuartzDeviceDriver::SetClip_PathFill(const CFX_PathData* pathData, + const CFX_Matrix* matrix, + int fillMode) { + SaveState(); + CGAffineTransform m = CGAffineTransformIdentity; + if (matrix) { + m = CGAffineTransformMake(matrix->GetA(), matrix->GetB(), matrix->GetC(), + matrix->GetD(), matrix->GetE(), matrix->GetF()); + } + m = CGAffineTransformConcat(m, _foxitDevice2User); + CGContextConcatCTM(_context, m); + setPathToContext(pathData); + RestoreState(FALSE); + if ((fillMode & 3) == FXFILL_WINDING) { + CGContextClip(_context); + } else { + CGContextEOClip(_context); + } + return TRUE; +} +FX_FLOAT CFX_QuartzDeviceDriver::getLineWidth( + const CFX_GraphStateData* graphState, + CGAffineTransform ctm) { + FX_FLOAT lineWidth = graphState->m_LineWidth; + if (graphState->m_LineWidth <= 0.f) { + CGSize size; + size.width = 1; + size.height = 1; + CGSize temp = CGSizeApplyAffineTransform(size, ctm); + CGFloat x = 1 / temp.width; + CGFloat y = 1 / temp.height; + lineWidth = x > y ? x : y; + } + return lineWidth; +} +FX_BOOL CFX_QuartzDeviceDriver::SetClip_PathStroke( + const CFX_PathData* pathData, + const CFX_Matrix* matrix, + const CFX_GraphStateData* graphState) { + SaveState(); + CGAffineTransform m = CGAffineTransformIdentity; + if (matrix) { + m = CGAffineTransformMake(matrix->GetA(), matrix->GetB(), matrix->GetC(), + matrix->GetD(), matrix->GetE(), matrix->GetF()); + } + m = CGAffineTransformConcat(m, _foxitDevice2User); + CGContextConcatCTM(_context, m); + FX_FLOAT lineWidth = getLineWidth(graphState, m); + setStrokeInfo(graphState, 0xFF000000, lineWidth); + setPathToContext(pathData); + CGContextReplacePathWithStrokedPath(_context); + RestoreState(FALSE); + CGContextClip(_context); + return TRUE; +} +static CGBlendMode GetCGBlendMode(int blend_type) { + CGBlendMode mode = kCGBlendModeNormal; + switch (blend_type) { + case FXDIB_BLEND_NORMAL: + mode = kCGBlendModeNormal; + break; + case FXDIB_BLEND_MULTIPLY: + mode = kCGBlendModeMultiply; + break; + case FXDIB_BLEND_SCREEN: + mode = kCGBlendModeScreen; + break; + case FXDIB_BLEND_OVERLAY: + mode = kCGBlendModeOverlay; + break; + case FXDIB_BLEND_DARKEN: + mode = kCGBlendModeDarken; + break; + case FXDIB_BLEND_LIGHTEN: + mode = kCGBlendModeLighten; + break; + case FXDIB_BLEND_COLORDODGE: + mode = kCGBlendModeColorDodge; + break; + case FXDIB_BLEND_COLORBURN: + mode = kCGBlendModeColorBurn; + break; + case FXDIB_BLEND_HARDLIGHT: + mode = kCGBlendModeHardLight; + break; + case FXDIB_BLEND_SOFTLIGHT: + mode = kCGBlendModeSoftLight; + break; + case FXDIB_BLEND_DIFFERENCE: + mode = kCGBlendModeDifference; + break; + case FXDIB_BLEND_EXCLUSION: + mode = kCGBlendModeExclusion; + break; + case FXDIB_BLEND_HUE: + mode = kCGBlendModeHue; + break; + case FXDIB_BLEND_SATURATION: + mode = kCGBlendModeSaturation; + break; + case FXDIB_BLEND_COLOR: + mode = kCGBlendModeColor; + break; + case FXDIB_BLEND_LUMINOSITY: + mode = kCGBlendModeLuminosity; + break; + default: + mode = kCGBlendModeNormal; + break; + } + return mode; +} +FX_BOOL CFX_QuartzDeviceDriver::DrawPath(const CFX_PathData* pathData, + const CFX_Matrix* matrix, + const CFX_GraphStateData* graphState, + FX_DWORD fillArgb, + FX_DWORD strokeArgb, + int fillMode, + int alpha_flag, + void* pIccTransform, + int blend_type) { + SaveState(); + CGBlendMode mode = GetCGBlendMode(blend_type); + if (mode != kCGBlendModeNormal) { + CGContextSetBlendMode(_context, mode); + } + CGAffineTransform m = CGAffineTransformIdentity; + if (matrix) { + m = CGAffineTransformMake(matrix->GetA(), matrix->GetB(), matrix->GetC(), + matrix->GetD(), matrix->GetE(), matrix->GetF()); + } + m = CGAffineTransformConcat(m, _foxitDevice2User); + CGContextConcatCTM(_context, m); + int pathMode = 0; + if (graphState && strokeArgb) { + CGContextSetMiterLimit(_context, graphState->m_MiterLimit); + FX_FLOAT lineWidth = getLineWidth(graphState, m); + setStrokeInfo(graphState, strokeArgb, lineWidth); + pathMode |= 4; + } + if (fillMode && fillArgb) { + setFillInfo(fillArgb); + if ((fillMode & 3) == FXFILL_WINDING) { + pathMode |= 1; + } else if ((fillMode & 3) == FXFILL_ALTERNATE) { + pathMode |= 2; + } + } + setPathToContext(pathData); + if (fillMode & FXFILL_FULLCOVER) { + CGContextSetShouldAntialias(_context, false); + } + if (pathMode == 4) { + CGContextStrokePath(_context); + } else if (pathMode == 1) { + CGContextFillPath(_context); + } else if (pathMode == 2) { + CGContextEOFillPath(_context); + } else if (pathMode == 5) { + CGContextDrawPath(_context, kCGPathFillStroke); + } else if (pathMode == 6) { + CGContextDrawPath(_context, kCGPathEOFillStroke); + } + RestoreState(FALSE); + return TRUE; +} +FX_BOOL CFX_QuartzDeviceDriver::FillRect(const FX_RECT* rect, + FX_ARGB fillArgb, + int alphaFlag, + void* iccTransform, + int blend_type) { + CGBlendMode mode = GetCGBlendMode(blend_type); + if (mode != kCGBlendModeNormal) { + CGContextSetBlendMode(_context, mode); + } + CGRect rect_fx = + CGRectMake(rect->left, rect->top, rect->Width(), rect->Height()); + CGRect rect_usr = CGRectApplyAffineTransform(rect_fx, _foxitDevice2User); + int32_t a, r, g, b; + ArgbDecode(fillArgb, a, r, g, b); + CGContextSetRGBFillColor(_context, r / 255.f, g / 255.f, b / 255.f, + a / 255.f); + CGContextFillRect(_context, rect_usr); + if (mode != kCGBlendModeNormal) { + CGContextSetBlendMode(_context, kCGBlendModeNormal); + } + return TRUE; +} +FX_BOOL CFX_QuartzDeviceDriver::DrawCosmeticLine(FX_FLOAT x1, + FX_FLOAT y1, + FX_FLOAT x2, + FX_FLOAT y2, + FX_DWORD argb, + int alphaFlag, + void* iccTransform, + int blend_type) { + CGBlendMode mode = GetCGBlendMode(blend_type); + if (mode != kCGBlendModeNormal) { + CGContextSetBlendMode(_context, mode); + } + CGPoint pt = + CGPointApplyAffineTransform(CGPointMake(x1, y1), _foxitDevice2User); + x1 = pt.x; + y1 = pt.y; + pt = CGPointApplyAffineTransform(CGPointMake(x2, y2), _foxitDevice2User); + x2 = pt.x; + y2 = pt.y; + int32_t a, r, g, b; + ArgbDecode(argb, a, r, g, b); + CGContextSetRGBStrokeColor(_context, r / 255.f, g / 255.f, b / 255.f, + a / 255.f); + CGContextMoveToPoint(_context, x1, y1); + CGContextAddLineToPoint(_context, x2, y2); + CGContextStrokePath(_context); + if (mode != kCGBlendModeNormal) { + CGContextSetBlendMode(_context, kCGBlendModeNormal); + } + return TRUE; +} +FX_BOOL CFX_QuartzDeviceDriver::GetClipBox(FX_RECT* rect) { + CGRect r = CGContextGetClipBoundingBox(_context); + r = CGRectApplyAffineTransform(r, _user2FoxitDevice); + rect->left = FXSYS_floor(r.origin.x); + rect->top = FXSYS_floor(r.origin.y); + rect->right = FXSYS_ceil(r.origin.x + r.size.width); + rect->bottom = FXSYS_ceil(r.origin.y + r.size.height); + return TRUE; +} +FX_BOOL CFX_QuartzDeviceDriver::GetDIBits(CFX_DIBitmap* bitmap, + int32_t left, + int32_t top, + void* pIccTransform, + FX_BOOL bDEdge) { + if (FXDC_PRINTER == _deviceClass) { + return FALSE; + } + if (bitmap->GetBPP() < 32) { + return FALSE; + } + if (!(_renderCaps | FXRC_GET_BITS)) { + return FALSE; + } + CGPoint pt = CGPointMake(left, top); + pt = CGPointApplyAffineTransform(pt, _foxitDevice2User); + CGAffineTransform ctm = CGContextGetCTM(_context); + pt.x *= FXSYS_fabs(ctm.a); + pt.y *= FXSYS_fabs(ctm.d); + CGImageRef image = CGBitmapContextCreateImage(_context); + if (NULL == image) { + return FALSE; + } + CGFloat width = (CGFloat)bitmap->GetWidth(); + CGFloat height = (CGFloat)bitmap->GetHeight(); + if (width + pt.x > _width) { + width -= (width + pt.x - _width); + } + if (height + pt.y > _height) { + height -= (height + pt.y - _height); + } + CGImageRef subImage = CGImageCreateWithImageInRect( + image, CGRectMake(pt.x, pt.y, width, height)); + CGContextRef context = createContextWithBitmap(bitmap); + CGRect rect = CGContextGetClipBoundingBox(context); + CGContextClearRect(context, rect); + CGContextDrawImage(context, rect, subImage); + CGContextRelease(context); + CGImageRelease(subImage); + CGImageRelease(image); + if (bitmap->HasAlpha()) { + for (int row = 0; row < bitmap->GetHeight(); row++) { + uint8_t* pScanline = (uint8_t*)bitmap->GetScanline(row); + for (int col = 0; col < bitmap->GetWidth(); col++) { + if (pScanline[3] > 0) { + pScanline[0] = (pScanline[0] * 255.f / pScanline[3] + .5f); + pScanline[1] = (pScanline[1] * 255.f / pScanline[3] + .5f); + pScanline[2] = (pScanline[2] * 255.f / pScanline[3] + .5f); + } + pScanline += 4; + } + } + } + return TRUE; +} +FX_BOOL CFX_QuartzDeviceDriver::SetDIBits(const CFX_DIBSource* pBitmap, + FX_ARGB argb, + const FX_RECT* srcRect, + int dest_left, + int dest_top, + int blendType, + int alphaFlag, + void* iccTransform) { + SaveState(); + CGFloat src_left, src_top, src_width, src_height; + if (srcRect) { + src_left = srcRect->left; + src_top = srcRect->top; + src_width = srcRect->Width(); + src_height = srcRect->Height(); + } else { + src_left = src_top = 0; + src_width = pBitmap->GetWidth(); + src_height = pBitmap->GetHeight(); + } + CGAffineTransform ctm = CGContextGetCTM(_context); + CGFloat scale_x = FXSYS_fabs(ctm.a); + CGFloat scale_y = FXSYS_fabs(ctm.d); + src_left /= scale_x; + src_top /= scale_y; + src_width /= scale_x; + src_height /= scale_y; + CGRect rect_fx = CGRectMake(dest_left, dest_top, src_width, src_height); + CGRect rect_usr = CGRectApplyAffineTransform(rect_fx, _foxitDevice2User); + CGContextBeginPath(_context); + CGContextAddRect(_context, rect_usr); + CGContextClip(_context); + rect_usr.size = + CGSizeMake(pBitmap->GetWidth() / scale_x, pBitmap->GetHeight() / scale_y); + rect_usr = CGRectOffset(rect_usr, -src_left, -src_top); + CG_SetImageTransform(dest_left, dest_top, src_width, src_height, &rect_usr); + CFX_DIBitmap* pBitmap1 = NULL; + if (pBitmap->IsAlphaMask()) { + if (pBitmap->GetBuffer()) { + pBitmap1 = (CFX_DIBitmap*)pBitmap; + } else { + pBitmap1 = pBitmap->Clone(); + } + if (NULL == pBitmap1) { + RestoreState(FALSE); + return FALSE; + } + CGDataProviderRef pBitmapProvider = CGDataProviderCreateWithData( + NULL, pBitmap1->GetBuffer(), + pBitmap1->GetPitch() * pBitmap1->GetHeight(), NULL); + CGColorSpaceRef pColorSpace = CGColorSpaceCreateDeviceGray(); + CGBitmapInfo bitmapInfo = kCGImageAlphaNone | kCGBitmapByteOrderDefault; + CGImageRef pImage = CGImageCreate( + pBitmap1->GetWidth(), pBitmap1->GetHeight(), pBitmap1->GetBPP(), + pBitmap1->GetBPP(), pBitmap1->GetPitch(), pColorSpace, bitmapInfo, + pBitmapProvider, NULL, true, kCGRenderingIntentDefault); + CGContextClipToMask(_context, rect_usr, pImage); + CGContextSetRGBFillColor(_context, FXARGB_R(argb) / 255.f, + FXARGB_G(argb) / 255.f, FXARGB_B(argb) / 255.f, + FXARGB_A(argb) / 255.f); + CGContextFillRect(_context, rect_usr); + CGImageRelease(pImage); + CGColorSpaceRelease(pColorSpace); + CGDataProviderRelease(pBitmapProvider); + if (pBitmap1 != pBitmap) { + delete pBitmap1; + } + RestoreState(FALSE); + return TRUE; + } + if (pBitmap->GetBPP() < 32) { + pBitmap1 = pBitmap->CloneConvert(FXDIB_Rgb32); + } else { + if (pBitmap->GetBuffer()) { + pBitmap1 = (CFX_DIBitmap*)pBitmap; + } else { + pBitmap1 = pBitmap->Clone(); + } + } + if (NULL == pBitmap1) { + RestoreState(FALSE); + return FALSE; + } + if (pBitmap1->HasAlpha()) { + if (pBitmap1 == pBitmap) { + pBitmap1 = pBitmap->Clone(); + if (!pBitmap1) { + RestoreState(FALSE); + return FALSE; + } + } + for (int row = 0; row < pBitmap1->GetHeight(); row++) { + uint8_t* pScanline = (uint8_t*)pBitmap1->GetScanline(row); + for (int col = 0; col < pBitmap1->GetWidth(); col++) { + pScanline[0] = (uint8_t)(pScanline[0] * pScanline[3] / 255.f + .5f); + pScanline[1] = (uint8_t)(pScanline[1] * pScanline[3] / 255.f + .5f); + pScanline[2] = (uint8_t)(pScanline[2] * pScanline[3] / 255.f + .5f); + pScanline += 4; + } + } + } + CGContextRef ctx = createContextWithBitmap(pBitmap1); + CGImageRef image = CGBitmapContextCreateImage(ctx); + int blend_mode = blendType; + if (FXDIB_BLEND_HARDLIGHT == blendType) { + blend_mode = kCGBlendModeSoftLight; + } else if (FXDIB_BLEND_SOFTLIGHT == blendType) { + blend_mode = kCGBlendModeHardLight; + } else if (blendType >= FXDIB_BLEND_NONSEPARABLE && + blendType <= FXDIB_BLEND_LUMINOSITY) { + blend_mode = blendType - 9; + } else if (blendType > FXDIB_BLEND_LUMINOSITY || blendType < 0) { + blend_mode = kCGBlendModeNormal; + } + CGContextSetBlendMode(_context, (CGBlendMode)blend_mode); + CGContextDrawImage(_context, rect_usr, image); + CGImageRelease(image); + CGContextRelease(ctx); + if (pBitmap1 != pBitmap) { + delete pBitmap1; + } + RestoreState(FALSE); + return TRUE; +} +FX_BOOL CFX_QuartzDeviceDriver::StretchDIBits(const CFX_DIBSource* pBitmap, + FX_ARGB argb, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + const FX_RECT* clipRect, + FX_DWORD flags, + int alphaFlag, + void* iccTransform, + int blend_type) { + SaveState(); + if (clipRect) { + CGContextBeginPath(_context); + CGRect rect_clip = CGRectMake(clipRect->left, clipRect->top, + clipRect->Width(), clipRect->Height()); + rect_clip = CGRectApplyAffineTransform(rect_clip, _foxitDevice2User); + CGContextAddRect(_context, rect_clip); + CGContextClip(_context); + } + CGRect rect = CGRectMake(dest_left, dest_top, dest_width, dest_height); + rect = CGRectApplyAffineTransform(rect, _foxitDevice2User); + if (FXDIB_BICUBIC_INTERPOL == flags) { + CGContextSetInterpolationQuality(_context, kCGInterpolationHigh); + } else if (FXDIB_DOWNSAMPLE == flags) { + CGContextSetInterpolationQuality(_context, kCGInterpolationNone); + } else { + CGContextSetInterpolationQuality(_context, kCGInterpolationMedium); + } + CG_SetImageTransform(dest_left, dest_top, dest_width, dest_height); + CFX_DIBitmap* pBitmap1 = NULL; + if (pBitmap->IsAlphaMask()) { + if (pBitmap->GetBuffer()) { + pBitmap1 = (CFX_DIBitmap*)pBitmap; + } else { + pBitmap1 = pBitmap->Clone(); + } + if (NULL == pBitmap1) { + RestoreState(FALSE); + return FALSE; + } + CGDataProviderRef pBitmapProvider = CGDataProviderCreateWithData( + NULL, pBitmap1->GetBuffer(), + pBitmap1->GetPitch() * pBitmap1->GetHeight(), NULL); + CGColorSpaceRef pColorSpace = CGColorSpaceCreateDeviceGray(); + CGBitmapInfo bitmapInfo = kCGImageAlphaNone | kCGBitmapByteOrderDefault; + CGImageRef pImage = CGImageCreate( + pBitmap1->GetWidth(), pBitmap1->GetHeight(), pBitmap1->GetBPP(), + pBitmap1->GetBPP(), pBitmap1->GetPitch(), pColorSpace, bitmapInfo, + pBitmapProvider, NULL, true, kCGRenderingIntentDefault); + CGContextClipToMask(_context, rect, pImage); + CGContextSetRGBFillColor(_context, FXARGB_R(argb) / 255.f, + FXARGB_G(argb) / 255.f, FXARGB_B(argb) / 255.f, + FXARGB_A(argb) / 255.f); + CGContextFillRect(_context, rect); + CGImageRelease(pImage); + CGColorSpaceRelease(pColorSpace); + CGDataProviderRelease(pBitmapProvider); + if (pBitmap1 != pBitmap) { + delete pBitmap1; + } + RestoreState(FALSE); + return TRUE; + } + if (pBitmap->GetBPP() < 32) { + pBitmap1 = pBitmap->CloneConvert(FXDIB_Rgb32); + } else { + if (pBitmap->GetBuffer()) { + pBitmap1 = (CFX_DIBitmap*)pBitmap; + } else { + pBitmap1 = pBitmap->Clone(); + } + } + if (NULL == pBitmap1) { + RestoreState(FALSE); + return FALSE; + } + if (pBitmap1->HasAlpha()) { + if (pBitmap1 == pBitmap) { + pBitmap1 = pBitmap->Clone(); + if (!pBitmap1) { + RestoreState(FALSE); + return FALSE; + } + } + for (int row = 0; row < pBitmap1->GetHeight(); row++) { + uint8_t* pScanline = (uint8_t*)pBitmap1->GetScanline(row); + for (int col = 0; col < pBitmap1->GetWidth(); col++) { + pScanline[0] = (uint8_t)(pScanline[0] * pScanline[3] / 255.f + .5f); + pScanline[1] = (uint8_t)(pScanline[1] * pScanline[3] / 255.f + .5f); + pScanline[2] = (uint8_t)(pScanline[2] * pScanline[3] / 255.f + .5f); + pScanline += 4; + } + } + } + CGContextRef ctx = createContextWithBitmap(pBitmap1); + CGImageRef image = CGBitmapContextCreateImage(ctx); + CGContextDrawImage(_context, rect, image); + CGImageRelease(image); + CGContextRelease(ctx); + if (pBitmap1 != pBitmap) { + delete pBitmap1; + } + RestoreState(FALSE); + return TRUE; +} +FX_BOOL CFX_QuartzDeviceDriver::CG_DrawGlypRun(int nChars, + const FXTEXT_CHARPOS* pCharPos, + CFX_Font* pFont, + CFX_FontCache* pCache, + const CFX_Matrix* pGlyphMatrix, + const CFX_Matrix* pObject2Device, + FX_FLOAT font_size, + FX_DWORD argb, + int alpha_flag, + void* pIccTransform) { + if (nChars == 0) { + return TRUE; + } + CQuartz2D& quartz2d = + ((CApplePlatform*)CFX_GEModule::Get()->GetPlatformData())->_quartz2d; + if (!pFont->GetPlatformFont()) { + if (pFont->GetPsName() == CFX_WideString::FromLocal("DFHeiStd-W5")) { + return FALSE; + } + pFont->SetPlatformFont( + quartz2d.CreateFont(pFont->GetFontData(), pFont->GetSize())); + if (!pFont->GetPlatformFont()) { + return FALSE; + } + } + CFX_FixedBufGrow<FX_WORD, 32> glyph_indices(nChars); + CFX_FixedBufGrow<CGPoint, 32> glyph_positions(nChars); + for (int i = 0; i < nChars; i++) { + glyph_indices[i] = pCharPos[i].m_ExtGID; + glyph_positions[i].x = pCharPos[i].m_OriginX; + glyph_positions[i].y = pCharPos[i].m_OriginY; + } + CFX_Matrix text_matrix; + if (pObject2Device) { + text_matrix.Concat(*pObject2Device); + } + CGAffineTransform matrix_cg = + CGAffineTransformMake(text_matrix.a, text_matrix.b, text_matrix.c, + text_matrix.d, text_matrix.e, text_matrix.f); + matrix_cg = CGAffineTransformConcat(matrix_cg, _foxitDevice2User); + CGContextSetTextMatrix(_context, matrix_cg); + CGContextSetFont(_context, (CGFontRef)pFont->GetPlatformFont()); + CGContextSetFontSize(_context, FXSYS_fabs(font_size)); + int32_t a, r, g, b; + ArgbDecode(argb, a, r, g, b); + CGContextSetRGBFillColor(_context, r / 255.f, g / 255.f, b / 255.f, + a / 255.f); + SaveState(); + if (pGlyphMatrix) { + CGPoint origin = CGPointMake(glyph_positions[0].x, glyph_positions[0].y); + origin = CGPointApplyAffineTransform(origin, matrix_cg); + CGContextTranslateCTM(_context, origin.x, origin.y); + CGAffineTransform glyph_matrix = CGAffineTransformMake( + pGlyphMatrix->a, pGlyphMatrix->b, pGlyphMatrix->c, pGlyphMatrix->d, + pGlyphMatrix->e, pGlyphMatrix->f); + if (_foxitDevice2User.d < 0) { + glyph_matrix = CGAffineTransformInvert(glyph_matrix); + } + CGContextConcatCTM(_context, glyph_matrix); + CGContextTranslateCTM(_context, -origin.x, -origin.y); + } + CGContextShowGlyphsAtPositions(_context, (CGGlyph*)glyph_indices, + glyph_positions, nChars); + RestoreState(FALSE); + return TRUE; +} +FX_BOOL CFX_QuartzDeviceDriver::DrawDeviceText(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) { + if (NULL == pFont || NULL == _context) { + return FALSE; + } + FX_BOOL bBold = pFont->IsBold(); + if (!bBold && pFont->GetSubstFont() && + pFont->GetSubstFont()->m_Weight >= 500 && + pFont->GetSubstFont()->m_Weight <= 600) { + return FALSE; + } + SaveState(); + CGContextSetTextDrawingMode(_context, kCGTextFillClip); + FX_BOOL ret = FALSE; + int32_t i = 0; + while (i < nChars) { + if (pCharPos[i].m_bGlyphAdjust || font_size < 0) { + if (i > 0) { + ret = CG_DrawGlypRun(i, pCharPos, pFont, pCache, NULL, pObject2Device, + font_size, color, alpha_flag, pIccTransform); + if (!ret) { + RestoreState(FALSE); + return ret; + } + } + const FXTEXT_CHARPOS* char_pos = pCharPos + i; + CFX_Matrix glphy_matrix; + if (font_size < 0) { + glphy_matrix.Concat(-1, 0, 0, -1, 0, 0); + } + if (char_pos->m_bGlyphAdjust) { + glphy_matrix.Concat( + char_pos->m_AdjustMatrix[0], char_pos->m_AdjustMatrix[1], + char_pos->m_AdjustMatrix[2], char_pos->m_AdjustMatrix[3], 0, 0); + } + ret = CG_DrawGlypRun(1, char_pos, pFont, pCache, &glphy_matrix, + pObject2Device, font_size, color, alpha_flag, + pIccTransform); + if (!ret) { + RestoreState(FALSE); + return ret; + } + i++; + pCharPos += i; + nChars -= i; + i = 0; + } else { + i++; + } + } + if (i > 0) { + ret = CG_DrawGlypRun(i, pCharPos, pFont, pCache, NULL, pObject2Device, + font_size, color, alpha_flag, pIccTransform); + } + RestoreState(FALSE); + return ret; +} +void CFX_QuartzDeviceDriver::setStrokeInfo(const CFX_GraphStateData* graphState, + FX_ARGB argb, + FX_FLOAT lineWidth) { + if (NULL == graphState) { + return; + } + CGContextSetLineWidth(_context, lineWidth); + CGLineCap cap; + switch (graphState->m_LineCap) { + case CFX_GraphStateData::LineCapRound: { + cap = kCGLineCapRound; + break; + } + case CFX_GraphStateData::LineCapSquare: { + cap = kCGLineCapSquare; + break; + } + case CFX_GraphStateData::LineCapButt: + default: { cap = kCGLineCapButt; } + } + CGContextSetLineCap(_context, cap); + CGLineJoin join; + switch (graphState->m_LineJoin) { + case CFX_GraphStateData::LineJoinRound: { + join = kCGLineJoinRound; + break; + } + case CFX_GraphStateData::LineJoinBevel: { + join = kCGLineJoinBevel; + break; + } + case CFX_GraphStateData::LineJoinMiter: + default: { join = kCGLineJoinMiter; } + } + CGContextSetLineJoin(_context, join); + if (graphState->m_DashCount) { +#if CGFLOAT_IS_DOUBLE + CGFloat* dashArray = new CGFloat[graphState->m_DashCount]; + for (int index = 0; index < graphState->m_DashCount; ++index) { + dashArray[index] = graphState->m_DashArray[index]; + } +#else + CGFloat* dashArray = (CGFloat*)graphState->m_DashArray; +#endif + CGContextSetLineDash(_context, graphState->m_DashPhase, dashArray, + graphState->m_DashCount); +#if CGFLOAT_IS_DOUBLE + delete[] dashArray; +#endif + } + int32_t a, r, g, b; + ArgbDecode(argb, a, r, g, b); + CGContextSetRGBStrokeColor(_context, r / 255.f, g / 255.f, b / 255.f, + a / 255.f); +} +void CFX_QuartzDeviceDriver::setFillInfo(FX_ARGB argb) { + int32_t a, r, g, b; + ArgbDecode(argb, a, r, g, b); + CGContextSetRGBFillColor(_context, r / 255.f, g / 255.f, b / 255.f, + a / 255.f); +} +void CFX_QuartzDeviceDriver::setPathToContext(const CFX_PathData* pathData) { + int32_t count = pathData->GetPointCount(); + FX_PATHPOINT* points = pathData->GetPoints(); + CGContextBeginPath(_context); + for (int32_t i = 0; i < count; i++) { + switch (points[i].m_Flag & FXPT_TYPE) { + case FXPT_MOVETO: + CGContextMoveToPoint(_context, points[i].m_PointX, points[i].m_PointY); + break; + case FXPT_LINETO: + CGContextAddLineToPoint(_context, points[i].m_PointX, + points[i].m_PointY); + break; + case FXPT_BEZIERTO: { + CGContextAddCurveToPoint(_context, points[i].m_PointX, + points[i].m_PointY, points[i + 1].m_PointX, + points[i + 1].m_PointY, points[i + 2].m_PointX, + points[i + 2].m_PointY); + i += 2; + } + } + if (points[i].m_Flag & FXPT_CLOSEFIGURE) { + CGContextClosePath(_context); + } + } +} +void CFX_QuartzDeviceDriver::CG_SetImageTransform(int dest_left, + int dest_top, + int dest_width, + int dest_height, + CGRect* rect) { + int flip_y = _foxitDevice2User.d * dest_height < 0 ? 1 : -1; + int flip_x = _foxitDevice2User.a * dest_width > 0 ? 1 : -1; + if (flip_y < 0 || flip_x < 0) { + if (dest_height < 0) { + dest_height = -dest_height; + dest_top -= dest_height; + } + CGRect rt = CGRectApplyAffineTransform( + CGRectMake(dest_left, dest_top, dest_width, dest_height), + _foxitDevice2User); + CGFloat offset_x = (rt.origin.x) + rt.size.width / 2.f, + offset_y = (rt.origin.y) + rt.size.height / 2.f; + CGAffineTransform transform = CGAffineTransformIdentity; + transform = CGAffineTransformConcat( + transform, CGAffineTransformMake(1, 0, 0, 1, -offset_x, -offset_y)); + transform = CGAffineTransformConcat( + transform, CGAffineTransformMake(flip_x, 0, 0, flip_y, 0, 0)); + transform = CGAffineTransformConcat( + transform, CGAffineTransformMake(1, 0, 0, 1, offset_x, offset_y)); + CGContextConcatCTM(_context, transform); + if (rect) { + *rect = CGRectApplyAffineTransform(*rect, transform); + } + } +} +void CFX_QuartzDeviceDriver::ClearDriver() { + if (NULL == _context) { + return; + } + for (int i = 0; i < m_saveCount; ++i) { + CGContextRestoreGState(_context); + } + m_saveCount = 0; + if (_context) { + CGContextRelease(_context); + } +} +CFX_QuartzDevice::CFX_QuartzDevice() { + m_bOwnedBitmap = FALSE; + m_pContext = NULL; +} +CFX_QuartzDevice::~CFX_QuartzDevice() { + if (m_pContext) { + CGContextRelease(m_pContext); + } + if (m_bOwnedBitmap) { + delete GetBitmap(); + } +} +CGContextRef CFX_QuartzDevice::GetContext() { + return m_pContext; +} +FX_BOOL CFX_QuartzDevice::Attach(CGContextRef context, int32_t nDeviceClass) { + if (m_pContext) { + CGContextRelease(m_pContext); + } + m_pContext = context; + CGContextRetain(m_pContext); + IFX_RenderDeviceDriver* pDriver = + new CFX_QuartzDeviceDriver(m_pContext, nDeviceClass); + SetDeviceDriver(pDriver); + return TRUE; +} +FX_BOOL CFX_QuartzDevice::Attach(CFX_DIBitmap* pBitmap) { + SetBitmap(pBitmap); + m_pContext = createContextWithBitmap(pBitmap); + if (NULL == m_pContext) { + return FALSE; + } + IFX_RenderDeviceDriver* pDriver = + new CFX_QuartzDeviceDriver(m_pContext, FXDC_DISPLAY); + SetDeviceDriver(pDriver); + return TRUE; +} +FX_BOOL CFX_QuartzDevice::Create(int32_t width, + int32_t height, + FXDIB_Format format) { + if ((uint8_t)format < 32) { + return FALSE; + } + CFX_DIBitmap* pBitmap = new CFX_DIBitmap; + if (!pBitmap->Create(width, height, format)) { + delete pBitmap; + return FALSE; + } + m_bOwnedBitmap = TRUE; + return Attach(pBitmap); +} +#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ |