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.
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
7 #include "../../../include/fxcrt/fx_ext.h"
8 #include "../../../include/fxge/fx_ge.h"
9 #include "../agg/include/fxfx_agg_clip_liang_barsky.h"
10 #include "../ge/text_int.h"
11 #include "../dib/dib_int.h"
12 #include "../agg/include/fx_agg_driver.h"
13 #include "../../../include/fxge/fx_freetype.h"
14 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
15 #include "apple_int.h"
16 #include "../../../include/fxge/fx_ge_apple.h"
17 #ifndef CGFLOAT_IS_DOUBLE
18 #error Expected CGFLOAT_IS_DOUBLE to be defined by CoreGraphics headers
20 void* CQuartz2D::createGraphics(CFX_DIBitmap* pBitmap)
25 CGBitmapInfo bmpInfo = kCGBitmapByteOrder32Little;
26 switch (pBitmap->GetFormat()) {
28 bmpInfo |= kCGImageAlphaNoneSkipFirst;
34 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
35 CGContextRef context = CGBitmapContextCreate(pBitmap->GetBuffer(),
42 CGColorSpaceRelease(colorSpace);
45 void CQuartz2D::destroyGraphics(void* graphics)
48 CGContextRelease((CGContextRef) graphics);
51 void* CQuartz2D::CreateFont(FX_LPCBYTE pFontData, FX_DWORD dwFontSize)
53 CGDataProviderRef pDataProvider = CGDataProviderCreateWithData(NULL, pFontData, (size_t)dwFontSize, NULL);
54 if (NULL == pDataProvider) {
57 CGFontRef pCGFont = CGFontCreateWithDataProvider(pDataProvider);
58 CGDataProviderRelease(pDataProvider);
61 void CQuartz2D::DestroyFont(void* pFont)
63 CGFontRelease((CGFontRef)pFont);
65 void CQuartz2D::setGraphicsTextMatrix(void* graphics, CFX_AffineMatrix* matrix)
67 if (!graphics || !matrix) {
70 CGContextRef context = (CGContextRef) graphics;
71 CGFloat ty = CGBitmapContextGetHeight(context) - matrix->f;
72 CGContextSetTextMatrix(context, CGAffineTransformMake(matrix->a,
79 FX_BOOL CQuartz2D::drawGraphicsString(void* graphics,
82 FX_WORD* glyphIndices,
83 CGPoint* glyphPositions,
86 CFX_AffineMatrix* matrix )
91 CGContextRef context = (CGContextRef) graphics;
92 CGContextSetFont(context, (CGFontRef)font);
93 CGContextSetFontSize(context, fontSize);
95 CGAffineTransform m = CGContextGetTextMatrix(context);
96 m = CGAffineTransformConcat(m,
97 CGAffineTransformMake(matrix->a,
103 CGContextSetTextMatrix(context, m);
106 ArgbDecode(argb, a, r, g, b);
107 CGContextSetRGBFillColor(context,
112 CGContextSaveGState(context);
113 #if CGFLOAT_IS_DOUBLE
114 CGPoint* glyphPositionsCG = new CGPoint[charsCount];
115 if (!glyphPositionsCG) {
118 for (int index = 0; index < charsCount; ++index) {
119 glyphPositionsCG[index].x = glyphPositions[index].x;
120 glyphPositionsCG[index].y = glyphPositions[index].y;
123 CGPoint* glyphPositionsCG = (CGPoint*)glyphPositions;
125 CGContextShowGlyphsAtPositions(context,
126 (CGGlyph *) glyphIndices,
129 #if CGFLOAT_IS_DOUBLE
130 delete[] glyphPositionsCG;
132 CGContextRestoreGState(context);
135 void CQuartz2D::saveGraphicsState(void * graphics)
138 CGContextSaveGState((CGContextRef) graphics);
141 void CQuartz2D::restoreGraphicsState(void * graphics)
144 CGContextRestoreGState((CGContextRef) graphics);
147 static CGContextRef createContextWithBitmap(CFX_DIBitmap* pBitmap)
149 if (!pBitmap || pBitmap->IsCmykImage() || pBitmap->GetBPP() < 32) {
152 CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little;
153 if (pBitmap->HasAlpha()) {
154 bitmapInfo |= kCGImageAlphaPremultipliedFirst;
156 bitmapInfo |= kCGImageAlphaNoneSkipFirst;
158 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
159 CGContextRef context = CGBitmapContextCreate(pBitmap->GetBuffer(),
161 pBitmap->GetHeight(),
166 CGColorSpaceRelease(colorSpace);
169 CFX_QuartzDeviceDriver::CFX_QuartzDeviceDriver(CGContextRef context, FX_INT32 deviceClass)
173 _deviceClass = deviceClass;
174 CGContextRetain(_context);
175 CGRect r = CGContextGetClipBoundingBox(context);
176 _width = FXSYS_round(r.size.width);
177 _height = FXSYS_round(r.size.height);
178 _renderCaps = FXRC_SOFT_CLIP | FXRC_BLEND_MODE |
179 FXRC_ALPHA_PATH | FXRC_ALPHA_IMAGE |
180 FXRC_BIT_MASK | FXRC_ALPHA_MASK;
181 if (_deviceClass != FXDC_DISPLAY) {
183 CGImageRef image = CGBitmapContextCreateImage(_context);
185 _renderCaps |= FXRC_GET_BITS;
186 _width = CGImageGetWidth(image);
187 _height = CGImageGetHeight(image);
188 CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(image);
189 if (kCGImageAlphaPremultipliedFirst == alphaInfo ||
190 kCGImageAlphaPremultipliedLast == alphaInfo ||
191 kCGImageAlphaOnly == alphaInfo) {
192 _renderCaps |= FXRC_ALPHA_OUTPUT;
195 CGImageRelease(image);
197 CGAffineTransform ctm = CGContextGetCTM(_context);
198 CGContextSaveGState(_context);
201 CGFloat offset_x, offset_y;
204 CGContextTranslateCTM(_context, -offset_x, -offset_y);
205 CGContextConcatCTM(_context, CGAffineTransformMake(1, 0, 0, -1, offset_x, _height + offset_y));
207 _foxitDevice2User = CGAffineTransformIdentity;
208 _user2FoxitDevice = CGAffineTransformInvert(_foxitDevice2User);
210 CFX_QuartzDeviceDriver::~CFX_QuartzDeviceDriver()
212 CGContextRestoreGState(_context);
214 for (int i = 0; i < m_saveCount; ++i) {
215 CGContextRestoreGState(_context);
218 CGContextRelease(_context);
221 int CFX_QuartzDeviceDriver::GetDeviceCaps(int capsID)
224 case FXDC_DEVICE_CLASS: {
227 case FXDC_PIXEL_WIDTH: {
230 case FXDC_PIXEL_HEIGHT: {
233 case FXDC_BITS_PIXEL: {
236 case FXDC_RENDER_CAPS: {
244 CFX_Matrix CFX_QuartzDeviceDriver::GetCTM() const
246 CGAffineTransform ctm = CGContextGetCTM(_context);
247 return CFX_Matrix(ctm.a, ctm.b, ctm.c, ctm.d, ctm.tx, ctm.ty);
249 void CFX_QuartzDeviceDriver::SaveState()
251 CGContextSaveGState(_context);
254 void CFX_QuartzDeviceDriver::RestoreState(FX_BOOL isKeepSaved )
256 CGContextRestoreGState(_context);
258 CGContextSaveGState(_context);
263 FX_BOOL CFX_QuartzDeviceDriver::SetClip_PathFill(const CFX_PathData* pathData,
264 const CFX_AffineMatrix* matrix,
268 CGAffineTransform m = CGAffineTransformIdentity;
270 m = CGAffineTransformMake(matrix->GetA(), matrix->GetB(), matrix->GetC(), matrix->GetD(), matrix->GetE(), matrix->GetF());
272 m = CGAffineTransformConcat(m, _foxitDevice2User);
273 CGContextConcatCTM(_context, m);
274 setPathToContext(pathData);
276 if ((fillMode & 3) == FXFILL_WINDING) {
277 CGContextClip(_context);
279 CGContextEOClip(_context);
283 FX_FLOAT CFX_QuartzDeviceDriver::getLineWidth(const CFX_GraphStateData * graphState, CGAffineTransform ctm)
285 FX_FLOAT lineWidth = graphState->m_LineWidth;
286 if (graphState->m_LineWidth <= 0.f) {
290 CGSize temp = CGSizeApplyAffineTransform(size, ctm);
291 CGFloat x = 1 / temp.width;
292 CGFloat y = 1 / temp.height;
293 lineWidth = x > y ? x : y;
297 FX_BOOL CFX_QuartzDeviceDriver::SetClip_PathStroke(const CFX_PathData* pathData,
298 const CFX_AffineMatrix* matrix,
299 const CFX_GraphStateData* graphState )
302 CGAffineTransform m = CGAffineTransformIdentity;
304 m = CGAffineTransformMake(matrix->GetA(), matrix->GetB(), matrix->GetC(), matrix->GetD(), matrix->GetE(), matrix->GetF());
306 m = CGAffineTransformConcat(m, _foxitDevice2User);
307 CGContextConcatCTM(_context, m);
308 FX_FLOAT lineWidth = getLineWidth(graphState, m);
309 setStrokeInfo(graphState, 0xFF000000, lineWidth);
310 setPathToContext(pathData);
311 CGContextReplacePathWithStrokedPath(_context);
313 CGContextClip(_context);
316 static CGBlendMode GetCGBlendMode(int blend_type)
318 CGBlendMode mode = kCGBlendModeNormal;
319 switch (blend_type) {
320 case FXDIB_BLEND_NORMAL:
321 mode = kCGBlendModeNormal;
323 case FXDIB_BLEND_MULTIPLY:
324 mode = kCGBlendModeMultiply;
326 case FXDIB_BLEND_SCREEN:
327 mode = kCGBlendModeScreen;
329 case FXDIB_BLEND_OVERLAY:
330 mode = kCGBlendModeOverlay;
332 case FXDIB_BLEND_DARKEN:
333 mode = kCGBlendModeDarken;
335 case FXDIB_BLEND_LIGHTEN:
336 mode = kCGBlendModeLighten;
338 case FXDIB_BLEND_COLORDODGE:
339 mode = kCGBlendModeColorDodge;
341 case FXDIB_BLEND_COLORBURN:
342 mode = kCGBlendModeColorBurn;
344 case FXDIB_BLEND_HARDLIGHT:
345 mode = kCGBlendModeHardLight;
347 case FXDIB_BLEND_SOFTLIGHT:
348 mode = kCGBlendModeSoftLight;
350 case FXDIB_BLEND_DIFFERENCE:
351 mode = kCGBlendModeDifference;
353 case FXDIB_BLEND_EXCLUSION:
354 mode = kCGBlendModeExclusion;
356 case FXDIB_BLEND_HUE:
357 mode = kCGBlendModeHue;
359 case FXDIB_BLEND_SATURATION:
360 mode = kCGBlendModeSaturation;
362 case FXDIB_BLEND_COLOR:
363 mode = kCGBlendModeColor;
365 case FXDIB_BLEND_LUMINOSITY:
366 mode = kCGBlendModeLuminosity;
369 mode = kCGBlendModeNormal;
374 FX_BOOL CFX_QuartzDeviceDriver::DrawPath(const CFX_PathData* pathData,
375 const CFX_AffineMatrix* matrix,
376 const CFX_GraphStateData* graphState,
386 CGBlendMode mode = GetCGBlendMode(blend_type);
387 if (mode != kCGBlendModeNormal) {
388 CGContextSetBlendMode(_context, mode);
390 CGAffineTransform m = CGAffineTransformIdentity;
392 m = CGAffineTransformMake(matrix->GetA(), matrix->GetB(), matrix->GetC(), matrix->GetD(), matrix->GetE(), matrix->GetF());
394 m = CGAffineTransformConcat(m, _foxitDevice2User);
395 CGContextConcatCTM(_context, m);
397 if (graphState && strokeArgb) {
398 CGContextSetMiterLimit(_context, graphState->m_MiterLimit);
399 FX_FLOAT lineWidth = getLineWidth(graphState, m);
400 setStrokeInfo(graphState, strokeArgb, lineWidth);
403 if (fillMode && fillArgb) {
404 setFillInfo(fillArgb);
405 if ((fillMode & 3) == FXFILL_WINDING) {
407 } else if ((fillMode & 3) == FXFILL_ALTERNATE) {
411 setPathToContext(pathData);
412 if (fillMode & FXFILL_FULLCOVER) {
413 CGContextSetShouldAntialias(_context, false);
416 CGContextStrokePath(_context);
417 } else if (pathMode == 1) {
418 CGContextFillPath(_context);
419 } else if (pathMode == 2) {
420 CGContextEOFillPath(_context);
421 } else if (pathMode == 5) {
422 CGContextDrawPath(_context, kCGPathFillStroke);
423 } else if (pathMode == 6) {
424 CGContextDrawPath(_context, kCGPathEOFillStroke);
429 FX_BOOL CFX_QuartzDeviceDriver::FillRect(const FX_RECT* rect,
435 CGBlendMode mode = GetCGBlendMode(blend_type);
436 if (mode != kCGBlendModeNormal) {
437 CGContextSetBlendMode(_context, mode);
439 CGRect rect_fx = CGRectMake(rect->left, rect->top, rect->Width(), rect->Height());
440 CGRect rect_usr = CGRectApplyAffineTransform(rect_fx, _foxitDevice2User);
442 ArgbDecode(fillArgb, a, r, g, b);
443 CGContextSetRGBFillColor(_context,
448 CGContextFillRect(_context, rect_usr);
449 if (mode != kCGBlendModeNormal) {
450 CGContextSetBlendMode(_context, kCGBlendModeNormal);
454 FX_BOOL CFX_QuartzDeviceDriver::DrawCosmeticLine(FX_FLOAT x1,
463 CGBlendMode mode = GetCGBlendMode(blend_type);
464 if (mode != kCGBlendModeNormal) {
465 CGContextSetBlendMode(_context, mode);
467 CGPoint pt = CGPointApplyAffineTransform(CGPointMake(x1, y1), _foxitDevice2User);
470 pt = CGPointApplyAffineTransform(CGPointMake(x2, y2), _foxitDevice2User);
474 ArgbDecode(argb, a, r, g, b);
475 CGContextSetRGBStrokeColor(_context,
480 CGContextMoveToPoint(_context, x1, y1);
481 CGContextAddLineToPoint(_context, x2, y2);
482 CGContextStrokePath(_context);
483 if (mode != kCGBlendModeNormal) {
484 CGContextSetBlendMode(_context, kCGBlendModeNormal);
488 FX_BOOL CFX_QuartzDeviceDriver::GetClipBox(FX_RECT* rect)
490 CGRect r = CGContextGetClipBoundingBox(_context);
491 r = CGRectApplyAffineTransform(r, _user2FoxitDevice);
492 rect->left = FXSYS_floor(r.origin.x);
493 rect->top = FXSYS_floor(r.origin.y);
494 rect->right = FXSYS_ceil(r.origin.x + r.size.width);
495 rect->bottom = FXSYS_ceil(r.origin.y + r.size.height);
498 FX_BOOL CFX_QuartzDeviceDriver::GetDIBits(CFX_DIBitmap* bitmap,
504 if (FXDC_PRINTER == _deviceClass) {
507 if (bitmap->GetBPP() < 32) {
510 if (!(_renderCaps | FXRC_GET_BITS)) {
513 CGPoint pt = CGPointMake(left, top);
514 pt = CGPointApplyAffineTransform(pt, _foxitDevice2User);
515 CGAffineTransform ctm = CGContextGetCTM(_context);
516 pt.x *= FXSYS_fabs(ctm.a);
517 pt.y *= FXSYS_fabs(ctm.d);
518 CGImageRef image = CGBitmapContextCreateImage(_context);
522 CGFloat width = (CGFloat) bitmap->GetWidth();
523 CGFloat height = (CGFloat) bitmap->GetHeight();
524 if (width + pt.x > _width) {
525 width -= (width + pt.x - _width);
527 if (height + pt.y > _height) {
528 height -= (height + pt.y - _height);
530 CGImageRef subImage = CGImageCreateWithImageInRect(image,
535 CGContextRef context = createContextWithBitmap(bitmap);
536 CGRect rect = CGContextGetClipBoundingBox(context);
537 CGContextClearRect(context, rect);
538 CGContextDrawImage(context, rect, subImage);
539 CGContextRelease(context);
540 CGImageRelease(subImage);
541 CGImageRelease(image);
542 if (bitmap->HasAlpha()) {
543 for (int row = 0; row < bitmap->GetHeight(); row ++) {
544 FX_LPBYTE pScanline = (FX_LPBYTE)bitmap->GetScanline(row);
545 for (int col = 0; col < bitmap->GetWidth(); col ++) {
546 if (pScanline[3] > 0) {
547 pScanline[0] = (pScanline[0] * 255.f / pScanline[3] + .5f);
548 pScanline[1] = (pScanline[1] * 255.f / pScanline[3] + .5f);
549 pScanline[2] = (pScanline[2] * 255.f / pScanline[3] + .5f);
557 FX_BOOL CFX_QuartzDeviceDriver::SetDIBits(const CFX_DIBSource* pBitmap,
559 const FX_RECT* srcRect,
567 CGFloat src_left, src_top, src_width, src_height;
569 src_left = srcRect->left;
570 src_top = srcRect->top;
571 src_width = srcRect->Width();
572 src_height = srcRect->Height();
574 src_left = src_top = 0;
575 src_width = pBitmap->GetWidth();
576 src_height = pBitmap->GetHeight();
578 CGAffineTransform ctm = CGContextGetCTM(_context);
579 CGFloat scale_x = FXSYS_fabs(ctm.a);
580 CGFloat scale_y = FXSYS_fabs(ctm.d);
583 src_width /= scale_x;
584 src_height /= scale_y;
585 CGRect rect_fx = CGRectMake(dest_left, dest_top, src_width, src_height);
586 CGRect rect_usr = CGRectApplyAffineTransform(rect_fx, _foxitDevice2User);
587 CGContextBeginPath(_context);
588 CGContextAddRect(_context, rect_usr);
589 CGContextClip(_context);
590 rect_usr.size = CGSizeMake(pBitmap->GetWidth() / scale_x, pBitmap->GetHeight() / scale_y);
591 rect_usr = CGRectOffset(rect_usr, -src_left, -src_top);
592 CG_SetImageTransform(dest_left, dest_top, src_width, src_height, &rect_usr);
593 CFX_DIBitmap* pBitmap1 = NULL;
594 if (pBitmap->IsAlphaMask()) {
595 if (pBitmap->GetBuffer()) {
596 pBitmap1 = (CFX_DIBitmap*)pBitmap;
598 pBitmap1 = pBitmap->Clone();
600 if (NULL == pBitmap1) {
604 CGDataProviderRef pBitmapProvider = CGDataProviderCreateWithData(NULL,
605 pBitmap1->GetBuffer(),
606 pBitmap1->GetPitch() * pBitmap1->GetHeight(),
608 CGColorSpaceRef pColorSpace = CGColorSpaceCreateDeviceGray();
609 CGBitmapInfo bitmapInfo = kCGImageAlphaNone | kCGBitmapByteOrderDefault;
610 CGImageRef pImage = CGImageCreate(pBitmap1->GetWidth(),
611 pBitmap1->GetHeight(),
614 pBitmap1->GetPitch(),
617 pBitmapProvider, NULL, true,
618 kCGRenderingIntentDefault);
619 CGContextClipToMask(_context, rect_usr, pImage);
620 CGContextSetRGBFillColor(_context,
621 FXARGB_R(argb) / 255.f,
622 FXARGB_G(argb) / 255.f,
623 FXARGB_B(argb) / 255.f,
624 FXARGB_A(argb) / 255.f);
625 CGContextFillRect(_context, rect_usr);
626 CGImageRelease(pImage);
627 CGColorSpaceRelease(pColorSpace);
628 CGDataProviderRelease(pBitmapProvider);
629 if (pBitmap1 != pBitmap) {
635 if (pBitmap->GetBPP() < 32) {
636 pBitmap1 = pBitmap->CloneConvert(FXDIB_Rgb32);
638 if (pBitmap->GetBuffer()) {
639 pBitmap1 = (CFX_DIBitmap*)pBitmap;
641 pBitmap1 = pBitmap->Clone();
644 if (NULL == pBitmap1) {
648 if (pBitmap1->HasAlpha()) {
649 if (pBitmap1 == pBitmap) {
650 pBitmap1 = pBitmap->Clone();
656 for (int row = 0; row < pBitmap1->GetHeight(); row ++) {
657 FX_LPBYTE pScanline = (FX_LPBYTE)pBitmap1->GetScanline(row);
658 for (int col = 0; col < pBitmap1->GetWidth(); col ++) {
659 pScanline[0] = (FX_BYTE)(pScanline[0] * pScanline[3] / 255.f + .5f);
660 pScanline[1] = (FX_BYTE)(pScanline[1] * pScanline[3] / 255.f + .5f);
661 pScanline[2] = (FX_BYTE)(pScanline[2] * pScanline[3] / 255.f + .5f);
666 CGContextRef ctx = createContextWithBitmap(pBitmap1);
667 CGImageRef image = CGBitmapContextCreateImage(ctx);
668 int blend_mode = blendType;
669 if (FXDIB_BLEND_HARDLIGHT == blendType) {
670 blend_mode = kCGBlendModeSoftLight;
671 } else if (FXDIB_BLEND_SOFTLIGHT == blendType) {
672 blend_mode = kCGBlendModeHardLight;
673 } else if (blendType >= FXDIB_BLEND_NONSEPARABLE && blendType <= FXDIB_BLEND_LUMINOSITY) {
674 blend_mode = blendType - 9;
675 } else if (blendType > FXDIB_BLEND_LUMINOSITY || blendType < 0) {
676 blend_mode = kCGBlendModeNormal;
678 CGContextSetBlendMode(_context, (CGBlendMode)blend_mode);
679 CGContextDrawImage(_context, rect_usr, image);
680 CGImageRelease(image);
681 CGContextRelease(ctx);
682 if (pBitmap1 != pBitmap) {
688 FX_BOOL CFX_QuartzDeviceDriver::StretchDIBits(const CFX_DIBSource* pBitmap,
694 const FX_RECT* clipRect,
702 CGContextBeginPath(_context);
703 CGRect rect_clip = CGRectMake(clipRect->left, clipRect->top, clipRect->Width(), clipRect->Height());
704 rect_clip = CGRectApplyAffineTransform(rect_clip, _foxitDevice2User);
705 CGContextAddRect(_context, rect_clip);
706 CGContextClip(_context);
708 CGRect rect = CGRectMake(dest_left, dest_top, dest_width, dest_height);
709 rect = CGRectApplyAffineTransform(rect, _foxitDevice2User);
710 if (FXDIB_BICUBIC_INTERPOL == flags) {
711 CGContextSetInterpolationQuality(_context, kCGInterpolationHigh);
712 } else if (FXDIB_DOWNSAMPLE == flags) {
713 CGContextSetInterpolationQuality(_context, kCGInterpolationNone);
715 CGContextSetInterpolationQuality(_context, kCGInterpolationMedium);
717 CG_SetImageTransform(dest_left, dest_top, dest_width, dest_height);
718 CFX_DIBitmap* pBitmap1 = NULL;
719 if (pBitmap->IsAlphaMask()) {
720 if (pBitmap->GetBuffer()) {
721 pBitmap1 = (CFX_DIBitmap*)pBitmap;
723 pBitmap1 = pBitmap->Clone();
725 if (NULL == pBitmap1) {
729 CGDataProviderRef pBitmapProvider = CGDataProviderCreateWithData(NULL,
730 pBitmap1->GetBuffer(),
731 pBitmap1->GetPitch() * pBitmap1->GetHeight(),
733 CGColorSpaceRef pColorSpace = CGColorSpaceCreateDeviceGray();
734 CGBitmapInfo bitmapInfo = kCGImageAlphaNone | kCGBitmapByteOrderDefault;
735 CGImageRef pImage = CGImageCreate(pBitmap1->GetWidth(),
736 pBitmap1->GetHeight(),
739 pBitmap1->GetPitch(),
742 pBitmapProvider, NULL, true,
743 kCGRenderingIntentDefault);
744 CGContextClipToMask(_context, rect, pImage);
745 CGContextSetRGBFillColor(_context,
746 FXARGB_R(argb) / 255.f,
747 FXARGB_G(argb) / 255.f,
748 FXARGB_B(argb) / 255.f,
749 FXARGB_A(argb) / 255.f);
750 CGContextFillRect(_context, rect);
751 CGImageRelease(pImage);
752 CGColorSpaceRelease(pColorSpace);
753 CGDataProviderRelease(pBitmapProvider);
754 if (pBitmap1 != pBitmap) {
760 if (pBitmap->GetBPP() < 32) {
761 pBitmap1 = pBitmap->CloneConvert(FXDIB_Rgb32);
763 if (pBitmap->GetBuffer()) {
764 pBitmap1 = (CFX_DIBitmap*)pBitmap;
766 pBitmap1 = pBitmap->Clone();
769 if (NULL == pBitmap1) {
773 if (pBitmap1->HasAlpha()) {
774 if (pBitmap1 == pBitmap) {
775 pBitmap1 = pBitmap->Clone();
781 for (int row = 0; row < pBitmap1->GetHeight(); row ++) {
782 FX_LPBYTE pScanline = (FX_LPBYTE)pBitmap1->GetScanline(row);
783 for (int col = 0; col < pBitmap1->GetWidth(); col ++) {
784 pScanline[0] = (FX_BYTE)(pScanline[0] * pScanline[3] / 255.f + .5f);
785 pScanline[1] = (FX_BYTE)(pScanline[1] * pScanline[3] / 255.f + .5f);
786 pScanline[2] = (FX_BYTE)(pScanline[2] * pScanline[3] / 255.f + .5f);
791 CGContextRef ctx = createContextWithBitmap(pBitmap1);
792 CGImageRef image = CGBitmapContextCreateImage(ctx);
793 CGContextDrawImage(_context, rect, image);
794 CGImageRelease(image);
795 CGContextRelease(ctx);
796 if (pBitmap1 != pBitmap) {
802 FX_BOOL CFX_QuartzDeviceDriver::CG_DrawGlypRun(int nChars,
803 const FXTEXT_CHARPOS* pCharPos,
805 CFX_FontCache* pCache,
806 const CFX_AffineMatrix* pGlyphMatrix,
807 const CFX_AffineMatrix* pObject2Device,
816 CQuartz2D& quartz2d = ((CApplePlatform *) CFX_GEModule::Get()->GetPlatformData())->_quartz2d;
817 if (!pFont->m_pPlatformFont) {
818 if (pFont->GetPsName() == CFX_WideString::FromLocal("DFHeiStd-W5")) {
821 pFont->m_pPlatformFont = quartz2d.CreateFont(pFont->m_pFontData, pFont->m_dwSize);
822 if (NULL == pFont->m_pPlatformFont) {
826 CFX_FixedBufGrow<FX_WORD, 32> glyph_indices(nChars);
827 CFX_FixedBufGrow<CGPoint, 32> glyph_positions(nChars);
828 for (int i = 0; i < nChars; i++ ) {
829 glyph_indices[i] = pCharPos[i].m_ExtGID;
830 glyph_positions[i].x = pCharPos[i].m_OriginX;
831 glyph_positions[i].y = pCharPos[i].m_OriginY;
833 CFX_AffineMatrix text_matrix;
834 if (pObject2Device) {
835 text_matrix.Concat(*pObject2Device);
837 CGAffineTransform matrix_cg = CGAffineTransformMake(text_matrix.a,
843 matrix_cg = CGAffineTransformConcat(matrix_cg, _foxitDevice2User);
844 CGContextSetTextMatrix(_context, matrix_cg);
845 CGContextSetFont(_context, (CGFontRef)pFont->m_pPlatformFont);
846 CGContextSetFontSize(_context, FXSYS_fabs(font_size));
848 ArgbDecode(argb, a, r, g, b);
849 CGContextSetRGBFillColor(_context,
856 CGPoint origin = CGPointMake( glyph_positions[0].x, glyph_positions[0].y);
857 origin = CGPointApplyAffineTransform(origin, matrix_cg);
858 CGContextTranslateCTM(_context, origin.x, origin.y);
859 CGAffineTransform glyph_matrix = CGAffineTransformMake(pGlyphMatrix->a,
865 if (_foxitDevice2User.d < 0) {
866 glyph_matrix = CGAffineTransformInvert(glyph_matrix);
868 CGContextConcatCTM(_context, glyph_matrix);
869 CGContextTranslateCTM(_context, -origin.x, -origin.y);
871 CGContextShowGlyphsAtPositions(_context,
872 (CGGlyph*)glyph_indices,
878 FX_BOOL CFX_QuartzDeviceDriver::DrawDeviceText(int nChars,
879 const FXTEXT_CHARPOS* pCharPos,
881 CFX_FontCache* pCache,
882 const CFX_AffineMatrix* pObject2Device,
888 if (NULL == pFont || NULL == _context) {
891 FX_BOOL bBold = pFont->IsBold();
892 if (!bBold && pFont->GetSubstFont() &&
893 pFont->GetSubstFont()->m_Weight >= 500 &&
894 pFont->GetSubstFont()->m_Weight <= 600) {
898 CGContextSetTextDrawingMode(_context, kCGTextFillClip);
902 if (pCharPos[i].m_bGlyphAdjust || font_size < 0) {
904 ret = CG_DrawGlypRun(i, pCharPos, pFont, pCache, NULL, pObject2Device, font_size, color, alpha_flag, pIccTransform);
910 const FXTEXT_CHARPOS* char_pos = pCharPos + i;
911 CFX_AffineMatrix glphy_matrix;
913 glphy_matrix.Concat(-1, 0, 0, -1, 0, 0);
915 if (char_pos->m_bGlyphAdjust) {
916 glphy_matrix.Concat(char_pos->m_AdjustMatrix[0],
917 char_pos->m_AdjustMatrix[1],
918 char_pos->m_AdjustMatrix[2],
919 char_pos->m_AdjustMatrix[3], 0, 0);
921 ret = CG_DrawGlypRun(1, char_pos, pFont, pCache, &glphy_matrix, pObject2Device, font_size, color, alpha_flag, pIccTransform);
935 ret = CG_DrawGlypRun(i, pCharPos, pFont, pCache, NULL, pObject2Device, font_size, color, alpha_flag, pIccTransform);
940 void CFX_QuartzDeviceDriver::setStrokeInfo(const CFX_GraphStateData* graphState, FX_ARGB argb, FX_FLOAT lineWidth)
942 if (NULL == graphState) {
945 CGContextSetLineWidth(_context, lineWidth);
947 switch (graphState->m_LineCap) {
948 case CFX_GraphStateData::LineCapRound: {
949 cap = kCGLineCapRound;
952 case CFX_GraphStateData::LineCapSquare: {
953 cap = kCGLineCapSquare;
956 case CFX_GraphStateData::LineCapButt:
958 cap = kCGLineCapButt;
961 CGContextSetLineCap(_context, cap);
963 switch (graphState->m_LineJoin) {
964 case CFX_GraphStateData::LineJoinRound: {
965 join = kCGLineJoinRound;
968 case CFX_GraphStateData::LineJoinBevel: {
969 join = kCGLineJoinBevel;
972 case CFX_GraphStateData::LineJoinMiter:
974 join = kCGLineJoinMiter;
977 CGContextSetLineJoin(_context, join);
978 if (graphState->m_DashCount) {
979 #if CGFLOAT_IS_DOUBLE
980 CGFloat* dashArray = new CGFloat[graphState->m_DashCount];
984 for (int index = 0; index < graphState->m_DashCount; ++index) {
985 dashArray[index] = graphState->m_DashArray[index];
988 CGFloat* dashArray = (CGFloat*)graphState->m_DashArray;
990 CGContextSetLineDash(_context, graphState->m_DashPhase, dashArray, graphState->m_DashCount);
991 #if CGFLOAT_IS_DOUBLE
996 ArgbDecode(argb, a, r, g, b);
997 CGContextSetRGBStrokeColor(_context,
1003 void CFX_QuartzDeviceDriver::setFillInfo(FX_ARGB argb)
1005 FX_INT32 a, r, g, b;
1006 ArgbDecode(argb, a, r, g, b);
1007 CGContextSetRGBFillColor(_context,
1013 void CFX_QuartzDeviceDriver::setPathToContext(const CFX_PathData* pathData)
1015 FX_INT32 count = pathData->GetPointCount();
1016 FX_PATHPOINT* points = pathData->GetPoints();
1017 CGContextBeginPath(_context);
1018 for (FX_INT32 i = 0; i < count; i ++) {
1019 switch (points[i].m_Flag & FXPT_TYPE) {
1021 CGContextMoveToPoint(_context, points[i].m_PointX, points[i].m_PointY);
1024 CGContextAddLineToPoint(_context, points[i].m_PointX, points[i].m_PointY);
1026 case FXPT_BEZIERTO: {
1027 CGContextAddCurveToPoint(_context,
1028 points[i].m_PointX, points[i].m_PointY,
1029 points[i + 1].m_PointX, points[i + 1].m_PointY,
1030 points[i + 2].m_PointX, points[i + 2].m_PointY);
1034 if (points[i].m_Flag & FXPT_CLOSEFIGURE) {
1035 CGContextClosePath(_context);
1039 void CFX_QuartzDeviceDriver::CG_SetImageTransform(int dest_left, int dest_top, int dest_width, int dest_height,
1042 int flip_y = _foxitDevice2User.d * dest_height < 0 ? 1 : -1;
1043 int flip_x = _foxitDevice2User.a * dest_width > 0 ? 1 : -1;
1044 if (flip_y < 0 || flip_x < 0) {
1045 if (dest_height < 0) {
1046 dest_height = -dest_height;
1047 dest_top -= dest_height;
1049 CGRect rt = CGRectApplyAffineTransform(CGRectMake(dest_left, dest_top, dest_width, dest_height), _foxitDevice2User);
1050 CGFloat offset_x = (rt.origin.x) + rt.size.width / 2.f,
1051 offset_y = (rt.origin.y) + rt.size.height / 2.f;
1052 CGAffineTransform transform = CGAffineTransformIdentity;
1053 transform = CGAffineTransformConcat(transform, CGAffineTransformMake(1, 0, 0, 1, -offset_x, -offset_y));
1054 transform = CGAffineTransformConcat(transform, CGAffineTransformMake(flip_x, 0, 0, flip_y, 0, 0));
1055 transform = CGAffineTransformConcat(transform, CGAffineTransformMake(1, 0, 0, 1, offset_x, offset_y));
1056 CGContextConcatCTM(_context, transform);
1058 *rect = CGRectApplyAffineTransform(*rect, transform);
1062 void CFX_QuartzDeviceDriver::ClearDriver()
1064 if (NULL == _context) {
1067 for (int i = 0; i < m_saveCount; ++i) {
1068 CGContextRestoreGState(_context);
1072 CGContextRelease(_context);
1075 CFX_QuartzDevice::CFX_QuartzDevice()
1077 m_bOwnedBitmap = FALSE;
1080 CFX_QuartzDevice::~CFX_QuartzDevice()
1083 CGContextRelease(m_pContext);
1085 if (GetBitmap() && m_bOwnedBitmap) {
1089 CGContextRef CFX_QuartzDevice::GetContext()
1093 FX_BOOL CFX_QuartzDevice::Attach(CGContextRef context, FX_INT32 nDeviceClass)
1096 CGContextRelease(m_pContext);
1098 m_pContext = context;
1099 CGContextRetain(m_pContext);
1100 IFX_RenderDeviceDriver* pDriver = FX_NEW CFX_QuartzDeviceDriver(m_pContext, nDeviceClass);
1104 SetDeviceDriver(pDriver);
1107 FX_BOOL CFX_QuartzDevice::Attach(CFX_DIBitmap* pBitmap)
1110 m_pContext = createContextWithBitmap(pBitmap);
1111 if (NULL == m_pContext) {
1114 IFX_RenderDeviceDriver* pDriver = FX_NEW CFX_QuartzDeviceDriver(m_pContext, FXDC_DISPLAY);
1118 SetDeviceDriver(pDriver);
1121 FX_BOOL CFX_QuartzDevice::Create(FX_INT32 width, FX_INT32 height, FXDIB_Format format)
1123 if ((FX_BYTE)format < 32) {
1126 CFX_DIBitmap* pBitmap = FX_NEW CFX_DIBitmap;
1130 if (!pBitmap->Create(width, height, format)) {
1134 m_bOwnedBitmap = TRUE;
1135 return Attach(pBitmap);