1// Copyright 2014 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "../../../include/fxcrt/fx_ext.h"
8#include "../../../include/fxge/fx_ge.h"
9#if _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_
10#include "apple_int.h"
11#include "../../../include/fxge/fx_ge_apple.h"
12#include "../agg/include/fxfx_agg_clip_liang_barsky.h"
13#include "../ge/text_int.h"
14#include "../dib/dib_int.h"
15#include "../agg/include/fx_agg_driver.h"
16#include "../../../include/fxge/fx_freetype.h"
17#if (_FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_ && (!defined(_FPDFAPI_MINI_)))
18void CFX_AggDeviceDriver::InitPlatform()
19{
20    CQuartz2D & quartz2d = ((CApplePlatform *) CFX_GEModule::Get()->GetPlatformData())->_quartz2d;
21    m_pPlatformGraphics = quartz2d.createGraphics(m_pBitmap);
22}
23void CFX_AggDeviceDriver::DestroyPlatform()
24{
25    CQuartz2D & quartz2d = ((CApplePlatform *) CFX_GEModule::Get()->GetPlatformData())->_quartz2d;
26    if (m_pPlatformGraphics) {
27        quartz2d.destroyGraphics(m_pPlatformGraphics);
28        m_pPlatformGraphics = NULL;
29    }
30}
31void CFX_FaceCache::InitPlatform() {}
32void CFX_FaceCache::DestroyPlatform() {}
33CFX_GlyphBitmap* CFX_FaceCache::RenderGlyph_Nativetext(CFX_Font *				pFont,
34        FX_DWORD					glyph_index,
35        const CFX_AffineMatrix *	pMatrix,
36        int						dest_width,
37        int						anti_alias)
38{
39    return NULL;
40}
41static FX_BOOL _CGDrawGlyphRun(CGContextRef               pContext,
42                               int                        nChars,
43                               const FXTEXT_CHARPOS*      pCharPos,
44                               CFX_Font*                  pFont,
45                               CFX_FontCache*             pCache,
46                               const CFX_AffineMatrix*    pObject2Device,
47                               FX_FLOAT                   font_size,
48                               FX_DWORD                   argb,
49                               int                        alpha_flag,
50                               void*                      pIccTransform)
51{
52    if (nChars == 0) {
53        return TRUE;
54    }
55    CFX_AffineMatrix new_matrix;
56    FX_BOOL bNegSize = font_size < 0;
57    if (bNegSize) {
58        font_size = -font_size;
59    }
60    FX_FLOAT ori_x = pCharPos[0].m_OriginX, ori_y = pCharPos[0].m_OriginY;
61    new_matrix.Transform(ori_x, ori_y);
62    if (pObject2Device) {
63        new_matrix.Concat(*pObject2Device);
64    }
65    CQuartz2D& quartz2d = ((CApplePlatform *) CFX_GEModule::Get()->GetPlatformData())->_quartz2d;
66    if (!pFont->m_pPlatformFont) {
67        if (pFont->GetPsName() == CFX_WideString::FromLocal("DFHeiStd-W5")) {
68            return FALSE;
69        }
70        pFont->m_pPlatformFont = quartz2d.CreateFont(pFont->m_pFontData, pFont->m_dwSize);
71        if (NULL == pFont->m_pPlatformFont) {
72            return FALSE;
73        }
74    }
75    CFX_FixedBufGrow<FX_WORD, 32> glyph_indices(nChars);
76    CFX_FixedBufGrow<CGPoint, 32> glyph_positions(nChars);
77    for (int i = 0; i < nChars; i++ ) {
78        glyph_indices[i] = pCharPos[i].m_ExtGID;
79        if (bNegSize) {
80            glyph_positions[i].x = -pCharPos[i].m_OriginX;
81        } else {
82            glyph_positions[i].x = pCharPos[i].m_OriginX;
83        }
84        glyph_positions[i].y = pCharPos[i].m_OriginY;
85    }
86    if (bNegSize) {
87        new_matrix.a = -new_matrix.a;
88    } else {
89        new_matrix.b = -new_matrix.b;
90        new_matrix.d = -new_matrix.d;
91    }
92    quartz2d.setGraphicsTextMatrix(pContext, &new_matrix);
93    return quartz2d.drawGraphicsString(pContext,
94                                       pFont->m_pPlatformFont,
95                                       font_size,
96                                       glyph_indices,
97                                       glyph_positions,
98                                       nChars,
99                                       argb,
100                                       NULL);
101}
102static void _DoNothing(void *info, const void *data, size_t size) {}
103FX_BOOL CFX_AggDeviceDriver::DrawDeviceText(int						 nChars,
104        const FXTEXT_CHARPOS *	 pCharPos,
105        CFX_Font *				 pFont,
106        CFX_FontCache *			 pCache,
107        const CFX_AffineMatrix * pObject2Device,
108        FX_FLOAT				 font_size,
109        FX_DWORD				 argb,
110        int alpha_flag, void* pIccTransform)
111{
112    if (!pFont) {
113        return FALSE;
114    }
115    FX_BOOL bBold = pFont->IsBold();
116    if (!bBold && pFont->GetSubstFont() &&
117            pFont->GetSubstFont()->m_Weight >= 500 &&
118            pFont->GetSubstFont()->m_Weight <= 600) {
119        return FALSE;
120    }
121    for (int i = 0; i < nChars; i ++) {
122        if (pCharPos[i].m_bGlyphAdjust) {
123            return FALSE;
124        }
125    }
126    CGContextRef ctx = CGContextRef(m_pPlatformGraphics);
127    if (NULL == ctx) {
128        return FALSE;
129    }
130    CGContextSaveGState(ctx);
131    CGContextSetTextDrawingMode(ctx, kCGTextFillClip);
132    CGRect rect_cg;
133    CGImageRef pImageCG = NULL;
134    if (m_pClipRgn) {
135        rect_cg = CGRectMake(m_pClipRgn->GetBox().left, m_pClipRgn->GetBox().top, m_pClipRgn->GetBox().Width(), m_pClipRgn->GetBox().Height());
136        const CFX_DIBitmap*	pClipMask = m_pClipRgn->GetMask();
137        if (pClipMask) {
138            CGDataProviderRef pClipMaskDataProvider = CGDataProviderCreateWithData(NULL,
139                    pClipMask->GetBuffer(),
140                    pClipMask->GetPitch() * pClipMask->GetHeight(),
141                    _DoNothing);
142            CGFloat decode_f[2] = {255.f, 0.f};
143            pImageCG = CGImageMaskCreate(pClipMask->GetWidth(), pClipMask->GetHeight(),
144                                         8, 8, pClipMask->GetPitch(), pClipMaskDataProvider,
145                                         decode_f, FALSE);
146            CGDataProviderRelease(pClipMaskDataProvider);
147        }
148    } else {
149        rect_cg = CGRectMake(0, 0, m_pBitmap->GetWidth(), m_pBitmap->GetHeight());
150    }
151    rect_cg = CGContextConvertRectToDeviceSpace(ctx, rect_cg);
152    if (pImageCG) {
153        CGContextClipToMask(ctx, rect_cg, pImageCG);
154    } else {
155        CGContextClipToRect(ctx, rect_cg);
156    }
157    FX_BOOL ret = _CGDrawGlyphRun(ctx, nChars, pCharPos, pFont, pCache, pObject2Device, font_size, argb, alpha_flag, pIccTransform);
158    if (pImageCG) {
159        CGImageRelease(pImageCG);
160    }
161    CGContextRestoreGState(ctx);
162    return ret;
163}
164void CFX_Font::ReleasePlatformResource()
165{
166    if (m_pPlatformFont) {
167        CQuartz2D & quartz2d = ((CApplePlatform *) CFX_GEModule::Get()->GetPlatformData())->_quartz2d;
168        quartz2d.DestroyFont(m_pPlatformFont);
169        m_pPlatformFont = NULL;
170    }
171}
172#endif
173#endif
174