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