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_ge.h"
9 #include "../agg/include/fxfx_agg_clip_liang_barsky.h"
10 #include "../ge/text_int.h"
11 #include "../dib/dib_int.h"
12 #include "../agg/include/fx_agg_driver.h"
13 #include "../../../include/fxge/fx_freetype.h"
14 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
15 #include "apple_int.h"
16 #include "../../../include/fxge/fx_ge_apple.h"
17 #ifndef CGFLOAT_IS_DOUBLE
18 #error Expected CGFLOAT_IS_DOUBLE to be defined by CoreGraphics headers
19 #endif
createGraphics(CFX_DIBitmap * pBitmap)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 }
destroyGraphics(void * graphics)45 void CQuartz2D::destroyGraphics(void* graphics)
46 {
47 if (graphics) {
48 CGContextRelease((CGContextRef) graphics);
49 }
50 }
CreateFont(FX_LPCBYTE pFontData,FX_DWORD dwFontSize)51 void* CQuartz2D::CreateFont(FX_LPCBYTE 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 }
DestroyFont(void * pFont)61 void CQuartz2D::DestroyFont(void* pFont)
62 {
63 CGFontRelease((CGFontRef)pFont);
64 }
setGraphicsTextMatrix(void * graphics,CFX_AffineMatrix * matrix)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 }
drawGraphicsString(void * graphics,void * font,FX_FLOAT fontSize,FX_WORD * glyphIndices,CGPoint * glyphPositions,FX_INT32 charsCount,FX_ARGB argb,CFX_AffineMatrix * matrix)79 FX_BOOL CQuartz2D::drawGraphicsString(void* graphics,
80 void* font,
81 FX_FLOAT fontSize,
82 FX_WORD* glyphIndices,
83 CGPoint* glyphPositions,
84 FX_INT32 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 FX_INT32 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 }
saveGraphicsState(void * graphics)135 void CQuartz2D::saveGraphicsState(void * graphics)
136 {
137 if (graphics) {
138 CGContextSaveGState((CGContextRef) graphics);
139 }
140 }
restoreGraphicsState(void * graphics)141 void CQuartz2D::restoreGraphicsState(void * graphics)
142 {
143 if (graphics) {
144 CGContextRestoreGState((CGContextRef) graphics);
145 }
146 }
createContextWithBitmap(CFX_DIBitmap * pBitmap)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 }
CFX_QuartzDeviceDriver(CGContextRef context,FX_INT32 deviceClass)169 CFX_QuartzDeviceDriver::CFX_QuartzDeviceDriver(CGContextRef context, FX_INT32 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 }
~CFX_QuartzDeviceDriver()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 }
GetDeviceCaps(int capsID)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 }
GetCTM() const244 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 }
SaveState()249 void CFX_QuartzDeviceDriver::SaveState()
250 {
251 CGContextSaveGState(_context);
252 m_saveCount++;
253 }
RestoreState(FX_BOOL isKeepSaved)254 void CFX_QuartzDeviceDriver::RestoreState(FX_BOOL isKeepSaved )
255 {
256 CGContextRestoreGState(_context);
257 if (isKeepSaved) {
258 CGContextSaveGState(_context);
259 } else {
260 m_saveCount--;
261 }
262 }
SetClip_PathFill(const CFX_PathData * pathData,const CFX_AffineMatrix * matrix,int fillMode)263 FX_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 }
getLineWidth(const CFX_GraphStateData * graphState,CGAffineTransform ctm)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 }
SetClip_PathStroke(const CFX_PathData * pathData,const CFX_AffineMatrix * matrix,const CFX_GraphStateData * graphState)297 FX_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 }
GetCGBlendMode(int blend_type)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 }
DrawPath(const CFX_PathData * pathData,const CFX_AffineMatrix * matrix,const CFX_GraphStateData * graphState,FX_DWORD fillArgb,FX_DWORD strokeArgb,int fillMode,int alpha_flag,void * pIccTransform,int blend_type)374 FX_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 }
FillRect(const FX_RECT * rect,FX_ARGB fillArgb,int alphaFlag,void * iccTransform,int blend_type)429 FX_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 FX_INT32 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 }
DrawCosmeticLine(FX_FLOAT x1,FX_FLOAT y1,FX_FLOAT x2,FX_FLOAT y2,FX_DWORD argb,int alphaFlag,void * iccTransform,int blend_type)454 FX_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 FX_INT32 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 }
GetClipBox(FX_RECT * rect)488 FX_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 }
GetDIBits(CFX_DIBitmap * bitmap,FX_INT32 left,FX_INT32 top,void * pIccTransform,FX_BOOL bDEdge)498 FX_BOOL CFX_QuartzDeviceDriver::GetDIBits(CFX_DIBitmap* bitmap,
499 FX_INT32 left,
500 FX_INT32 top,
501 void* pIccTransform,
502 FX_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 FX_LPBYTE pScanline = (FX_LPBYTE)bitmap->GetScanline(row);
545 for (int col = 0; col < bitmap->GetWidth(); col ++) {
546 if (pScanline[3] > 0) {
547 pScanline[0] = (pScanline[0] * 255.f / pScanline[3] + .5f);
548 pScanline[1] = (pScanline[1] * 255.f / pScanline[3] + .5f);
549 pScanline[2] = (pScanline[2] * 255.f / pScanline[3] + .5f);
550 }
551 pScanline += 4;
552 }
553 }
554 }
555 return TRUE;
556 }
SetDIBits(const CFX_DIBSource * pBitmap,FX_ARGB argb,const FX_RECT * srcRect,int dest_left,int dest_top,int blendType,int alphaFlag,void * iccTransform)557 FX_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 FX_LPBYTE pScanline = (FX_LPBYTE)pBitmap1->GetScanline(row);
658 for (int col = 0; col < pBitmap1->GetWidth(); col ++) {
659 pScanline[0] = (FX_BYTE)(pScanline[0] * pScanline[3] / 255.f + .5f);
660 pScanline[1] = (FX_BYTE)(pScanline[1] * pScanline[3] / 255.f + .5f);
661 pScanline[2] = (FX_BYTE)(pScanline[2] * pScanline[3] / 255.f + .5f);
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 }
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)688 FX_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 FX_LPBYTE pScanline = (FX_LPBYTE)pBitmap1->GetScanline(row);
783 for (int col = 0; col < pBitmap1->GetWidth(); col ++) {
784 pScanline[0] = (FX_BYTE)(pScanline[0] * pScanline[3] / 255.f + .5f);
785 pScanline[1] = (FX_BYTE)(pScanline[1] * pScanline[3] / 255.f + .5f);
786 pScanline[2] = (FX_BYTE)(pScanline[2] * pScanline[3] / 255.f + .5f);
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 }
CG_DrawGlypRun(int nChars,const FXTEXT_CHARPOS * pCharPos,CFX_Font * pFont,CFX_FontCache * pCache,const CFX_AffineMatrix * pGlyphMatrix,const CFX_AffineMatrix * pObject2Device,FX_FLOAT font_size,FX_DWORD argb,int alpha_flag,void * pIccTransform)802 FX_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 FX_INT32 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 }
DrawDeviceText(int nChars,const FXTEXT_CHARPOS * pCharPos,CFX_Font * pFont,CFX_FontCache * pCache,const CFX_AffineMatrix * pObject2Device,FX_FLOAT font_size,FX_DWORD color,int alpha_flag,void * pIccTransform)878 FX_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 FX_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 FX_BOOL ret = FALSE;
900 FX_INT32 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 }
setStrokeInfo(const CFX_GraphStateData * graphState,FX_ARGB argb,FX_FLOAT lineWidth)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 FX_INT32 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 }
setFillInfo(FX_ARGB argb)1003 void CFX_QuartzDeviceDriver::setFillInfo(FX_ARGB argb)
1004 {
1005 FX_INT32 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 }
setPathToContext(const CFX_PathData * pathData)1013 void CFX_QuartzDeviceDriver::setPathToContext(const CFX_PathData* pathData)
1014 {
1015 FX_INT32 count = pathData->GetPointCount();
1016 FX_PATHPOINT* points = pathData->GetPoints();
1017 CGContextBeginPath(_context);
1018 for (FX_INT32 i = 0; i < count; i ++) {
1019 switch (points[i].m_Flag & FXPT_TYPE) {
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 }
CG_SetImageTransform(int dest_left,int dest_top,int dest_width,int dest_height,CGRect * rect)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 }
ClearDriver()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 }
CFX_QuartzDevice()1075 CFX_QuartzDevice::CFX_QuartzDevice()
1076 {
1077 m_bOwnedBitmap = FALSE;
1078 m_pContext = NULL;
1079 }
~CFX_QuartzDevice()1080 CFX_QuartzDevice::~CFX_QuartzDevice()
1081 {
1082 if (m_pContext) {
1083 CGContextRelease(m_pContext);
1084 }
1085 if (GetBitmap() && m_bOwnedBitmap) {
1086 delete GetBitmap();
1087 }
1088 }
GetContext()1089 CGContextRef CFX_QuartzDevice::GetContext()
1090 {
1091 return m_pContext;
1092 }
Attach(CGContextRef context,FX_INT32 nDeviceClass)1093 FX_BOOL CFX_QuartzDevice::Attach(CGContextRef context, FX_INT32 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 }
Attach(CFX_DIBitmap * pBitmap)1104 FX_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 }
Create(FX_INT32 width,FX_INT32 height,FXDIB_Format format)1115 FX_BOOL CFX_QuartzDevice::Create(FX_INT32 width, FX_INT32 height, FXDIB_Format format)
1116 {
1117 if ((FX_BYTE)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
1129