diff options
Diffstat (limited to 'core/src/fxge/apple/fx_quartz_device.cpp')
-rw-r--r-- | core/src/fxge/apple/fx_quartz_device.cpp | 2276 |
1 files changed, 1138 insertions, 1138 deletions
diff --git a/core/src/fxge/apple/fx_quartz_device.cpp b/core/src/fxge/apple/fx_quartz_device.cpp index bef45163f7..7cb94f1093 100644 --- a/core/src/fxge/apple/fx_quartz_device.cpp +++ b/core/src/fxge/apple/fx_quartz_device.cpp @@ -1,1138 +1,1138 @@ -// 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 "../../../include/fxcrt/fx_ext.h"
-#include "../../../include/fxge/fx_ge.h"
-#include "../agg/include/fxfx_agg_clip_liang_barsky.h"
-#include "../ge/text_int.h"
-#include "../dib/dib_int.h"
-#include "../agg/include/fx_agg_driver.h"
-#include "../../../include/fxge/fx_freetype.h"
-#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
-#include "apple_int.h"
-#include "../../../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(FX_LPCBYTE 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_AffineMatrix* 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,
- FX_INT32 charsCount,
- FX_ARGB argb,
- CFX_AffineMatrix* 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);
- }
- FX_INT32 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];
- if (!glyphPositionsCG) {
- return FALSE;
- }
- 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, FX_INT32 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_AffineMatrix* 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_AffineMatrix* 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_AffineMatrix* 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);
- FX_INT32 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;
- FX_INT32 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,
- FX_INT32 left,
- FX_INT32 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 ++) {
- FX_LPBYTE pScanline = (FX_LPBYTE)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 ++) {
- FX_LPBYTE pScanline = (FX_LPBYTE)pBitmap1->GetScanline(row);
- for (int col = 0; col < pBitmap1->GetWidth(); col ++) {
- pScanline[0] = (FX_BYTE)(pScanline[0] * pScanline[3] / 255.f + .5f);
- pScanline[1] = (FX_BYTE)(pScanline[1] * pScanline[3] / 255.f + .5f);
- pScanline[2] = (FX_BYTE)(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 ++) {
- FX_LPBYTE pScanline = (FX_LPBYTE)pBitmap1->GetScanline(row);
- for (int col = 0; col < pBitmap1->GetWidth(); col ++) {
- pScanline[0] = (FX_BYTE)(pScanline[0] * pScanline[3] / 255.f + .5f);
- pScanline[1] = (FX_BYTE)(pScanline[1] * pScanline[3] / 255.f + .5f);
- pScanline[2] = (FX_BYTE)(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_AffineMatrix* pGlyphMatrix,
- const CFX_AffineMatrix* 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->m_pPlatformFont) {
- if (pFont->GetPsName() == CFX_WideString::FromLocal("DFHeiStd-W5")) {
- return FALSE;
- }
- pFont->m_pPlatformFont = quartz2d.CreateFont(pFont->m_pFontData, pFont->m_dwSize);
- if (NULL == pFont->m_pPlatformFont) {
- 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_AffineMatrix 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->m_pPlatformFont);
- CGContextSetFontSize(_context, FXSYS_fabs(font_size));
- FX_INT32 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) {
- CGAffineTransform ctm = CGContextGetCTM(_context);
- 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_AffineMatrix* 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;
- FX_INT32 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_AffineMatrix 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];
- if (!dashArray) {
- return;
- }
- 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
- }
- FX_INT32 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)
-{
- FX_INT32 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)
-{
- FX_INT32 count = pathData->GetPointCount();
- FX_PATHPOINT* points = pathData->GetPoints();
- CGContextBeginPath(_context);
- for (FX_INT32 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 (GetBitmap() && m_bOwnedBitmap) {
- delete GetBitmap();
- }
-}
-CGContextRef CFX_QuartzDevice::GetContext()
-{
- return m_pContext;
-}
-FX_BOOL CFX_QuartzDevice::Attach(CGContextRef context, FX_INT32 nDeviceClass)
-{
- if (m_pContext) {
- CGContextRelease(m_pContext);
- }
- m_pContext = context;
- CGContextRetain(m_pContext);
- IFX_RenderDeviceDriver* pDriver = FX_NEW CFX_QuartzDeviceDriver(m_pContext, nDeviceClass);
- if (!pDriver) {
- return FALSE;
- }
- 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 = FX_NEW CFX_QuartzDeviceDriver(m_pContext, FXDC_DISPLAY);
- if (!pDriver) {
- return FALSE;
- }
- SetDeviceDriver(pDriver);
- return TRUE;
-}
-FX_BOOL CFX_QuartzDevice::Create(FX_INT32 width, FX_INT32 height, FXDIB_Format format)
-{
- if ((FX_BYTE)format < 32) {
- return FALSE;
- }
- CFX_DIBitmap* pBitmap = FX_NEW CFX_DIBitmap;
- if (!pBitmap) {
- return FALSE;
- }
- if (!pBitmap->Create(width, height, format)) {
- delete pBitmap;
- return FALSE;
- }
- m_bOwnedBitmap = TRUE;
- return Attach(pBitmap);
-}
-#endif
+// 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 "../../../include/fxcrt/fx_ext.h" +#include "../../../include/fxge/fx_ge.h" +#include "../agg/include/fxfx_agg_clip_liang_barsky.h" +#include "../ge/text_int.h" +#include "../dib/dib_int.h" +#include "../agg/include/fx_agg_driver.h" +#include "../../../include/fxge/fx_freetype.h" +#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ +#include "apple_int.h" +#include "../../../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(FX_LPCBYTE 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_AffineMatrix* 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, + FX_INT32 charsCount, + FX_ARGB argb, + CFX_AffineMatrix* 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); + } + FX_INT32 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]; + if (!glyphPositionsCG) { + return FALSE; + } + 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, FX_INT32 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_AffineMatrix* 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_AffineMatrix* 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_AffineMatrix* 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); + FX_INT32 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; + FX_INT32 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, + FX_INT32 left, + FX_INT32 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 ++) { + FX_LPBYTE pScanline = (FX_LPBYTE)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 ++) { + FX_LPBYTE pScanline = (FX_LPBYTE)pBitmap1->GetScanline(row); + for (int col = 0; col < pBitmap1->GetWidth(); col ++) { + pScanline[0] = (FX_BYTE)(pScanline[0] * pScanline[3] / 255.f + .5f); + pScanline[1] = (FX_BYTE)(pScanline[1] * pScanline[3] / 255.f + .5f); + pScanline[2] = (FX_BYTE)(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 ++) { + FX_LPBYTE pScanline = (FX_LPBYTE)pBitmap1->GetScanline(row); + for (int col = 0; col < pBitmap1->GetWidth(); col ++) { + pScanline[0] = (FX_BYTE)(pScanline[0] * pScanline[3] / 255.f + .5f); + pScanline[1] = (FX_BYTE)(pScanline[1] * pScanline[3] / 255.f + .5f); + pScanline[2] = (FX_BYTE)(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_AffineMatrix* pGlyphMatrix, + const CFX_AffineMatrix* 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->m_pPlatformFont) { + if (pFont->GetPsName() == CFX_WideString::FromLocal("DFHeiStd-W5")) { + return FALSE; + } + pFont->m_pPlatformFont = quartz2d.CreateFont(pFont->m_pFontData, pFont->m_dwSize); + if (NULL == pFont->m_pPlatformFont) { + 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_AffineMatrix 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->m_pPlatformFont); + CGContextSetFontSize(_context, FXSYS_fabs(font_size)); + FX_INT32 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) { + CGAffineTransform ctm = CGContextGetCTM(_context); + 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_AffineMatrix* 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; + FX_INT32 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_AffineMatrix 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]; + if (!dashArray) { + return; + } + 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 + } + FX_INT32 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) +{ + FX_INT32 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) +{ + FX_INT32 count = pathData->GetPointCount(); + FX_PATHPOINT* points = pathData->GetPoints(); + CGContextBeginPath(_context); + for (FX_INT32 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 (GetBitmap() && m_bOwnedBitmap) { + delete GetBitmap(); + } +} +CGContextRef CFX_QuartzDevice::GetContext() +{ + return m_pContext; +} +FX_BOOL CFX_QuartzDevice::Attach(CGContextRef context, FX_INT32 nDeviceClass) +{ + if (m_pContext) { + CGContextRelease(m_pContext); + } + m_pContext = context; + CGContextRetain(m_pContext); + IFX_RenderDeviceDriver* pDriver = FX_NEW CFX_QuartzDeviceDriver(m_pContext, nDeviceClass); + if (!pDriver) { + return FALSE; + } + 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 = FX_NEW CFX_QuartzDeviceDriver(m_pContext, FXDC_DISPLAY); + if (!pDriver) { + return FALSE; + } + SetDeviceDriver(pDriver); + return TRUE; +} +FX_BOOL CFX_QuartzDevice::Create(FX_INT32 width, FX_INT32 height, FXDIB_Format format) +{ + if ((FX_BYTE)format < 32) { + return FALSE; + } + CFX_DIBitmap* pBitmap = FX_NEW CFX_DIBitmap; + if (!pBitmap) { + return FALSE; + } + if (!pBitmap->Create(width, height, format)) { + delete pBitmap; + return FALSE; + } + m_bOwnedBitmap = TRUE; + return Attach(pBitmap); +} +#endif |