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 "core/include/fxcrt/fx_ext.h"
8 #include "core/include/fxge/fx_freetype.h"
9 #include "core/include/fxge/fx_ge.h"
10 #include "core/src/fxge/agg/include/fx_agg_driver.h"
11 #include "core/src/fxge/dib/dib_int.h"
12 #include "core/src/fxge/ge/text_int.h"
13 
14 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
15 #include "apple_int.h"
16 #include "core/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 
createGraphics(CFX_DIBitmap * pBitmap)21 void* CQuartz2D::createGraphics(CFX_DIBitmap* pBitmap) {
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(
36       pBitmap->GetBuffer(), pBitmap->GetWidth(), pBitmap->GetHeight(), 8,
37       pBitmap->GetPitch(), colorSpace, bmpInfo);
38   CGColorSpaceRelease(colorSpace);
39   return context;
40 }
destroyGraphics(void * graphics)41 void CQuartz2D::destroyGraphics(void* graphics) {
42   if (graphics) {
43     CGContextRelease((CGContextRef)graphics);
44   }
45 }
CreateFont(const uint8_t * pFontData,FX_DWORD dwFontSize)46 void* CQuartz2D::CreateFont(const uint8_t* pFontData, FX_DWORD dwFontSize) {
47   CGDataProviderRef pDataProvider =
48       CGDataProviderCreateWithData(NULL, pFontData, (size_t)dwFontSize, NULL);
49   if (NULL == pDataProvider) {
50     return NULL;
51   }
52   CGFontRef pCGFont = CGFontCreateWithDataProvider(pDataProvider);
53   CGDataProviderRelease(pDataProvider);
54   return pCGFont;
55 }
DestroyFont(void * pFont)56 void CQuartz2D::DestroyFont(void* pFont) {
57   CGFontRelease((CGFontRef)pFont);
58 }
setGraphicsTextMatrix(void * graphics,CFX_Matrix * matrix)59 void CQuartz2D::setGraphicsTextMatrix(void* graphics, CFX_Matrix* matrix) {
60   if (!graphics || !matrix) {
61     return;
62   }
63   CGContextRef context = (CGContextRef)graphics;
64   CGFloat ty = CGBitmapContextGetHeight(context) - matrix->f;
65   CGContextSetTextMatrix(
66       context, CGAffineTransformMake(matrix->a, matrix->b, matrix->c, matrix->d,
67                                      matrix->e, ty));
68 }
drawGraphicsString(void * graphics,void * font,FX_FLOAT fontSize,FX_WORD * glyphIndices,CGPoint * glyphPositions,int32_t charsCount,FX_ARGB argb,CFX_Matrix * matrix)69 FX_BOOL CQuartz2D::drawGraphicsString(void* graphics,
70                                       void* font,
71                                       FX_FLOAT fontSize,
72                                       FX_WORD* glyphIndices,
73                                       CGPoint* glyphPositions,
74                                       int32_t charsCount,
75                                       FX_ARGB argb,
76                                       CFX_Matrix* matrix) {
77   if (!graphics) {
78     return FALSE;
79   }
80   CGContextRef context = (CGContextRef)graphics;
81   CGContextSetFont(context, (CGFontRef)font);
82   CGContextSetFontSize(context, fontSize);
83   if (matrix) {
84     CGAffineTransform m = CGContextGetTextMatrix(context);
85     m = CGAffineTransformConcat(
86         m, CGAffineTransformMake(matrix->a, matrix->b, matrix->c, matrix->d,
87                                  matrix->e, matrix->f));
88     CGContextSetTextMatrix(context, m);
89   }
90   int32_t a, r, g, b;
91   ArgbDecode(argb, a, r, g, b);
92   CGContextSetRGBFillColor(context, r / 255.f, g / 255.f, b / 255.f, a / 255.f);
93   CGContextSaveGState(context);
94 #if CGFLOAT_IS_DOUBLE
95   CGPoint* glyphPositionsCG = new CGPoint[charsCount];
96   for (int index = 0; index < charsCount; ++index) {
97     glyphPositionsCG[index].x = glyphPositions[index].x;
98     glyphPositionsCG[index].y = glyphPositions[index].y;
99   }
100 #else
101   CGPoint* glyphPositionsCG = (CGPoint*)glyphPositions;
102 #endif
103   CGContextShowGlyphsAtPositions(context, (CGGlyph*)glyphIndices,
104                                  glyphPositionsCG, charsCount);
105 #if CGFLOAT_IS_DOUBLE
106   delete[] glyphPositionsCG;
107 #endif
108   CGContextRestoreGState(context);
109   return TRUE;
110 }
saveGraphicsState(void * graphics)111 void CQuartz2D::saveGraphicsState(void* graphics) {
112   if (graphics) {
113     CGContextSaveGState((CGContextRef)graphics);
114   }
115 }
restoreGraphicsState(void * graphics)116 void CQuartz2D::restoreGraphicsState(void* graphics) {
117   if (graphics) {
118     CGContextRestoreGState((CGContextRef)graphics);
119   }
120 }
createContextWithBitmap(CFX_DIBitmap * pBitmap)121 static CGContextRef createContextWithBitmap(CFX_DIBitmap* pBitmap) {
122   if (!pBitmap || pBitmap->IsCmykImage() || pBitmap->GetBPP() < 32) {
123     return NULL;
124   }
125   CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little;
126   if (pBitmap->HasAlpha()) {
127     bitmapInfo |= kCGImageAlphaPremultipliedFirst;
128   } else {
129     bitmapInfo |= kCGImageAlphaNoneSkipFirst;
130   }
131   CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
132   CGContextRef context = CGBitmapContextCreate(
133       pBitmap->GetBuffer(), pBitmap->GetWidth(), pBitmap->GetHeight(), 8,
134       pBitmap->GetPitch(), colorSpace, bitmapInfo);
135   CGColorSpaceRelease(colorSpace);
136   return context;
137 }
CFX_QuartzDeviceDriver(CGContextRef context,int32_t deviceClass)138 CFX_QuartzDeviceDriver::CFX_QuartzDeviceDriver(CGContextRef context,
139                                                int32_t deviceClass) {
140   m_saveCount = 0;
141   _context = context;
142   _deviceClass = deviceClass;
143   CGContextRetain(_context);
144   CGRect r = CGContextGetClipBoundingBox(context);
145   _width = FXSYS_round(r.size.width);
146   _height = FXSYS_round(r.size.height);
147   _renderCaps = FXRC_SOFT_CLIP | FXRC_BLEND_MODE | FXRC_ALPHA_PATH |
148                 FXRC_ALPHA_IMAGE | FXRC_BIT_MASK | FXRC_ALPHA_MASK;
149   if (_deviceClass != FXDC_DISPLAY) {
150   } else {
151     CGImageRef image = CGBitmapContextCreateImage(_context);
152     if (image) {
153       _renderCaps |= FXRC_GET_BITS;
154       _width = CGImageGetWidth(image);
155       _height = CGImageGetHeight(image);
156       CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(image);
157       if (kCGImageAlphaPremultipliedFirst == alphaInfo ||
158           kCGImageAlphaPremultipliedLast == alphaInfo ||
159           kCGImageAlphaOnly == alphaInfo) {
160         _renderCaps |= FXRC_ALPHA_OUTPUT;
161       }
162     }
163     CGImageRelease(image);
164   }
165   CGAffineTransform ctm = CGContextGetCTM(_context);
166   CGContextSaveGState(_context);
167   m_saveCount++;
168   if (ctm.d >= 0) {
169     CGFloat offset_x, offset_y;
170     offset_x = ctm.tx;
171     offset_y = ctm.ty;
172     CGContextTranslateCTM(_context, -offset_x, -offset_y);
173     CGContextConcatCTM(_context, CGAffineTransformMake(1, 0, 0, -1, offset_x,
174                                                        _height + offset_y));
175   }
176   _foxitDevice2User = CGAffineTransformIdentity;
177   _user2FoxitDevice = CGAffineTransformInvert(_foxitDevice2User);
178 }
~CFX_QuartzDeviceDriver()179 CFX_QuartzDeviceDriver::~CFX_QuartzDeviceDriver() {
180   CGContextRestoreGState(_context);
181   m_saveCount--;
182   for (int i = 0; i < m_saveCount; ++i) {
183     CGContextRestoreGState(_context);
184   }
185   if (_context) {
186     CGContextRelease(_context);
187   }
188 }
GetDeviceCaps(int capsID)189 int CFX_QuartzDeviceDriver::GetDeviceCaps(int capsID) {
190   switch (capsID) {
191     case FXDC_DEVICE_CLASS: {
192       return _deviceClass;
193     }
194     case FXDC_PIXEL_WIDTH: {
195       return _width;
196     }
197     case FXDC_PIXEL_HEIGHT: {
198       return _height;
199     }
200     case FXDC_BITS_PIXEL: {
201       return 32;
202     }
203     case FXDC_RENDER_CAPS: {
204       return _renderCaps;
205     }
206     default: { return 0; }
207   }
208 }
GetCTM() const209 CFX_Matrix CFX_QuartzDeviceDriver::GetCTM() const {
210   CGAffineTransform ctm = CGContextGetCTM(_context);
211   return CFX_Matrix(ctm.a, ctm.b, ctm.c, ctm.d, ctm.tx, ctm.ty);
212 }
SaveState()213 void CFX_QuartzDeviceDriver::SaveState() {
214   CGContextSaveGState(_context);
215   m_saveCount++;
216 }
RestoreState(FX_BOOL isKeepSaved)217 void CFX_QuartzDeviceDriver::RestoreState(FX_BOOL isKeepSaved) {
218   CGContextRestoreGState(_context);
219   if (isKeepSaved) {
220     CGContextSaveGState(_context);
221   } else {
222     m_saveCount--;
223   }
224 }
SetClip_PathFill(const CFX_PathData * pathData,const CFX_Matrix * matrix,int fillMode)225 FX_BOOL CFX_QuartzDeviceDriver::SetClip_PathFill(const CFX_PathData* pathData,
226                                                  const CFX_Matrix* matrix,
227                                                  int fillMode) {
228   SaveState();
229   CGAffineTransform m = CGAffineTransformIdentity;
230   if (matrix) {
231     m = CGAffineTransformMake(matrix->GetA(), matrix->GetB(), matrix->GetC(),
232                               matrix->GetD(), matrix->GetE(), matrix->GetF());
233   }
234   m = CGAffineTransformConcat(m, _foxitDevice2User);
235   CGContextConcatCTM(_context, m);
236   setPathToContext(pathData);
237   RestoreState(FALSE);
238   if ((fillMode & 3) == FXFILL_WINDING) {
239     CGContextClip(_context);
240   } else {
241     CGContextEOClip(_context);
242   }
243   return TRUE;
244 }
getLineWidth(const CFX_GraphStateData * graphState,CGAffineTransform ctm)245 FX_FLOAT CFX_QuartzDeviceDriver::getLineWidth(
246     const CFX_GraphStateData* graphState,
247     CGAffineTransform ctm) {
248   FX_FLOAT lineWidth = graphState->m_LineWidth;
249   if (graphState->m_LineWidth <= 0.f) {
250     CGSize size;
251     size.width = 1;
252     size.height = 1;
253     CGSize temp = CGSizeApplyAffineTransform(size, ctm);
254     CGFloat x = 1 / temp.width;
255     CGFloat y = 1 / temp.height;
256     lineWidth = x > y ? x : y;
257   }
258   return lineWidth;
259 }
SetClip_PathStroke(const CFX_PathData * pathData,const CFX_Matrix * matrix,const CFX_GraphStateData * graphState)260 FX_BOOL CFX_QuartzDeviceDriver::SetClip_PathStroke(
261     const CFX_PathData* pathData,
262     const CFX_Matrix* matrix,
263     const CFX_GraphStateData* graphState) {
264   SaveState();
265   CGAffineTransform m = CGAffineTransformIdentity;
266   if (matrix) {
267     m = CGAffineTransformMake(matrix->GetA(), matrix->GetB(), matrix->GetC(),
268                               matrix->GetD(), matrix->GetE(), matrix->GetF());
269   }
270   m = CGAffineTransformConcat(m, _foxitDevice2User);
271   CGContextConcatCTM(_context, m);
272   FX_FLOAT lineWidth = getLineWidth(graphState, m);
273   setStrokeInfo(graphState, 0xFF000000, lineWidth);
274   setPathToContext(pathData);
275   CGContextReplacePathWithStrokedPath(_context);
276   RestoreState(FALSE);
277   CGContextClip(_context);
278   return TRUE;
279 }
GetCGBlendMode(int blend_type)280 static CGBlendMode GetCGBlendMode(int blend_type) {
281   CGBlendMode mode = kCGBlendModeNormal;
282   switch (blend_type) {
283     case FXDIB_BLEND_NORMAL:
284       mode = kCGBlendModeNormal;
285       break;
286     case FXDIB_BLEND_MULTIPLY:
287       mode = kCGBlendModeMultiply;
288       break;
289     case FXDIB_BLEND_SCREEN:
290       mode = kCGBlendModeScreen;
291       break;
292     case FXDIB_BLEND_OVERLAY:
293       mode = kCGBlendModeOverlay;
294       break;
295     case FXDIB_BLEND_DARKEN:
296       mode = kCGBlendModeDarken;
297       break;
298     case FXDIB_BLEND_LIGHTEN:
299       mode = kCGBlendModeLighten;
300       break;
301     case FXDIB_BLEND_COLORDODGE:
302       mode = kCGBlendModeColorDodge;
303       break;
304     case FXDIB_BLEND_COLORBURN:
305       mode = kCGBlendModeColorBurn;
306       break;
307     case FXDIB_BLEND_HARDLIGHT:
308       mode = kCGBlendModeHardLight;
309       break;
310     case FXDIB_BLEND_SOFTLIGHT:
311       mode = kCGBlendModeSoftLight;
312       break;
313     case FXDIB_BLEND_DIFFERENCE:
314       mode = kCGBlendModeDifference;
315       break;
316     case FXDIB_BLEND_EXCLUSION:
317       mode = kCGBlendModeExclusion;
318       break;
319     case FXDIB_BLEND_HUE:
320       mode = kCGBlendModeHue;
321       break;
322     case FXDIB_BLEND_SATURATION:
323       mode = kCGBlendModeSaturation;
324       break;
325     case FXDIB_BLEND_COLOR:
326       mode = kCGBlendModeColor;
327       break;
328     case FXDIB_BLEND_LUMINOSITY:
329       mode = kCGBlendModeLuminosity;
330       break;
331     default:
332       mode = kCGBlendModeNormal;
333       break;
334   }
335   return mode;
336 }
DrawPath(const CFX_PathData * pathData,const CFX_Matrix * matrix,const CFX_GraphStateData * graphState,FX_DWORD fillArgb,FX_DWORD strokeArgb,int fillMode,int alpha_flag,void * pIccTransform,int blend_type)337 FX_BOOL CFX_QuartzDeviceDriver::DrawPath(const CFX_PathData* pathData,
338                                          const CFX_Matrix* matrix,
339                                          const CFX_GraphStateData* graphState,
340                                          FX_DWORD fillArgb,
341                                          FX_DWORD strokeArgb,
342                                          int fillMode,
343                                          int alpha_flag,
344                                          void* pIccTransform,
345                                          int blend_type) {
346   SaveState();
347   CGBlendMode mode = GetCGBlendMode(blend_type);
348   if (mode != kCGBlendModeNormal) {
349     CGContextSetBlendMode(_context, mode);
350   }
351   CGAffineTransform m = CGAffineTransformIdentity;
352   if (matrix) {
353     m = CGAffineTransformMake(matrix->GetA(), matrix->GetB(), matrix->GetC(),
354                               matrix->GetD(), matrix->GetE(), matrix->GetF());
355   }
356   m = CGAffineTransformConcat(m, _foxitDevice2User);
357   CGContextConcatCTM(_context, m);
358   int pathMode = 0;
359   if (graphState && strokeArgb) {
360     CGContextSetMiterLimit(_context, graphState->m_MiterLimit);
361     FX_FLOAT lineWidth = getLineWidth(graphState, m);
362     setStrokeInfo(graphState, strokeArgb, lineWidth);
363     pathMode |= 4;
364   }
365   if (fillMode && fillArgb) {
366     setFillInfo(fillArgb);
367     if ((fillMode & 3) == FXFILL_WINDING) {
368       pathMode |= 1;
369     } else if ((fillMode & 3) == FXFILL_ALTERNATE) {
370       pathMode |= 2;
371     }
372   }
373   setPathToContext(pathData);
374   if (fillMode & FXFILL_FULLCOVER) {
375     CGContextSetShouldAntialias(_context, false);
376   }
377   if (pathMode == 4) {
378     CGContextStrokePath(_context);
379   } else if (pathMode == 1) {
380     CGContextFillPath(_context);
381   } else if (pathMode == 2) {
382     CGContextEOFillPath(_context);
383   } else if (pathMode == 5) {
384     CGContextDrawPath(_context, kCGPathFillStroke);
385   } else if (pathMode == 6) {
386     CGContextDrawPath(_context, kCGPathEOFillStroke);
387   }
388   RestoreState(FALSE);
389   return TRUE;
390 }
FillRect(const FX_RECT * rect,FX_ARGB fillArgb,int alphaFlag,void * iccTransform,int blend_type)391 FX_BOOL CFX_QuartzDeviceDriver::FillRect(const FX_RECT* rect,
392                                          FX_ARGB fillArgb,
393                                          int alphaFlag,
394                                          void* iccTransform,
395                                          int blend_type) {
396   CGBlendMode mode = GetCGBlendMode(blend_type);
397   if (mode != kCGBlendModeNormal) {
398     CGContextSetBlendMode(_context, mode);
399   }
400   CGRect rect_fx =
401       CGRectMake(rect->left, rect->top, rect->Width(), rect->Height());
402   CGRect rect_usr = CGRectApplyAffineTransform(rect_fx, _foxitDevice2User);
403   int32_t a, r, g, b;
404   ArgbDecode(fillArgb, a, r, g, b);
405   CGContextSetRGBFillColor(_context, r / 255.f, g / 255.f, b / 255.f,
406                            a / 255.f);
407   CGContextFillRect(_context, rect_usr);
408   if (mode != kCGBlendModeNormal) {
409     CGContextSetBlendMode(_context, kCGBlendModeNormal);
410   }
411   return TRUE;
412 }
DrawCosmeticLine(FX_FLOAT x1,FX_FLOAT y1,FX_FLOAT x2,FX_FLOAT y2,FX_DWORD argb,int alphaFlag,void * iccTransform,int blend_type)413 FX_BOOL CFX_QuartzDeviceDriver::DrawCosmeticLine(FX_FLOAT x1,
414                                                  FX_FLOAT y1,
415                                                  FX_FLOAT x2,
416                                                  FX_FLOAT y2,
417                                                  FX_DWORD argb,
418                                                  int alphaFlag,
419                                                  void* iccTransform,
420                                                  int blend_type) {
421   CGBlendMode mode = GetCGBlendMode(blend_type);
422   if (mode != kCGBlendModeNormal) {
423     CGContextSetBlendMode(_context, mode);
424   }
425   CGPoint pt =
426       CGPointApplyAffineTransform(CGPointMake(x1, y1), _foxitDevice2User);
427   x1 = pt.x;
428   y1 = pt.y;
429   pt = CGPointApplyAffineTransform(CGPointMake(x2, y2), _foxitDevice2User);
430   x2 = pt.x;
431   y2 = pt.y;
432   int32_t a, r, g, b;
433   ArgbDecode(argb, a, r, g, b);
434   CGContextSetRGBStrokeColor(_context, r / 255.f, g / 255.f, b / 255.f,
435                              a / 255.f);
436   CGContextMoveToPoint(_context, x1, y1);
437   CGContextAddLineToPoint(_context, x2, y2);
438   CGContextStrokePath(_context);
439   if (mode != kCGBlendModeNormal) {
440     CGContextSetBlendMode(_context, kCGBlendModeNormal);
441   }
442   return TRUE;
443 }
GetClipBox(FX_RECT * rect)444 FX_BOOL CFX_QuartzDeviceDriver::GetClipBox(FX_RECT* rect) {
445   CGRect r = CGContextGetClipBoundingBox(_context);
446   r = CGRectApplyAffineTransform(r, _user2FoxitDevice);
447   rect->left = FXSYS_floor(r.origin.x);
448   rect->top = FXSYS_floor(r.origin.y);
449   rect->right = FXSYS_ceil(r.origin.x + r.size.width);
450   rect->bottom = FXSYS_ceil(r.origin.y + r.size.height);
451   return TRUE;
452 }
GetDIBits(CFX_DIBitmap * bitmap,int32_t left,int32_t top,void * pIccTransform,FX_BOOL bDEdge)453 FX_BOOL CFX_QuartzDeviceDriver::GetDIBits(CFX_DIBitmap* bitmap,
454                                           int32_t left,
455                                           int32_t top,
456                                           void* pIccTransform,
457                                           FX_BOOL bDEdge) {
458   if (FXDC_PRINTER == _deviceClass) {
459     return FALSE;
460   }
461   if (bitmap->GetBPP() < 32) {
462     return FALSE;
463   }
464   if (!(_renderCaps | FXRC_GET_BITS)) {
465     return FALSE;
466   }
467   CGPoint pt = CGPointMake(left, top);
468   pt = CGPointApplyAffineTransform(pt, _foxitDevice2User);
469   CGAffineTransform ctm = CGContextGetCTM(_context);
470   pt.x *= FXSYS_fabs(ctm.a);
471   pt.y *= FXSYS_fabs(ctm.d);
472   CGImageRef image = CGBitmapContextCreateImage(_context);
473   if (NULL == image) {
474     return FALSE;
475   }
476   CGFloat width = (CGFloat)bitmap->GetWidth();
477   CGFloat height = (CGFloat)bitmap->GetHeight();
478   if (width + pt.x > _width) {
479     width -= (width + pt.x - _width);
480   }
481   if (height + pt.y > _height) {
482     height -= (height + pt.y - _height);
483   }
484   CGImageRef subImage = CGImageCreateWithImageInRect(
485       image, CGRectMake(pt.x, pt.y, width, height));
486   CGContextRef context = createContextWithBitmap(bitmap);
487   CGRect rect = CGContextGetClipBoundingBox(context);
488   CGContextClearRect(context, rect);
489   CGContextDrawImage(context, rect, subImage);
490   CGContextRelease(context);
491   CGImageRelease(subImage);
492   CGImageRelease(image);
493   if (bitmap->HasAlpha()) {
494     for (int row = 0; row < bitmap->GetHeight(); row++) {
495       uint8_t* pScanline = (uint8_t*)bitmap->GetScanline(row);
496       for (int col = 0; col < bitmap->GetWidth(); col++) {
497         if (pScanline[3] > 0) {
498           pScanline[0] = (pScanline[0] * 255.f / pScanline[3] + .5f);
499           pScanline[1] = (pScanline[1] * 255.f / pScanline[3] + .5f);
500           pScanline[2] = (pScanline[2] * 255.f / pScanline[3] + .5f);
501         }
502         pScanline += 4;
503       }
504     }
505   }
506   return TRUE;
507 }
SetDIBits(const CFX_DIBSource * pBitmap,FX_ARGB argb,const FX_RECT * srcRect,int dest_left,int dest_top,int blendType,int alphaFlag,void * iccTransform)508 FX_BOOL CFX_QuartzDeviceDriver::SetDIBits(const CFX_DIBSource* pBitmap,
509                                           FX_ARGB argb,
510                                           const FX_RECT* srcRect,
511                                           int dest_left,
512                                           int dest_top,
513                                           int blendType,
514                                           int alphaFlag,
515                                           void* iccTransform) {
516   SaveState();
517   CGFloat src_left, src_top, src_width, src_height;
518   if (srcRect) {
519     src_left = srcRect->left;
520     src_top = srcRect->top;
521     src_width = srcRect->Width();
522     src_height = srcRect->Height();
523   } else {
524     src_left = src_top = 0;
525     src_width = pBitmap->GetWidth();
526     src_height = pBitmap->GetHeight();
527   }
528   CGAffineTransform ctm = CGContextGetCTM(_context);
529   CGFloat scale_x = FXSYS_fabs(ctm.a);
530   CGFloat scale_y = FXSYS_fabs(ctm.d);
531   src_left /= scale_x;
532   src_top /= scale_y;
533   src_width /= scale_x;
534   src_height /= scale_y;
535   CGRect rect_fx = CGRectMake(dest_left, dest_top, src_width, src_height);
536   CGRect rect_usr = CGRectApplyAffineTransform(rect_fx, _foxitDevice2User);
537   CGContextBeginPath(_context);
538   CGContextAddRect(_context, rect_usr);
539   CGContextClip(_context);
540   rect_usr.size =
541       CGSizeMake(pBitmap->GetWidth() / scale_x, pBitmap->GetHeight() / scale_y);
542   rect_usr = CGRectOffset(rect_usr, -src_left, -src_top);
543   CG_SetImageTransform(dest_left, dest_top, src_width, src_height, &rect_usr);
544   CFX_DIBitmap* pBitmap1 = NULL;
545   if (pBitmap->IsAlphaMask()) {
546     if (pBitmap->GetBuffer()) {
547       pBitmap1 = (CFX_DIBitmap*)pBitmap;
548     } else {
549       pBitmap1 = pBitmap->Clone();
550     }
551     if (NULL == pBitmap1) {
552       RestoreState(FALSE);
553       return FALSE;
554     }
555     CGDataProviderRef pBitmapProvider = CGDataProviderCreateWithData(
556         NULL, pBitmap1->GetBuffer(),
557         pBitmap1->GetPitch() * pBitmap1->GetHeight(), NULL);
558     CGColorSpaceRef pColorSpace = CGColorSpaceCreateDeviceGray();
559     CGBitmapInfo bitmapInfo = kCGImageAlphaNone | kCGBitmapByteOrderDefault;
560     CGImageRef pImage = CGImageCreate(
561         pBitmap1->GetWidth(), pBitmap1->GetHeight(), pBitmap1->GetBPP(),
562         pBitmap1->GetBPP(), pBitmap1->GetPitch(), pColorSpace, bitmapInfo,
563         pBitmapProvider, NULL, true, kCGRenderingIntentDefault);
564     CGContextClipToMask(_context, rect_usr, pImage);
565     CGContextSetRGBFillColor(_context, FXARGB_R(argb) / 255.f,
566                              FXARGB_G(argb) / 255.f, FXARGB_B(argb) / 255.f,
567                              FXARGB_A(argb) / 255.f);
568     CGContextFillRect(_context, rect_usr);
569     CGImageRelease(pImage);
570     CGColorSpaceRelease(pColorSpace);
571     CGDataProviderRelease(pBitmapProvider);
572     if (pBitmap1 != pBitmap) {
573       delete pBitmap1;
574     }
575     RestoreState(FALSE);
576     return TRUE;
577   }
578   if (pBitmap->GetBPP() < 32) {
579     pBitmap1 = pBitmap->CloneConvert(FXDIB_Rgb32);
580   } else {
581     if (pBitmap->GetBuffer()) {
582       pBitmap1 = (CFX_DIBitmap*)pBitmap;
583     } else {
584       pBitmap1 = pBitmap->Clone();
585     }
586   }
587   if (NULL == pBitmap1) {
588     RestoreState(FALSE);
589     return FALSE;
590   }
591   if (pBitmap1->HasAlpha()) {
592     if (pBitmap1 == pBitmap) {
593       pBitmap1 = pBitmap->Clone();
594       if (!pBitmap1) {
595         RestoreState(FALSE);
596         return FALSE;
597       }
598     }
599     for (int row = 0; row < pBitmap1->GetHeight(); row++) {
600       uint8_t* pScanline = (uint8_t*)pBitmap1->GetScanline(row);
601       for (int col = 0; col < pBitmap1->GetWidth(); col++) {
602         pScanline[0] = (uint8_t)(pScanline[0] * pScanline[3] / 255.f + .5f);
603         pScanline[1] = (uint8_t)(pScanline[1] * pScanline[3] / 255.f + .5f);
604         pScanline[2] = (uint8_t)(pScanline[2] * pScanline[3] / 255.f + .5f);
605         pScanline += 4;
606       }
607     }
608   }
609   CGContextRef ctx = createContextWithBitmap(pBitmap1);
610   CGImageRef image = CGBitmapContextCreateImage(ctx);
611   int blend_mode = blendType;
612   if (FXDIB_BLEND_HARDLIGHT == blendType) {
613     blend_mode = kCGBlendModeSoftLight;
614   } else if (FXDIB_BLEND_SOFTLIGHT == blendType) {
615     blend_mode = kCGBlendModeHardLight;
616   } else if (blendType >= FXDIB_BLEND_NONSEPARABLE &&
617              blendType <= FXDIB_BLEND_LUMINOSITY) {
618     blend_mode = blendType - 9;
619   } else if (blendType > FXDIB_BLEND_LUMINOSITY || blendType < 0) {
620     blend_mode = kCGBlendModeNormal;
621   }
622   CGContextSetBlendMode(_context, (CGBlendMode)blend_mode);
623   CGContextDrawImage(_context, rect_usr, image);
624   CGImageRelease(image);
625   CGContextRelease(ctx);
626   if (pBitmap1 != pBitmap) {
627     delete pBitmap1;
628   }
629   RestoreState(FALSE);
630   return TRUE;
631 }
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)632 FX_BOOL CFX_QuartzDeviceDriver::StretchDIBits(const CFX_DIBSource* pBitmap,
633                                               FX_ARGB argb,
634                                               int dest_left,
635                                               int dest_top,
636                                               int dest_width,
637                                               int dest_height,
638                                               const FX_RECT* clipRect,
639                                               FX_DWORD flags,
640                                               int alphaFlag,
641                                               void* iccTransform,
642                                               int blend_type) {
643   SaveState();
644   if (clipRect) {
645     CGContextBeginPath(_context);
646     CGRect rect_clip = CGRectMake(clipRect->left, clipRect->top,
647                                   clipRect->Width(), clipRect->Height());
648     rect_clip = CGRectApplyAffineTransform(rect_clip, _foxitDevice2User);
649     CGContextAddRect(_context, rect_clip);
650     CGContextClip(_context);
651   }
652   CGRect rect = CGRectMake(dest_left, dest_top, dest_width, dest_height);
653   rect = CGRectApplyAffineTransform(rect, _foxitDevice2User);
654   if (FXDIB_BICUBIC_INTERPOL == flags) {
655     CGContextSetInterpolationQuality(_context, kCGInterpolationHigh);
656   } else if (FXDIB_DOWNSAMPLE == flags) {
657     CGContextSetInterpolationQuality(_context, kCGInterpolationNone);
658   } else {
659     CGContextSetInterpolationQuality(_context, kCGInterpolationMedium);
660   }
661   CG_SetImageTransform(dest_left, dest_top, dest_width, dest_height);
662   CFX_DIBitmap* pBitmap1 = NULL;
663   if (pBitmap->IsAlphaMask()) {
664     if (pBitmap->GetBuffer()) {
665       pBitmap1 = (CFX_DIBitmap*)pBitmap;
666     } else {
667       pBitmap1 = pBitmap->Clone();
668     }
669     if (NULL == pBitmap1) {
670       RestoreState(FALSE);
671       return FALSE;
672     }
673     CGDataProviderRef pBitmapProvider = CGDataProviderCreateWithData(
674         NULL, pBitmap1->GetBuffer(),
675         pBitmap1->GetPitch() * pBitmap1->GetHeight(), NULL);
676     CGColorSpaceRef pColorSpace = CGColorSpaceCreateDeviceGray();
677     CGBitmapInfo bitmapInfo = kCGImageAlphaNone | kCGBitmapByteOrderDefault;
678     CGImageRef pImage = CGImageCreate(
679         pBitmap1->GetWidth(), pBitmap1->GetHeight(), pBitmap1->GetBPP(),
680         pBitmap1->GetBPP(), pBitmap1->GetPitch(), pColorSpace, bitmapInfo,
681         pBitmapProvider, NULL, true, kCGRenderingIntentDefault);
682     CGContextClipToMask(_context, rect, pImage);
683     CGContextSetRGBFillColor(_context, FXARGB_R(argb) / 255.f,
684                              FXARGB_G(argb) / 255.f, FXARGB_B(argb) / 255.f,
685                              FXARGB_A(argb) / 255.f);
686     CGContextFillRect(_context, rect);
687     CGImageRelease(pImage);
688     CGColorSpaceRelease(pColorSpace);
689     CGDataProviderRelease(pBitmapProvider);
690     if (pBitmap1 != pBitmap) {
691       delete pBitmap1;
692     }
693     RestoreState(FALSE);
694     return TRUE;
695   }
696   if (pBitmap->GetBPP() < 32) {
697     pBitmap1 = pBitmap->CloneConvert(FXDIB_Rgb32);
698   } else {
699     if (pBitmap->GetBuffer()) {
700       pBitmap1 = (CFX_DIBitmap*)pBitmap;
701     } else {
702       pBitmap1 = pBitmap->Clone();
703     }
704   }
705   if (NULL == pBitmap1) {
706     RestoreState(FALSE);
707     return FALSE;
708   }
709   if (pBitmap1->HasAlpha()) {
710     if (pBitmap1 == pBitmap) {
711       pBitmap1 = pBitmap->Clone();
712       if (!pBitmap1) {
713         RestoreState(FALSE);
714         return FALSE;
715       }
716     }
717     for (int row = 0; row < pBitmap1->GetHeight(); row++) {
718       uint8_t* pScanline = (uint8_t*)pBitmap1->GetScanline(row);
719       for (int col = 0; col < pBitmap1->GetWidth(); col++) {
720         pScanline[0] = (uint8_t)(pScanline[0] * pScanline[3] / 255.f + .5f);
721         pScanline[1] = (uint8_t)(pScanline[1] * pScanline[3] / 255.f + .5f);
722         pScanline[2] = (uint8_t)(pScanline[2] * pScanline[3] / 255.f + .5f);
723         pScanline += 4;
724       }
725     }
726   }
727   CGContextRef ctx = createContextWithBitmap(pBitmap1);
728   CGImageRef image = CGBitmapContextCreateImage(ctx);
729   CGContextDrawImage(_context, rect, image);
730   CGImageRelease(image);
731   CGContextRelease(ctx);
732   if (pBitmap1 != pBitmap) {
733     delete pBitmap1;
734   }
735   RestoreState(FALSE);
736   return TRUE;
737 }
CG_DrawGlypRun(int nChars,const FXTEXT_CHARPOS * pCharPos,CFX_Font * pFont,CFX_FontCache * pCache,const CFX_Matrix * pGlyphMatrix,const CFX_Matrix * pObject2Device,FX_FLOAT font_size,FX_DWORD argb,int alpha_flag,void * pIccTransform)738 FX_BOOL CFX_QuartzDeviceDriver::CG_DrawGlypRun(int nChars,
739                                                const FXTEXT_CHARPOS* pCharPos,
740                                                CFX_Font* pFont,
741                                                CFX_FontCache* pCache,
742                                                const CFX_Matrix* pGlyphMatrix,
743                                                const CFX_Matrix* pObject2Device,
744                                                FX_FLOAT font_size,
745                                                FX_DWORD argb,
746                                                int alpha_flag,
747                                                void* pIccTransform) {
748   if (nChars == 0) {
749     return TRUE;
750   }
751   CQuartz2D& quartz2d =
752       ((CApplePlatform*)CFX_GEModule::Get()->GetPlatformData())->_quartz2d;
753   if (!pFont->GetPlatformFont()) {
754     if (pFont->GetPsName() == CFX_WideString::FromLocal("DFHeiStd-W5")) {
755       return FALSE;
756     }
757     pFont->SetPlatformFont(
758         quartz2d.CreateFont(pFont->GetFontData(), pFont->GetSize()));
759     if (!pFont->GetPlatformFont()) {
760       return FALSE;
761     }
762   }
763   CFX_FixedBufGrow<FX_WORD, 32> glyph_indices(nChars);
764   CFX_FixedBufGrow<CGPoint, 32> glyph_positions(nChars);
765   for (int i = 0; i < nChars; i++) {
766     glyph_indices[i] = pCharPos[i].m_ExtGID;
767     glyph_positions[i].x = pCharPos[i].m_OriginX;
768     glyph_positions[i].y = pCharPos[i].m_OriginY;
769   }
770   CFX_Matrix text_matrix;
771   if (pObject2Device) {
772     text_matrix.Concat(*pObject2Device);
773   }
774   CGAffineTransform matrix_cg =
775       CGAffineTransformMake(text_matrix.a, text_matrix.b, text_matrix.c,
776                             text_matrix.d, text_matrix.e, text_matrix.f);
777   matrix_cg = CGAffineTransformConcat(matrix_cg, _foxitDevice2User);
778   CGContextSetTextMatrix(_context, matrix_cg);
779   CGContextSetFont(_context, (CGFontRef)pFont->GetPlatformFont());
780   CGContextSetFontSize(_context, FXSYS_fabs(font_size));
781   int32_t a, r, g, b;
782   ArgbDecode(argb, a, r, g, b);
783   CGContextSetRGBFillColor(_context, r / 255.f, g / 255.f, b / 255.f,
784                            a / 255.f);
785   SaveState();
786   if (pGlyphMatrix) {
787     CGPoint origin = CGPointMake(glyph_positions[0].x, glyph_positions[0].y);
788     origin = CGPointApplyAffineTransform(origin, matrix_cg);
789     CGContextTranslateCTM(_context, origin.x, origin.y);
790     CGAffineTransform glyph_matrix = CGAffineTransformMake(
791         pGlyphMatrix->a, pGlyphMatrix->b, pGlyphMatrix->c, pGlyphMatrix->d,
792         pGlyphMatrix->e, pGlyphMatrix->f);
793     if (_foxitDevice2User.d < 0) {
794       glyph_matrix = CGAffineTransformInvert(glyph_matrix);
795     }
796     CGContextConcatCTM(_context, glyph_matrix);
797     CGContextTranslateCTM(_context, -origin.x, -origin.y);
798   }
799   CGContextShowGlyphsAtPositions(_context, (CGGlyph*)glyph_indices,
800                                  glyph_positions, nChars);
801   RestoreState(FALSE);
802   return TRUE;
803 }
DrawDeviceText(int nChars,const FXTEXT_CHARPOS * pCharPos,CFX_Font * pFont,CFX_FontCache * pCache,const CFX_Matrix * pObject2Device,FX_FLOAT font_size,FX_DWORD color,int alpha_flag,void * pIccTransform)804 FX_BOOL CFX_QuartzDeviceDriver::DrawDeviceText(int nChars,
805                                                const FXTEXT_CHARPOS* pCharPos,
806                                                CFX_Font* pFont,
807                                                CFX_FontCache* pCache,
808                                                const CFX_Matrix* pObject2Device,
809                                                FX_FLOAT font_size,
810                                                FX_DWORD color,
811                                                int alpha_flag,
812                                                void* pIccTransform) {
813   if (NULL == pFont || NULL == _context) {
814     return FALSE;
815   }
816   FX_BOOL bBold = pFont->IsBold();
817   if (!bBold && pFont->GetSubstFont() &&
818       pFont->GetSubstFont()->m_Weight >= 500 &&
819       pFont->GetSubstFont()->m_Weight <= 600) {
820     return FALSE;
821   }
822   SaveState();
823   CGContextSetTextDrawingMode(_context, kCGTextFillClip);
824   FX_BOOL ret = FALSE;
825   int32_t i = 0;
826   while (i < nChars) {
827     if (pCharPos[i].m_bGlyphAdjust || font_size < 0) {
828       if (i > 0) {
829         ret = CG_DrawGlypRun(i, pCharPos, pFont, pCache, NULL, pObject2Device,
830                              font_size, color, alpha_flag, pIccTransform);
831         if (!ret) {
832           RestoreState(FALSE);
833           return ret;
834         }
835       }
836       const FXTEXT_CHARPOS* char_pos = pCharPos + i;
837       CFX_Matrix glphy_matrix;
838       if (font_size < 0) {
839         glphy_matrix.Concat(-1, 0, 0, -1, 0, 0);
840       }
841       if (char_pos->m_bGlyphAdjust) {
842         glphy_matrix.Concat(
843             char_pos->m_AdjustMatrix[0], char_pos->m_AdjustMatrix[1],
844             char_pos->m_AdjustMatrix[2], char_pos->m_AdjustMatrix[3], 0, 0);
845       }
846       ret = CG_DrawGlypRun(1, char_pos, pFont, pCache, &glphy_matrix,
847                            pObject2Device, font_size, color, alpha_flag,
848                            pIccTransform);
849       if (!ret) {
850         RestoreState(FALSE);
851         return ret;
852       }
853       i++;
854       pCharPos += i;
855       nChars -= i;
856       i = 0;
857     } else {
858       i++;
859     }
860   }
861   if (i > 0) {
862     ret = CG_DrawGlypRun(i, pCharPos, pFont, pCache, NULL, pObject2Device,
863                          font_size, color, alpha_flag, pIccTransform);
864   }
865   RestoreState(FALSE);
866   return ret;
867 }
setStrokeInfo(const CFX_GraphStateData * graphState,FX_ARGB argb,FX_FLOAT lineWidth)868 void CFX_QuartzDeviceDriver::setStrokeInfo(const CFX_GraphStateData* graphState,
869                                            FX_ARGB argb,
870                                            FX_FLOAT lineWidth) {
871   if (NULL == graphState) {
872     return;
873   }
874   CGContextSetLineWidth(_context, lineWidth);
875   CGLineCap cap;
876   switch (graphState->m_LineCap) {
877     case CFX_GraphStateData::LineCapRound: {
878       cap = kCGLineCapRound;
879       break;
880     }
881     case CFX_GraphStateData::LineCapSquare: {
882       cap = kCGLineCapSquare;
883       break;
884     }
885     case CFX_GraphStateData::LineCapButt:
886     default: { cap = kCGLineCapButt; }
887   }
888   CGContextSetLineCap(_context, cap);
889   CGLineJoin join;
890   switch (graphState->m_LineJoin) {
891     case CFX_GraphStateData::LineJoinRound: {
892       join = kCGLineJoinRound;
893       break;
894     }
895     case CFX_GraphStateData::LineJoinBevel: {
896       join = kCGLineJoinBevel;
897       break;
898     }
899     case CFX_GraphStateData::LineJoinMiter:
900     default: { join = kCGLineJoinMiter; }
901   }
902   CGContextSetLineJoin(_context, join);
903   if (graphState->m_DashCount) {
904 #if CGFLOAT_IS_DOUBLE
905     CGFloat* dashArray = new CGFloat[graphState->m_DashCount];
906     for (int index = 0; index < graphState->m_DashCount; ++index) {
907       dashArray[index] = graphState->m_DashArray[index];
908     }
909 #else
910     CGFloat* dashArray = (CGFloat*)graphState->m_DashArray;
911 #endif
912     CGContextSetLineDash(_context, graphState->m_DashPhase, dashArray,
913                          graphState->m_DashCount);
914 #if CGFLOAT_IS_DOUBLE
915     delete[] dashArray;
916 #endif
917   }
918   int32_t a, r, g, b;
919   ArgbDecode(argb, a, r, g, b);
920   CGContextSetRGBStrokeColor(_context, r / 255.f, g / 255.f, b / 255.f,
921                              a / 255.f);
922 }
setFillInfo(FX_ARGB argb)923 void CFX_QuartzDeviceDriver::setFillInfo(FX_ARGB argb) {
924   int32_t a, r, g, b;
925   ArgbDecode(argb, a, r, g, b);
926   CGContextSetRGBFillColor(_context, r / 255.f, g / 255.f, b / 255.f,
927                            a / 255.f);
928 }
setPathToContext(const CFX_PathData * pathData)929 void CFX_QuartzDeviceDriver::setPathToContext(const CFX_PathData* pathData) {
930   int32_t count = pathData->GetPointCount();
931   FX_PATHPOINT* points = pathData->GetPoints();
932   CGContextBeginPath(_context);
933   for (int32_t i = 0; i < count; i++) {
934     switch (points[i].m_Flag & FXPT_TYPE) {
935       case FXPT_MOVETO:
936         CGContextMoveToPoint(_context, points[i].m_PointX, points[i].m_PointY);
937         break;
938       case FXPT_LINETO:
939         CGContextAddLineToPoint(_context, points[i].m_PointX,
940                                 points[i].m_PointY);
941         break;
942       case FXPT_BEZIERTO: {
943         CGContextAddCurveToPoint(_context, points[i].m_PointX,
944                                  points[i].m_PointY, points[i + 1].m_PointX,
945                                  points[i + 1].m_PointY, points[i + 2].m_PointX,
946                                  points[i + 2].m_PointY);
947         i += 2;
948       }
949     }
950     if (points[i].m_Flag & FXPT_CLOSEFIGURE) {
951       CGContextClosePath(_context);
952     }
953   }
954 }
CG_SetImageTransform(int dest_left,int dest_top,int dest_width,int dest_height,CGRect * rect)955 void CFX_QuartzDeviceDriver::CG_SetImageTransform(int dest_left,
956                                                   int dest_top,
957                                                   int dest_width,
958                                                   int dest_height,
959                                                   CGRect* rect) {
960   int flip_y = _foxitDevice2User.d * dest_height < 0 ? 1 : -1;
961   int flip_x = _foxitDevice2User.a * dest_width > 0 ? 1 : -1;
962   if (flip_y < 0 || flip_x < 0) {
963     if (dest_height < 0) {
964       dest_height = -dest_height;
965       dest_top -= dest_height;
966     }
967     CGRect rt = CGRectApplyAffineTransform(
968         CGRectMake(dest_left, dest_top, dest_width, dest_height),
969         _foxitDevice2User);
970     CGFloat offset_x = (rt.origin.x) + rt.size.width / 2.f,
971             offset_y = (rt.origin.y) + rt.size.height / 2.f;
972     CGAffineTransform transform = CGAffineTransformIdentity;
973     transform = CGAffineTransformConcat(
974         transform, CGAffineTransformMake(1, 0, 0, 1, -offset_x, -offset_y));
975     transform = CGAffineTransformConcat(
976         transform, CGAffineTransformMake(flip_x, 0, 0, flip_y, 0, 0));
977     transform = CGAffineTransformConcat(
978         transform, CGAffineTransformMake(1, 0, 0, 1, offset_x, offset_y));
979     CGContextConcatCTM(_context, transform);
980     if (rect) {
981       *rect = CGRectApplyAffineTransform(*rect, transform);
982     }
983   }
984 }
ClearDriver()985 void CFX_QuartzDeviceDriver::ClearDriver() {
986   if (NULL == _context) {
987     return;
988   }
989   for (int i = 0; i < m_saveCount; ++i) {
990     CGContextRestoreGState(_context);
991   }
992   m_saveCount = 0;
993   if (_context) {
994     CGContextRelease(_context);
995   }
996 }
CFX_QuartzDevice()997 CFX_QuartzDevice::CFX_QuartzDevice() {
998   m_bOwnedBitmap = FALSE;
999   m_pContext = NULL;
1000 }
~CFX_QuartzDevice()1001 CFX_QuartzDevice::~CFX_QuartzDevice() {
1002   if (m_pContext) {
1003     CGContextRelease(m_pContext);
1004   }
1005   if (m_bOwnedBitmap) {
1006     delete GetBitmap();
1007   }
1008 }
GetContext()1009 CGContextRef CFX_QuartzDevice::GetContext() {
1010   return m_pContext;
1011 }
Attach(CGContextRef context,int32_t nDeviceClass)1012 FX_BOOL CFX_QuartzDevice::Attach(CGContextRef context, int32_t nDeviceClass) {
1013   if (m_pContext) {
1014     CGContextRelease(m_pContext);
1015   }
1016   m_pContext = context;
1017   CGContextRetain(m_pContext);
1018   IFX_RenderDeviceDriver* pDriver =
1019       new CFX_QuartzDeviceDriver(m_pContext, nDeviceClass);
1020   SetDeviceDriver(pDriver);
1021   return TRUE;
1022 }
Attach(CFX_DIBitmap * pBitmap)1023 FX_BOOL CFX_QuartzDevice::Attach(CFX_DIBitmap* pBitmap) {
1024   SetBitmap(pBitmap);
1025   m_pContext = createContextWithBitmap(pBitmap);
1026   if (NULL == m_pContext) {
1027     return FALSE;
1028   }
1029   IFX_RenderDeviceDriver* pDriver =
1030       new CFX_QuartzDeviceDriver(m_pContext, FXDC_DISPLAY);
1031   SetDeviceDriver(pDriver);
1032   return TRUE;
1033 }
Create(int32_t width,int32_t height,FXDIB_Format format)1034 FX_BOOL CFX_QuartzDevice::Create(int32_t width,
1035                                  int32_t height,
1036                                  FXDIB_Format format) {
1037   if ((uint8_t)format < 32) {
1038     return FALSE;
1039   }
1040   CFX_DIBitmap* pBitmap = new CFX_DIBitmap;
1041   if (!pBitmap->Create(width, height, format)) {
1042     delete pBitmap;
1043     return FALSE;
1044   }
1045   m_bOwnedBitmap = TRUE;
1046   return Attach(pBitmap);
1047 }
1048 #endif  // _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_
1049