FX_BOOL considered harmful, part 2.
[pdfium.git] / core / src / fxge / apple / fx_quartz_device.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "../../../include/fxcrt/fx_ext.h"
8 #include "../../../include/fxge/fx_freetype.h"
9 #include "../../../include/fxge/fx_ge.h"
10 #include "../agg/include/fx_agg_driver.h"
11 #include "../dib/dib_int.h"
12 #include "../ge/text_int.h"
13
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
19 #endif
20 void* CQuartz2D::createGraphics(CFX_DIBitmap* pBitmap)
21 {
22     if (!pBitmap) {
23         return NULL;
24     }
25     CGBitmapInfo bmpInfo = kCGBitmapByteOrder32Little;
26     switch (pBitmap->GetFormat()) {
27         case FXDIB_Rgb32:
28             bmpInfo |= kCGImageAlphaNoneSkipFirst;
29             break;
30         case FXDIB_Argb:
31         default:
32             return NULL;
33     }
34     CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
35     CGContextRef context = CGBitmapContextCreate(pBitmap->GetBuffer(),
36                            pBitmap->GetWidth(),
37                            pBitmap->GetHeight(),
38                            8,
39                            pBitmap->GetPitch(),
40                            colorSpace,
41                            bmpInfo);
42     CGColorSpaceRelease(colorSpace);
43     return context;
44 }
45 void CQuartz2D::destroyGraphics(void* graphics)
46 {
47     if (graphics) {
48         CGContextRelease((CGContextRef) graphics);
49     }
50 }
51 void* CQuartz2D::CreateFont(const uint8_t* pFontData, FX_DWORD dwFontSize)
52 {
53     CGDataProviderRef pDataProvider = CGDataProviderCreateWithData(NULL, pFontData, (size_t)dwFontSize, NULL);
54     if (NULL == pDataProvider) {
55         return NULL;
56     }
57     CGFontRef pCGFont = CGFontCreateWithDataProvider(pDataProvider);
58     CGDataProviderRelease(pDataProvider);
59     return pCGFont;
60 }
61 void CQuartz2D::DestroyFont(void* pFont)
62 {
63     CGFontRelease((CGFontRef)pFont);
64 }
65 void CQuartz2D::setGraphicsTextMatrix(void* graphics, CFX_AffineMatrix* matrix)
66 {
67     if (!graphics || !matrix) {
68         return;
69     }
70     CGContextRef context = (CGContextRef) graphics;
71     CGFloat ty = CGBitmapContextGetHeight(context) - matrix->f;
72     CGContextSetTextMatrix(context, CGAffineTransformMake(matrix->a,
73                            matrix->b,
74                            matrix->c,
75                            matrix->d,
76                            matrix->e,
77                            ty));
78 }
79 bool CQuartz2D::drawGraphicsString(void*                 graphics,
80                                       void*                 font,
81                                       FX_FLOAT              fontSize,
82                                       FX_WORD*              glyphIndices,
83                                       CGPoint*           glyphPositions,
84                                       int32_t              charsCount,
85                                       FX_ARGB               argb,
86                                       CFX_AffineMatrix*     matrix )
87 {
88     if (!graphics) {
89         return false;
90     }
91     CGContextRef context = (CGContextRef) graphics;
92     CGContextSetFont(context, (CGFontRef)font);
93     CGContextSetFontSize(context, fontSize);
94     if (matrix) {
95         CGAffineTransform m = CGContextGetTextMatrix(context);
96         m = CGAffineTransformConcat(m,
97                                     CGAffineTransformMake(matrix->a,
98                                             matrix->b,
99                                             matrix->c,
100                                             matrix->d,
101                                             matrix->e,
102                                             matrix->f));
103         CGContextSetTextMatrix(context, m);
104     }
105     int32_t a, r, g, b;
106     ArgbDecode(argb, a, r, g, b);
107     CGContextSetRGBFillColor(context,
108                              r / 255.f,
109                              g / 255.f,
110                              b / 255.f,
111                              a / 255.f);
112     CGContextSaveGState(context);
113 #if CGFLOAT_IS_DOUBLE
114     CGPoint* glyphPositionsCG = new CGPoint[charsCount];
115     if (!glyphPositionsCG) {
116         return false;
117     }
118     for (int index = 0; index < charsCount; ++index) {
119         glyphPositionsCG[index].x = glyphPositions[index].x;
120         glyphPositionsCG[index].y = glyphPositions[index].y;
121     }
122 #else
123     CGPoint* glyphPositionsCG = (CGPoint*)glyphPositions;
124 #endif
125     CGContextShowGlyphsAtPositions(context,
126                                    (CGGlyph *) glyphIndices,
127                                    glyphPositionsCG,
128                                    charsCount);
129 #if CGFLOAT_IS_DOUBLE
130     delete[] glyphPositionsCG;
131 #endif
132     CGContextRestoreGState(context);
133     return true;
134 }
135 void CQuartz2D::saveGraphicsState(void * graphics)
136 {
137     if (graphics) {
138         CGContextSaveGState((CGContextRef) graphics);
139     }
140 }
141 void CQuartz2D::restoreGraphicsState(void * graphics)
142 {
143     if (graphics) {
144         CGContextRestoreGState((CGContextRef) graphics);
145     }
146 }
147 static CGContextRef createContextWithBitmap(CFX_DIBitmap* pBitmap)
148 {
149     if (!pBitmap || pBitmap->IsCmykImage() || pBitmap->GetBPP() < 32) {
150         return NULL;
151     }
152     CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little;
153     if (pBitmap->HasAlpha()) {
154         bitmapInfo |= kCGImageAlphaPremultipliedFirst;
155     } else {
156         bitmapInfo |= kCGImageAlphaNoneSkipFirst;
157     }
158     CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
159     CGContextRef context = CGBitmapContextCreate(pBitmap->GetBuffer(),
160                            pBitmap->GetWidth(),
161                            pBitmap->GetHeight(),
162                            8,
163                            pBitmap->GetPitch(),
164                            colorSpace,
165                            bitmapInfo);
166     CGColorSpaceRelease(colorSpace);
167     return context;
168 }
169 CFX_QuartzDeviceDriver::CFX_QuartzDeviceDriver(CGContextRef context, int32_t deviceClass)
170 {
171     m_saveCount = 0;
172     _context            = context;
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) {
182     } else {
183         CGImageRef image = CGBitmapContextCreateImage(_context);
184         if (image) {
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;
193             }
194         }
195         CGImageRelease(image);
196     }
197     CGAffineTransform ctm = CGContextGetCTM(_context);
198     CGContextSaveGState(_context);
199     m_saveCount++;
200     if (ctm.d >= 0) {
201         CGFloat offset_x, offset_y;
202         offset_x = ctm.tx;
203         offset_y = ctm.ty;
204         CGContextTranslateCTM(_context, -offset_x, -offset_y);
205         CGContextConcatCTM(_context, CGAffineTransformMake(1, 0, 0, -1, offset_x, _height + offset_y));
206     }
207     _foxitDevice2User = CGAffineTransformIdentity;
208     _user2FoxitDevice = CGAffineTransformInvert(_foxitDevice2User);
209 }
210 CFX_QuartzDeviceDriver::~CFX_QuartzDeviceDriver()
211 {
212     CGContextRestoreGState(_context);
213     m_saveCount--;
214     for (int i = 0; i < m_saveCount; ++i) {
215         CGContextRestoreGState(_context);
216     }
217     if (_context) {
218         CGContextRelease(_context);
219     }
220 }
221 int CFX_QuartzDeviceDriver::GetDeviceCaps(int capsID)
222 {
223     switch (capsID) {
224         case FXDC_DEVICE_CLASS: {
225                 return _deviceClass;
226             }
227         case FXDC_PIXEL_WIDTH: {
228                 return _width;
229             }
230         case FXDC_PIXEL_HEIGHT: {
231                 return _height;
232             }
233         case FXDC_BITS_PIXEL: {
234                 return 32;
235             }
236         case FXDC_RENDER_CAPS: {
237                 return _renderCaps;
238             }
239         default: {
240                 return 0;
241             }
242     }
243 }
244 CFX_Matrix CFX_QuartzDeviceDriver::GetCTM() const
245 {
246     CGAffineTransform ctm = CGContextGetCTM(_context);
247     return CFX_Matrix(ctm.a, ctm.b, ctm.c, ctm.d, ctm.tx, ctm.ty);
248 }
249 void CFX_QuartzDeviceDriver::SaveState()
250 {
251     CGContextSaveGState(_context);
252     m_saveCount++;
253 }
254 void CFX_QuartzDeviceDriver::RestoreState(bool isKeepSaved )
255 {
256     CGContextRestoreGState(_context);
257     if (isKeepSaved) {
258         CGContextSaveGState(_context);
259     } else {
260         m_saveCount--;
261     }
262 }
263 bool CFX_QuartzDeviceDriver::SetClip_PathFill(const CFX_PathData*    pathData,
264         const CFX_AffineMatrix*   matrix,
265         int                       fillMode )
266 {
267     SaveState();
268     CGAffineTransform m = CGAffineTransformIdentity;
269     if (matrix) {
270         m = CGAffineTransformMake(matrix->GetA(), matrix->GetB(), matrix->GetC(), matrix->GetD(), matrix->GetE(), matrix->GetF());
271     }
272     m = CGAffineTransformConcat(m, _foxitDevice2User);
273     CGContextConcatCTM(_context, m);
274     setPathToContext(pathData);
275     RestoreState(false);
276     if ((fillMode & 3) == FXFILL_WINDING) {
277         CGContextClip(_context);
278     } else {
279         CGContextEOClip(_context);
280     }
281     return true;
282 }
283 FX_FLOAT CFX_QuartzDeviceDriver::getLineWidth(const CFX_GraphStateData * graphState, CGAffineTransform ctm)
284 {
285     FX_FLOAT lineWidth = graphState->m_LineWidth;
286     if (graphState->m_LineWidth <= 0.f) {
287         CGSize size;
288         size.width = 1;
289         size.height = 1;
290         CGSize temp = CGSizeApplyAffineTransform(size, ctm);
291         CGFloat x = 1 / temp.width;
292         CGFloat y = 1 / temp.height;
293         lineWidth = x > y ? x : y;
294     }
295     return lineWidth;
296 }
297 bool CFX_QuartzDeviceDriver::SetClip_PathStroke(const CFX_PathData*      pathData,
298         const CFX_AffineMatrix*     matrix,
299         const CFX_GraphStateData*   graphState )
300 {
301     SaveState();
302     CGAffineTransform m = CGAffineTransformIdentity;
303     if (matrix) {
304         m = CGAffineTransformMake(matrix->GetA(), matrix->GetB(), matrix->GetC(), matrix->GetD(), matrix->GetE(), matrix->GetF());
305     }
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);
312     RestoreState(false);
313     CGContextClip(_context);
314     return true;
315 }
316 static CGBlendMode GetCGBlendMode(int blend_type)
317 {
318     CGBlendMode mode = kCGBlendModeNormal;
319     switch (blend_type) {
320         case FXDIB_BLEND_NORMAL:
321             mode = kCGBlendModeNormal;
322             break;
323         case FXDIB_BLEND_MULTIPLY:
324             mode = kCGBlendModeMultiply;
325             break;
326         case FXDIB_BLEND_SCREEN:
327             mode = kCGBlendModeScreen;
328             break;
329         case FXDIB_BLEND_OVERLAY:
330             mode = kCGBlendModeOverlay;
331             break;
332         case FXDIB_BLEND_DARKEN:
333             mode = kCGBlendModeDarken;
334             break;
335         case FXDIB_BLEND_LIGHTEN:
336             mode = kCGBlendModeLighten;
337             break;
338         case FXDIB_BLEND_COLORDODGE:
339             mode = kCGBlendModeColorDodge;
340             break;
341         case FXDIB_BLEND_COLORBURN:
342             mode = kCGBlendModeColorBurn;
343             break;
344         case FXDIB_BLEND_HARDLIGHT:
345             mode = kCGBlendModeHardLight;
346             break;
347         case FXDIB_BLEND_SOFTLIGHT:
348             mode = kCGBlendModeSoftLight;
349             break;
350         case FXDIB_BLEND_DIFFERENCE:
351             mode = kCGBlendModeDifference;
352             break;
353         case FXDIB_BLEND_EXCLUSION:
354             mode = kCGBlendModeExclusion;
355             break;
356         case FXDIB_BLEND_HUE:
357             mode = kCGBlendModeHue;
358             break;
359         case FXDIB_BLEND_SATURATION:
360             mode = kCGBlendModeSaturation;
361             break;
362         case FXDIB_BLEND_COLOR:
363             mode = kCGBlendModeColor;
364             break;
365         case FXDIB_BLEND_LUMINOSITY:
366             mode = kCGBlendModeLuminosity;
367             break;
368         default:
369             mode = kCGBlendModeNormal;
370             break;
371     }
372     return mode;
373 }
374 bool CFX_QuartzDeviceDriver::DrawPath(const CFX_PathData*        pathData,
375         const CFX_AffineMatrix*       matrix,
376         const CFX_GraphStateData*     graphState,
377         FX_DWORD                      fillArgb,
378         FX_DWORD                      strokeArgb,
379         int                           fillMode,
380         int                           alpha_flag,
381         void*                         pIccTransform,
382         int                                                     blend_type
383                                         )
384 {
385     SaveState();
386     CGBlendMode mode = GetCGBlendMode(blend_type);
387     if (mode != kCGBlendModeNormal) {
388         CGContextSetBlendMode(_context, mode);
389     }
390     CGAffineTransform m = CGAffineTransformIdentity;
391     if (matrix) {
392         m = CGAffineTransformMake(matrix->GetA(), matrix->GetB(), matrix->GetC(), matrix->GetD(), matrix->GetE(), matrix->GetF());
393     }
394     m = CGAffineTransformConcat(m, _foxitDevice2User);
395     CGContextConcatCTM(_context, m);
396     int pathMode = 0;
397     if (graphState && strokeArgb) {
398         CGContextSetMiterLimit(_context, graphState->m_MiterLimit);
399         FX_FLOAT lineWidth = getLineWidth(graphState, m);
400         setStrokeInfo(graphState, strokeArgb, lineWidth);
401         pathMode |= 4;
402     }
403     if (fillMode && fillArgb) {
404         setFillInfo(fillArgb);
405         if ((fillMode & 3) == FXFILL_WINDING) {
406             pathMode |= 1;
407         } else if ((fillMode & 3) == FXFILL_ALTERNATE) {
408             pathMode |= 2;
409         }
410     }
411     setPathToContext(pathData);
412     if (fillMode & FXFILL_FULLCOVER) {
413         CGContextSetShouldAntialias(_context, false);
414     }
415     if (pathMode == 4) {
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);
425     }
426     RestoreState(false);
427     return true;
428 }
429 bool CFX_QuartzDeviceDriver::FillRect(const FX_RECT*         rect,
430         FX_ARGB                   fillArgb,
431         int                       alphaFlag        ,
432         void*                     iccTransform ,
433         int                                             blend_type )
434 {
435     CGBlendMode mode = GetCGBlendMode(blend_type);
436     if (mode != kCGBlendModeNormal) {
437         CGContextSetBlendMode(_context, mode);
438     }
439     CGRect rect_fx = CGRectMake(rect->left, rect->top, rect->Width(), rect->Height());
440     CGRect rect_usr = CGRectApplyAffineTransform(rect_fx, _foxitDevice2User);
441     int32_t a, r, g, b;
442     ArgbDecode(fillArgb, a, r, g, b);
443     CGContextSetRGBFillColor(_context,
444                              r / 255.f,
445                              g / 255.f,
446                              b / 255.f,
447                              a / 255.f);
448     CGContextFillRect(_context, rect_usr);
449     if (mode != kCGBlendModeNormal) {
450         CGContextSetBlendMode(_context, kCGBlendModeNormal);
451     }
452     return true;
453 }
454 bool CFX_QuartzDeviceDriver::DrawCosmeticLine(FX_FLOAT           x1,
455         FX_FLOAT              y1,
456         FX_FLOAT              x2,
457         FX_FLOAT              y2,
458         FX_DWORD              argb,
459         int                   alphaFlag       ,
460         void*                 iccTransform    ,
461         int                                     blend_type )
462 {
463     CGBlendMode mode = GetCGBlendMode(blend_type);
464     if (mode != kCGBlendModeNormal) {
465         CGContextSetBlendMode(_context, mode);
466     }
467     CGPoint pt = CGPointApplyAffineTransform(CGPointMake(x1, y1), _foxitDevice2User);
468     x1 = pt.x;
469     y1 = pt.y;
470     pt = CGPointApplyAffineTransform(CGPointMake(x2, y2), _foxitDevice2User);
471     x2 = pt.x;
472     y2 = pt.y;
473     int32_t a, r, g, b;
474     ArgbDecode(argb, a, r, g, b);
475     CGContextSetRGBStrokeColor(_context,
476                                r / 255.f,
477                                g / 255.f,
478                                b / 255.f,
479                                a / 255.f);
480     CGContextMoveToPoint(_context, x1, y1);
481     CGContextAddLineToPoint(_context, x2, y2);
482     CGContextStrokePath(_context);
483     if (mode != kCGBlendModeNormal) {
484         CGContextSetBlendMode(_context, kCGBlendModeNormal);
485     }
486     return true;
487 }
488 bool CFX_QuartzDeviceDriver::GetClipBox(FX_RECT* rect)
489 {
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);
496     return true;
497 }
498 bool CFX_QuartzDeviceDriver::GetDIBits(CFX_DIBitmap*     bitmap,
499         int32_t            left,
500         int32_t            top,
501         void* pIccTransform,
502         bool bDEdge)
503 {
504     if (FXDC_PRINTER == _deviceClass) {
505         return false;
506     }
507     if (bitmap->GetBPP() < 32) {
508         return false;
509     }
510     if (!(_renderCaps | FXRC_GET_BITS)) {
511         return false;
512     }
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);
519     if (NULL == image) {
520         return false;
521     }
522     CGFloat width       = (CGFloat) bitmap->GetWidth();
523     CGFloat height      = (CGFloat) bitmap->GetHeight();
524     if (width + pt.x > _width) {
525         width -= (width + pt.x - _width);
526     }
527     if (height + pt.y > _height) {
528         height -= (height + pt.y - _height);
529     }
530     CGImageRef subImage = CGImageCreateWithImageInRect(image,
531                           CGRectMake(pt.x,
532                                      pt.y,
533                                      width,
534                                      height));
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             uint8_t* pScanline = (uint8_t*)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);
550                 }
551                 pScanline += 4;
552             }
553         }
554     }
555     return true;
556 }
557 bool CFX_QuartzDeviceDriver::SetDIBits(const CFX_DIBSource*      pBitmap,
558         FX_ARGB                     argb,
559         const FX_RECT*              srcRect,
560         int                         dest_left,
561         int                         dest_top,
562         int                         blendType,
563         int                         alphaFlag       ,
564         void*                       iccTransform    )
565 {
566     SaveState();
567     CGFloat src_left, src_top, src_width, src_height;
568     if (srcRect) {
569         src_left = srcRect->left;
570         src_top = srcRect->top;
571         src_width = srcRect->Width();
572         src_height = srcRect->Height();
573     } else {
574         src_left = src_top = 0;
575         src_width = pBitmap->GetWidth();
576         src_height = pBitmap->GetHeight();
577     }
578     CGAffineTransform ctm = CGContextGetCTM(_context);
579     CGFloat scale_x = FXSYS_fabs(ctm.a);
580     CGFloat scale_y = FXSYS_fabs(ctm.d);
581     src_left /= scale_x;
582     src_top /= scale_y;
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;
597         } else {
598             pBitmap1 = pBitmap->Clone();
599         }
600         if (NULL == pBitmap1) {
601             RestoreState(false);
602             return false;
603         }
604         CGDataProviderRef pBitmapProvider = CGDataProviderCreateWithData(NULL,
605                                             pBitmap1->GetBuffer(),
606                                             pBitmap1->GetPitch() * pBitmap1->GetHeight(),
607                                             NULL);
608         CGColorSpaceRef pColorSpace = CGColorSpaceCreateDeviceGray();
609         CGBitmapInfo bitmapInfo = kCGImageAlphaNone | kCGBitmapByteOrderDefault;
610         CGImageRef pImage = CGImageCreate(pBitmap1->GetWidth(),
611                                           pBitmap1->GetHeight(),
612                                           pBitmap1->GetBPP(),
613                                           pBitmap1->GetBPP(),
614                                           pBitmap1->GetPitch(),
615                                           pColorSpace,
616                                           bitmapInfo,
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) {
630             delete pBitmap1;
631         }
632         RestoreState(false);
633         return true;
634     }
635     if (pBitmap->GetBPP() < 32) {
636         pBitmap1 = pBitmap->CloneConvert(FXDIB_Rgb32);
637     } else {
638         if (pBitmap->GetBuffer()) {
639             pBitmap1 = (CFX_DIBitmap*)pBitmap;
640         } else {
641             pBitmap1 = pBitmap->Clone();
642         }
643     }
644     if (NULL == pBitmap1) {
645         RestoreState(false);
646         return false;
647     }
648     if (pBitmap1->HasAlpha()) {
649         if (pBitmap1 == pBitmap) {
650             pBitmap1 = pBitmap->Clone();
651             if (!pBitmap1) {
652                 RestoreState(false);
653                 return false;
654             }
655         }
656         for (int row = 0; row < pBitmap1->GetHeight(); row ++) {
657             uint8_t* pScanline = (uint8_t*)pBitmap1->GetScanline(row);
658             for (int col = 0; col < pBitmap1->GetWidth(); col ++) {
659                 pScanline[0] = (uint8_t)(pScanline[0] * pScanline[3] / 255.f + .5f);
660                 pScanline[1] = (uint8_t)(pScanline[1] * pScanline[3] / 255.f + .5f);
661                 pScanline[2] = (uint8_t)(pScanline[2] * pScanline[3] / 255.f + .5f);
662                 pScanline += 4;
663             }
664         }
665     }
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;
677     }
678     CGContextSetBlendMode(_context, (CGBlendMode)blend_mode);
679     CGContextDrawImage(_context, rect_usr, image);
680     CGImageRelease(image);
681     CGContextRelease(ctx);
682     if (pBitmap1 != pBitmap) {
683         delete pBitmap1;
684     }
685     RestoreState(false);
686     return true;
687 }
688 bool CFX_QuartzDeviceDriver::StretchDIBits(const CFX_DIBSource*      pBitmap,
689         FX_ARGB                     argb,
690         int                         dest_left,
691         int                         dest_top,
692         int                         dest_width,
693         int                         dest_height,
694         const FX_RECT*              clipRect,
695         FX_DWORD                    flags,
696         int                         alphaFlag      ,
697         void*                       iccTransform ,
698         int                                                     blend_type)
699 {
700     SaveState();
701     if (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);
707     }
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);
714     } else {
715         CGContextSetInterpolationQuality(_context, kCGInterpolationMedium);
716     }
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;
722         } else {
723             pBitmap1 = pBitmap->Clone();
724         }
725         if (NULL == pBitmap1) {
726             RestoreState(false);
727             return false;
728         }
729         CGDataProviderRef pBitmapProvider = CGDataProviderCreateWithData(NULL,
730                                             pBitmap1->GetBuffer(),
731                                             pBitmap1->GetPitch() * pBitmap1->GetHeight(),
732                                             NULL);
733         CGColorSpaceRef pColorSpace = CGColorSpaceCreateDeviceGray();
734         CGBitmapInfo bitmapInfo = kCGImageAlphaNone | kCGBitmapByteOrderDefault;
735         CGImageRef pImage = CGImageCreate(pBitmap1->GetWidth(),
736                                           pBitmap1->GetHeight(),
737                                           pBitmap1->GetBPP(),
738                                           pBitmap1->GetBPP(),
739                                           pBitmap1->GetPitch(),
740                                           pColorSpace,
741                                           bitmapInfo,
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) {
755             delete pBitmap1;
756         }
757         RestoreState(false);
758         return true;
759     }
760     if (pBitmap->GetBPP() < 32) {
761         pBitmap1 = pBitmap->CloneConvert(FXDIB_Rgb32);
762     } else {
763         if (pBitmap->GetBuffer()) {
764             pBitmap1 = (CFX_DIBitmap*)pBitmap;
765         } else {
766             pBitmap1 = pBitmap->Clone();
767         }
768     }
769     if (NULL == pBitmap1) {
770         RestoreState(false);
771         return false;
772     }
773     if (pBitmap1->HasAlpha()) {
774         if (pBitmap1 == pBitmap) {
775             pBitmap1 = pBitmap->Clone();
776             if (!pBitmap1) {
777                 RestoreState(false);
778                 return false;
779             }
780         }
781         for (int row = 0; row < pBitmap1->GetHeight(); row ++) {
782             uint8_t* pScanline = (uint8_t*)pBitmap1->GetScanline(row);
783             for (int col = 0; col < pBitmap1->GetWidth(); col ++) {
784                 pScanline[0] = (uint8_t)(pScanline[0] * pScanline[3] / 255.f + .5f);
785                 pScanline[1] = (uint8_t)(pScanline[1] * pScanline[3] / 255.f + .5f);
786                 pScanline[2] = (uint8_t)(pScanline[2] * pScanline[3] / 255.f + .5f);
787                 pScanline += 4;
788             }
789         }
790     }
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) {
797         delete pBitmap1;
798     }
799     RestoreState(false);
800     return true;
801 }
802 bool CFX_QuartzDeviceDriver::CG_DrawGlypRun(int                        nChars,
803         const FXTEXT_CHARPOS*      pCharPos,
804         CFX_Font*                  pFont,
805         CFX_FontCache*             pCache,
806         const CFX_AffineMatrix*    pGlyphMatrix,
807         const CFX_AffineMatrix*    pObject2Device,
808         FX_FLOAT                   font_size,
809         FX_DWORD                   argb,
810         int                        alpha_flag,
811         void*                      pIccTransform)
812 {
813     if (nChars == 0) {
814         return true;
815     }
816     CQuartz2D& quartz2d = ((CApplePlatform *) CFX_GEModule::Get()->GetPlatformData())->_quartz2d;
817     if (!pFont->m_pPlatformFont) {
818         if (pFont->GetPsName() == CFX_WideString::FromLocal("DFHeiStd-W5")) {
819             return false;
820         }
821         pFont->m_pPlatformFont = quartz2d.CreateFont(pFont->m_pFontData, pFont->m_dwSize);
822         if (NULL == pFont->m_pPlatformFont) {
823             return false;
824         }
825     }
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;
832     }
833     CFX_AffineMatrix text_matrix;
834     if (pObject2Device) {
835         text_matrix.Concat(*pObject2Device);
836     }
837     CGAffineTransform matrix_cg = CGAffineTransformMake(text_matrix.a,
838                                   text_matrix.b,
839                                   text_matrix.c,
840                                   text_matrix.d,
841                                   text_matrix.e,
842                                   text_matrix.f);
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));
847     int32_t a, r, g, b;
848     ArgbDecode(argb, a, r, g, b);
849     CGContextSetRGBFillColor(_context,
850                              r / 255.f,
851                              g / 255.f,
852                              b / 255.f,
853                              a / 255.f);
854     SaveState();
855     if (pGlyphMatrix) {
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,
860                                          pGlyphMatrix->b,
861                                          pGlyphMatrix->c,
862                                          pGlyphMatrix->d,
863                                          pGlyphMatrix->e,
864                                          pGlyphMatrix->f);
865         if (_foxitDevice2User.d < 0) {
866             glyph_matrix = CGAffineTransformInvert(glyph_matrix);
867         }
868         CGContextConcatCTM(_context, glyph_matrix);
869         CGContextTranslateCTM(_context, -origin.x, -origin.y);
870     }
871     CGContextShowGlyphsAtPositions(_context,
872                                    (CGGlyph*)glyph_indices,
873                                    glyph_positions,
874                                    nChars);
875     RestoreState(false);
876     return true;
877 }
878 bool CFX_QuartzDeviceDriver::DrawDeviceText(int                      nChars,
879         const FXTEXT_CHARPOS*    pCharPos,
880         CFX_Font*                pFont,
881         CFX_FontCache*           pCache,
882         const CFX_AffineMatrix*  pObject2Device,
883         FX_FLOAT                 font_size,
884         FX_DWORD                 color,
885         int                      alpha_flag       ,
886         void*                    pIccTransform)
887 {
888     if (NULL == pFont || NULL == _context) {
889         return false;
890     }
891     bool bBold = pFont->IsBold();
892     if (!bBold && pFont->GetSubstFont() &&
893             pFont->GetSubstFont()->m_Weight >= 500 &&
894             pFont->GetSubstFont()->m_Weight <= 600) {
895         return false;
896     }
897     SaveState();
898     CGContextSetTextDrawingMode(_context, kCGTextFillClip);
899     bool ret = false;
900     int32_t i = 0;
901     while (i < nChars) {
902         if (pCharPos[i].m_bGlyphAdjust || font_size < 0) {
903             if (i > 0) {
904                 ret = CG_DrawGlypRun(i, pCharPos, pFont, pCache, NULL, pObject2Device, font_size, color, alpha_flag, pIccTransform);
905                 if (!ret) {
906                     RestoreState(false);
907                     return ret;
908                 }
909             }
910             const FXTEXT_CHARPOS* char_pos = pCharPos + i;
911             CFX_AffineMatrix glphy_matrix;
912             if (font_size < 0) {
913                 glphy_matrix.Concat(-1, 0, 0, -1, 0, 0);
914             }
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);
920             }
921             ret = CG_DrawGlypRun(1, char_pos, pFont, pCache, &glphy_matrix, pObject2Device, font_size, color, alpha_flag, pIccTransform);
922             if (!ret) {
923                 RestoreState(false);
924                 return ret;
925             }
926             i ++;
927             pCharPos += i;
928             nChars -= i;
929             i = 0;
930         } else {
931             i ++;
932         }
933     }
934     if (i > 0) {
935         ret = CG_DrawGlypRun(i, pCharPos, pFont, pCache, NULL, pObject2Device, font_size, color, alpha_flag, pIccTransform);
936     }
937     RestoreState(false);
938     return ret;
939 }
940 void CFX_QuartzDeviceDriver::setStrokeInfo(const CFX_GraphStateData* graphState, FX_ARGB argb, FX_FLOAT lineWidth)
941 {
942     if (NULL == graphState) {
943         return;
944     }
945     CGContextSetLineWidth(_context, lineWidth);
946     CGLineCap cap;
947     switch (graphState->m_LineCap) {
948         case CFX_GraphStateData::LineCapRound: {
949                 cap = kCGLineCapRound;
950                 break;
951             }
952         case CFX_GraphStateData::LineCapSquare: {
953                 cap = kCGLineCapSquare;
954                 break;
955             }
956         case CFX_GraphStateData::LineCapButt:
957         default: {
958                 cap = kCGLineCapButt;
959             }
960     }
961     CGContextSetLineCap(_context, cap);
962     CGLineJoin join;
963     switch (graphState->m_LineJoin) {
964         case CFX_GraphStateData::LineJoinRound: {
965                 join = kCGLineJoinRound;
966                 break;
967             }
968         case CFX_GraphStateData::LineJoinBevel: {
969                 join = kCGLineJoinBevel;
970                 break;
971             }
972         case CFX_GraphStateData::LineJoinMiter:
973         default: {
974                 join = kCGLineJoinMiter;
975             }
976     }
977     CGContextSetLineJoin(_context, join);
978     if (graphState->m_DashCount) {
979 #if CGFLOAT_IS_DOUBLE
980         CGFloat* dashArray = new CGFloat[graphState->m_DashCount];
981         if (!dashArray) {
982             return;
983         }
984         for (int index = 0; index < graphState->m_DashCount; ++index) {
985             dashArray[index] = graphState->m_DashArray[index];
986         }
987 #else
988         CGFloat* dashArray = (CGFloat*)graphState->m_DashArray;
989 #endif
990         CGContextSetLineDash(_context, graphState->m_DashPhase, dashArray, graphState->m_DashCount);
991 #if CGFLOAT_IS_DOUBLE
992         delete[] dashArray;
993 #endif
994     }
995     int32_t a, r, g, b;
996     ArgbDecode(argb, a, r, g, b);
997     CGContextSetRGBStrokeColor(_context,
998                                r / 255.f,
999                                g / 255.f,
1000                                b / 255.f,
1001                                a / 255.f);
1002 }
1003 void CFX_QuartzDeviceDriver::setFillInfo(FX_ARGB argb)
1004 {
1005     int32_t a, r, g, b;
1006     ArgbDecode(argb, a, r, g, b);
1007     CGContextSetRGBFillColor(_context,
1008                              r / 255.f,
1009                              g / 255.f,
1010                              b / 255.f,
1011                              a / 255.f);
1012 }
1013 void CFX_QuartzDeviceDriver::setPathToContext(const CFX_PathData* pathData)
1014 {
1015     int32_t count = pathData->GetPointCount();
1016     FX_PATHPOINT* points = pathData->GetPoints();
1017     CGContextBeginPath(_context);
1018     for (int32_t i = 0; i < count; i ++) {
1019         switch (points[i].m_Flag & FXPT_TYPE) {
1020             case FXPT_MOVETO:
1021                 CGContextMoveToPoint(_context, points[i].m_PointX, points[i].m_PointY);
1022                 break;
1023             case FXPT_LINETO:
1024                 CGContextAddLineToPoint(_context, points[i].m_PointX, points[i].m_PointY);
1025                 break;
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);
1031                     i += 2;
1032                 }
1033         }
1034         if (points[i].m_Flag & FXPT_CLOSEFIGURE) {
1035             CGContextClosePath(_context);
1036         }
1037     }
1038 }
1039 void CFX_QuartzDeviceDriver::CG_SetImageTransform(int dest_left, int dest_top, int dest_width, int dest_height,
1040         CGRect* rect )
1041 {
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;
1048         }
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);
1057         if (rect) {
1058             *rect = CGRectApplyAffineTransform(*rect, transform);
1059         }
1060     }
1061 }
1062 void CFX_QuartzDeviceDriver::ClearDriver()
1063 {
1064     if (NULL == _context) {
1065         return;
1066     }
1067     for (int i = 0; i < m_saveCount; ++i) {
1068         CGContextRestoreGState(_context);
1069     }
1070     m_saveCount = 0;
1071     if (_context) {
1072         CGContextRelease(_context);
1073     }
1074 }
1075 CFX_QuartzDevice::CFX_QuartzDevice()
1076 {
1077     m_bOwnedBitmap = false;
1078     m_pContext = NULL;
1079 }
1080 CFX_QuartzDevice::~CFX_QuartzDevice()
1081 {
1082     if (m_pContext) {
1083         CGContextRelease(m_pContext);
1084     }
1085     if (m_bOwnedBitmap) {
1086         delete GetBitmap();
1087     }
1088 }
1089 CGContextRef CFX_QuartzDevice::GetContext()
1090 {
1091     return m_pContext;
1092 }
1093 bool CFX_QuartzDevice::Attach(CGContextRef context, int32_t nDeviceClass)
1094 {
1095     if (m_pContext) {
1096         CGContextRelease(m_pContext);
1097     }
1098     m_pContext = context;
1099     CGContextRetain(m_pContext);
1100     IFX_RenderDeviceDriver* pDriver = new CFX_QuartzDeviceDriver(m_pContext, nDeviceClass);
1101     SetDeviceDriver(pDriver);
1102     return true;
1103 }
1104 bool CFX_QuartzDevice::Attach(CFX_DIBitmap* pBitmap)
1105 {
1106     SetBitmap(pBitmap);
1107     m_pContext = createContextWithBitmap(pBitmap);
1108     if (NULL == m_pContext) {
1109         return false;
1110     }
1111     IFX_RenderDeviceDriver* pDriver = new CFX_QuartzDeviceDriver(m_pContext, FXDC_DISPLAY);
1112     SetDeviceDriver(pDriver);
1113     return true;
1114 }
1115 bool CFX_QuartzDevice::Create(int32_t width, int32_t height, FXDIB_Format format)
1116 {
1117     if ((uint8_t)format < 32) {
1118         return false;
1119     }
1120     CFX_DIBitmap* pBitmap = new CFX_DIBitmap;
1121     if (!pBitmap->Create(width, height, format)) {
1122         delete pBitmap;
1123         return false;
1124     }
1125     m_bOwnedBitmap = true;
1126     return Attach(pBitmap);
1127 }
1128 #endif  // _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_