summaryrefslogtreecommitdiff
path: root/core/fxge/apple
diff options
context:
space:
mode:
Diffstat (limited to 'core/fxge/apple')
-rw-r--r--core/fxge/apple/apple_int.h271
-rw-r--r--core/fxge/apple/fx_apple_platform.cpp173
-rw-r--r--core/fxge/apple/fx_mac_imp.cpp113
-rw-r--r--core/fxge/apple/fx_quartz_device.cpp1048
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_