1/*
2 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26#import <Accelerate/Accelerate.h> // for vImage_Buffer
27
28#import "JNIUtilities.h"
29#import "CGGlyphImages.h"
30#import "CoreTextSupport.h"
31#import "fontscalerdefs.h" // contains the definition of GlyphInfo struct
32
33#import "sun_awt_SunHints.h"
34
35//#define USE_IMAGE_ALIGNED_MEMORY 1
36//#define CGGI_DEBUG 1
37//#define CGGI_DEBUG_DUMP 1
38//#define CGGI_DEBUG_HIT_COUNT 1
39
40#define PRINT_TX(x) \
41    NSLog(@"(%f, %f, %f, %f, %f, %f)", x.a, x.b, x.c, x.d, x.tx, x.ty);
42
43/*
44 * The GlyphCanvas is a global shared CGContext that characters are struck into.
45 * For each character, the glyph is struck, copied into a GlyphInfo struct, and
46 * the canvas is cleared for the next glyph.
47 *
48 * If the necessary canvas is too large, the shared one will not be used and a
49 * temporary one will be provided.
50 */
51@interface CGGI_GlyphCanvas : NSObject {
52@public
53    CGContextRef context;
54    vImage_Buffer *image;
55}
56@end;
57
58@implementation CGGI_GlyphCanvas
59@end
60
61
62#pragma mark --- Debugging Helpers ---
63
64/*
65 * These debug functions are only compiled when CGGI_DEBUG is activated.
66 * They will print out a full UInt8 canvas and any pixels struck (assuming
67 * the canvas is not too big).
68 *
69 * As another debug feature, the entire canvas will be filled with a light
70 * alpha value so it is easy to see where the glyph painting regions are
71 * at runtime.
72 */
73
74#ifdef CGGI_DEBUG_DUMP
75static void
76DUMP_PIXELS(const char msg[], const UInt8 pixels[],
77            const size_t bytesPerPixel, const int width, const int height)
78{
79    printf("| %s: (%d, %d)\n", msg, width, height);
80
81    if (width > 80 || height > 80) {
82        printf("| too big\n");
83        return;
84    }
85
86    size_t i, j = 0, k, size = width * height;
87    for (i = 0; i < size; i++) {
88        for (k = 0; k < bytesPerPixel; k++) {
89            if (pixels[i * bytesPerPixel + k] > 0x80) j++;
90        }
91    }
92
93    if (j == 0) {
94        printf("| empty\n");
95        return;
96    }
97
98    printf("|_");
99    int x, y;
100    for (x = 0; x < width; x++) {
101        printf("__");
102    }
103    printf("_\n");
104
105    for (y = 0; y < height; y++) {
106        printf("| ");
107        for (x = 0; x < width; x++) {
108            int p = 0;
109            for(k = 0; k < bytesPerPixel; k++) {
110                p += pixels[(y * width + x) * bytesPerPixel + k];
111            }
112
113            if (p < 0x80) {
114                printf("  ");
115            } else {
116                printf("[]");
117            }
118        }
119        printf(" |\n");
120    }
121}
122
123static void
124DUMP_IMG_PIXELS(const char msg[], const vImage_Buffer *image)
125{
126    const void *pixels = image->data;
127    const size_t pixelSize = image->rowBytes / image->width;
128    const size_t width = image->width;
129    const size_t height = image->height;
130
131    DUMP_PIXELS(msg, pixels, pixelSize, width, height);
132}
133
134static void
135PRINT_CGSTATES_INFO(const CGContextRef cgRef)
136{
137    // TODO(cpc): lots of SPI use in this method; remove/rewrite?
138#if 0
139    CGRect clip = CGContextGetClipBoundingBox(cgRef);
140    fprintf(stderr, "    clip: ((%f, %f), (%f, %f))\n",
141            clip.origin.x, clip.origin.y, clip.size.width, clip.size.height);
142
143    CGAffineTransform ctm = CGContextGetCTM(cgRef);
144    fprintf(stderr, "    ctm: (%f, %f, %f, %f, %f, %f)\n",
145            ctm.a, ctm.b, ctm.c, ctm.d, ctm.tx, ctm.ty);
146
147    CGAffineTransform txtTx = CGContextGetTextMatrix(cgRef);
148    fprintf(stderr, "    txtTx: (%f, %f, %f, %f, %f, %f)\n",
149            txtTx.a, txtTx.b, txtTx.c, txtTx.d, txtTx.tx, txtTx.ty);
150
151    if (CGContextIsPathEmpty(cgRef) == 0) {
152        CGPoint pathpoint = CGContextGetPathCurrentPoint(cgRef);
153        CGRect pathbbox = CGContextGetPathBoundingBox(cgRef);
154        fprintf(stderr, "    [pathpoint: (%f, %f)] [pathbbox: ((%f, %f), (%f, %f))]\n",
155                pathpoint.x, pathpoint.y, pathbbox.origin.x, pathbbox.origin.y,
156                pathbbox.size.width, pathbbox.size.width);
157    }
158
159    CGFloat linewidth = CGContextGetLineWidth(cgRef);
160    CGLineCap linecap = CGContextGetLineCap(cgRef);
161    CGLineJoin linejoin = CGContextGetLineJoin(cgRef);
162    CGFloat miterlimit = CGContextGetMiterLimit(cgRef);
163    size_t dashcount = CGContextGetLineDashCount(cgRef);
164    fprintf(stderr, "    [linewidth: %f] [linecap: %d] [linejoin: %d] [miterlimit: %f] [dashcount: %lu]\n",
165            linewidth, linecap, linejoin, miterlimit, (unsigned long)dashcount);
166
167    CGFloat smoothness = CGContextGetSmoothness(cgRef);
168    bool antialias = CGContextGetShouldAntialias(cgRef);
169    bool smoothfont = CGContextGetShouldSmoothFonts(cgRef);
170    JRSFontRenderingStyle fRendMode = CGContextGetFontRenderingMode(cgRef);
171    fprintf(stderr, "    [smoothness: %f] [antialias: %d] [smoothfont: %d] [fontrenderingmode: %d]\n",
172            smoothness, antialias, smoothfont, fRendMode);
173#endif
174}
175#endif
176
177#ifdef CGGI_DEBUG
178
179static void
180DUMP_GLYPHINFO(const GlyphInfo *info)
181{
182    printf("size: (%d, %d) pixelSize: %d\n",
183           info->width, info->height, info->rowBytes / info->width);
184    printf("adv: (%f, %f) top: (%f, %f)\n",
185           info->advanceX, info->advanceY, info->topLeftX, info->topLeftY);
186
187#ifdef CGGI_DEBUG_DUMP
188    DUMP_PIXELS("Glyph Info Struct",
189                info->image, info->rowBytes / info->width,
190                info->width, info->height);
191#endif
192}
193
194#endif
195
196
197#pragma mark --- Font Rendering Mode Descriptors ---
198static Int32 reverseGamma = 0;
199
200static UInt8 reverseGammaLut[256] = { 0 };
201
202static inline UInt8* getReverseGammaLut() {
203    if (reverseGamma == 0) {
204        // initialize gamma lut
205        double gamma;
206        int i;
207        const char* pGammaEnv = getenv("J2D_LCD_REVERSE_GAMMA");
208        if (pGammaEnv != NULL) {
209            reverseGamma = atol(pGammaEnv);
210        }
211
212        if (reverseGamma < 100 || reverseGamma > 250) {
213            reverseGamma = 180;
214        }
215
216        gamma = 100.0 / reverseGamma;
217        for (i = 0; i < 256; i++) {
218            double x = ((double)i) / 255.0;
219            reverseGammaLut[i] = (UInt8)(255 * pow(x, gamma));
220        }
221    }
222    return reverseGammaLut;
223}
224
225static inline void
226CGGI_CopyARGBPixelToRGBPixel(const UInt32 p, UInt8 *dst)
227{
228    UInt8* lut = getReverseGammaLut();
229
230    *(dst + 0) = lut[0xFF - (p >> 16 & 0xFF)];  // red
231    *(dst + 1) = lut[0xFF - (p >>  8 & 0xFF)];  // green
232    *(dst + 2) = lut[0xFF - (p & 0xFF)];        // blue
233}
234
235static void
236CGGI_CopyImageFromCanvasToRGBInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
237{
238    UInt32 *src = (UInt32 *)canvas->image->data;
239    size_t srcRowWidth = canvas->image->width;
240
241    UInt8 *dest = (UInt8 *)info->image;
242    size_t destRowWidth = info->width;
243
244    size_t height = info->height;
245
246    size_t y;
247
248    // fill empty glyph image with black-on-white glyph
249    for (y = 0; y < height; y++) {
250        size_t destRow = y * destRowWidth * 3;
251        size_t srcRow = y * srcRowWidth;
252
253        size_t x;
254        for (x = 0; x < destRowWidth; x++) {
255            CGGI_CopyARGBPixelToRGBPixel(src[srcRow + x],
256                                         dest + destRow + x * 3);
257        }
258    }
259}
260
261//static void CGGI_copyImageFromCanvasToAlphaInfo
262//(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
263//{
264//    vImage_Buffer infoBuffer;
265//    infoBuffer.data = info->image;
266//    infoBuffer.width = info->width;
267//    infoBuffer.height = info->height;
268//    infoBuffer.rowBytes = info->width; // three bytes per RGB pixel
269//
270//    UInt8 scrapPixel[info->width * info->height];
271//    vImage_Buffer scrapBuffer;
272//    scrapBuffer.data = &scrapPixel;
273//    scrapBuffer.width = info->width;
274//    scrapBuffer.height = info->height;
275//    scrapBuffer.rowBytes = info->width;
276//
277//    vImageConvert_ARGB8888toPlanar8(canvas->image, &infoBuffer,
278//        &scrapBuffer, &scrapBuffer, &scrapBuffer, kvImageNoFlags);
279//}
280
281static inline UInt8
282CGGI_ConvertBWPixelToByteGray(UInt32 p)
283{
284    return 0xFF - (((p >> 24 & 0xFF) + (p >> 16 & 0xFF) + (p >> 8 & 0xFF)) / 3);
285}
286
287static void
288CGGI_CopyImageFromCanvasToAlphaInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
289{
290    UInt32 *src = (UInt32 *)canvas->image->data;
291    size_t srcRowWidth = canvas->image->width;
292
293    UInt8 *dest = (UInt8 *)info->image;
294    size_t destRowWidth = info->width;
295
296    size_t height = info->height;
297
298    size_t y;
299
300    // fill empty glyph image with black-on-white glyph
301    for (y = 0; y < height; y++) {
302        size_t destRow = y * destRowWidth;
303        size_t srcRow = y * srcRowWidth;
304        size_t x;
305        for (x = 0; x < destRowWidth; x++) {
306            UInt32 p = src[srcRow + x];
307            dest[destRow + x] = CGGI_ConvertBWPixelToByteGray(p);
308        }
309    }
310}
311
312static void
313CGGI_CopyImageFromCanvasToARGBInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
314{
315    CGBitmapInfo bitmapInfo = CGBitmapContextGetBitmapInfo(canvas->context);
316    bool littleEndian = (bitmapInfo & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Little;
317
318    UInt32 *src = (UInt32 *)canvas->image->data;
319    size_t srcRowWidth = canvas->image->width;
320
321    UInt8 *dest = (UInt8 *)info->image;
322    size_t destRowWidth = info->width;
323
324    size_t height = info->height;
325
326    size_t y;
327
328    for (y = 0; y < height; y++) {
329        size_t srcRow = y * srcRowWidth;
330        if (littleEndian) {
331            UInt16 destRowBytes = info->rowBytes;
332            memcpy(dest, src + srcRow, destRowBytes);
333            dest += destRowBytes;
334        } else {
335            size_t x;
336            for (x = 0; x < destRowWidth; x++) {
337                UInt32 p = src[srcRow + x];
338                *dest++ = (p >> 24  & 0xFF); // blue  (alpha-premultiplied)
339                *dest++ = (p >> 16 & 0xFF); // green (alpha-premultiplied)
340                *dest++ = (p >> 8   & 0xFF); // red   (alpha-premultiplied)
341                *dest++ = (p & 0xFF); // alpha
342            }
343        }
344    }
345}
346
347#pragma mark --- Pixel Size, Modes, and Canvas Shaping Helper Functions ---
348
349typedef struct CGGI_GlyphInfoDescriptor {
350    size_t pixelSize;
351    void (*copyFxnPtr)(CGGI_GlyphCanvas *canvas, GlyphInfo *info);
352} CGGI_GlyphInfoDescriptor;
353
354typedef struct CGGI_RenderingMode {
355    CGGI_GlyphInfoDescriptor *glyphDescriptor;
356    JRSFontRenderingStyle cgFontMode;
357} CGGI_RenderingMode;
358
359static CGGI_GlyphInfoDescriptor grey =
360    { 1, &CGGI_CopyImageFromCanvasToAlphaInfo };
361static CGGI_GlyphInfoDescriptor rgb =
362    { 3, &CGGI_CopyImageFromCanvasToRGBInfo };
363static CGGI_GlyphInfoDescriptor argb =
364    { 4, &CGGI_CopyImageFromCanvasToARGBInfo };
365
366static inline CGGI_GlyphInfoDescriptor*
367CGGI_GetGlyphInfoDescriptor(const CGGI_RenderingMode *mode, CTFontRef font)
368{
369    return IsEmojiFont(font) ? &argb : mode->glyphDescriptor;
370}
371
372static inline CGGI_RenderingMode
373CGGI_GetRenderingMode(const AWTStrike *strike)
374{
375    CGGI_RenderingMode mode;
376    mode.cgFontMode = strike->fStyle;
377    NSException *e = nil;
378
379    switch (strike->fAAStyle) {
380    case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_OFF:
381    case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_ON:
382        mode.glyphDescriptor = &grey;
383        break;
384    case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HRGB:
385    case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HBGR:
386    case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VRGB:
387    case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VBGR:
388        mode.glyphDescriptor = &rgb;
389        break;
390    case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_GASP:
391    case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_DEFAULT:
392    default:
393        /* we expect that text antialiasing hint has been already
394         * evaluated. Report an error if we get 'unevaluated' hint here.
395         */
396        e = [NSException
397                exceptionWithName:@"IllegalArgumentException"
398                reason:@"Invalid hint value"
399                userInfo:nil];
400        @throw e;
401    }
402
403    return mode;
404}
405
406
407#pragma mark --- Canvas Managment ---
408
409/*
410 * Creates a new canvas of a fixed size, and initializes the CGContext as
411 * an 32-bit ARGB BitmapContext with some generic RGB color space.
412 */
413static inline void
414CGGI_InitCanvas(CGGI_GlyphCanvas *canvas,
415                const vImagePixelCount width, const vImagePixelCount height,
416                const CGGI_RenderingMode* mode)
417{
418    // our canvas is *always* 4-byte ARGB
419    size_t bytesPerRow = width * sizeof(UInt32);
420    size_t byteCount = bytesPerRow * height;
421
422    canvas->image = malloc(sizeof(vImage_Buffer));
423    canvas->image->width = width;
424    canvas->image->height = height;
425    canvas->image->rowBytes = bytesPerRow;
426
427    canvas->image->data = (void *)calloc(byteCount, sizeof(UInt8));
428    if (canvas->image->data == NULL) {
429        [[NSException exceptionWithName:NSMallocException
430            reason:@"Failed to allocate memory for the buffer which backs the CGContext for glyph strikes." userInfo:nil] raise];
431    }
432
433    uint32_t bmpInfo = kCGImageAlphaPremultipliedFirst;
434    if (mode->glyphDescriptor == &rgb) {
435        bmpInfo |= kCGBitmapByteOrder32Host;
436    }
437
438    CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
439    canvas->context = CGBitmapContextCreate(canvas->image->data,
440                                            width, height, 8, bytesPerRow,
441                                            colorSpace,
442                                            bmpInfo);
443
444    // set foreground color
445    CGContextSetRGBFillColor(canvas->context, 0.0f, 0.0f, 0.0f, 1.0f);
446
447    CGContextSetFontSize(canvas->context, 1);
448    CGContextSaveGState(canvas->context);
449
450    CGColorSpaceRelease(colorSpace);
451}
452
453/*
454 * Releases the BitmapContext and the associated memory backing it.
455 */
456static inline void
457CGGI_FreeCanvas(CGGI_GlyphCanvas *canvas)
458{
459    if (canvas->context != NULL) {
460        CGContextRelease(canvas->context);
461    }
462
463    if (canvas->image != NULL) {
464        if (canvas->image->data != NULL) {
465            free(canvas->image->data);
466        }
467        free(canvas->image);
468    }
469}
470
471/*
472 * This is the slack space that is preallocated for the global GlyphCanvas
473 * when it needs to be expanded. It has been set somewhat liberally to
474 * avoid re-upsizing frequently.
475 */
476#define CGGI_GLYPH_CANVAS_SLACK 2.5
477
478/*
479 * Quick and easy inline to check if this canvas is big enough.
480 */
481static inline void
482CGGI_SizeCanvas(CGGI_GlyphCanvas *canvas, const vImagePixelCount width,
483        const vImagePixelCount height,
484        const CGGI_RenderingMode* mode)
485{
486    if (canvas->image != NULL &&
487        width  < canvas->image->width &&
488        height < canvas->image->height)
489    {
490        return;
491    }
492
493    // if we don't have enough space to strike the largest glyph in the
494    // run, resize the canvas
495    CGGI_FreeCanvas(canvas);
496    CGGI_InitCanvas(canvas,
497                    width * CGGI_GLYPH_CANVAS_SLACK,
498                    height * CGGI_GLYPH_CANVAS_SLACK,
499                    mode);
500    JRSFontSetRenderingStyleOnContext(canvas->context, mode->cgFontMode);
501}
502
503/*
504 * Clear the canvas by blitting white (or transparent background for color glyphs) only into the region of interest
505 * (the rect which we will copy out of once the glyph is struck).
506 */
507static inline void
508CGGI_ClearCanvas(CGGI_GlyphCanvas *canvas, GlyphInfo *info, bool transparent)
509{
510    vImage_Buffer canvasRectToClear;
511    canvasRectToClear.data = canvas->image->data;
512    canvasRectToClear.height = info->height;
513    canvasRectToClear.width = info->width;
514    // use the row stride of the canvas, not the info
515    canvasRectToClear.rowBytes = canvas->image->rowBytes;
516
517    // clean the canvas
518#ifdef CGGI_DEBUG
519    Pixel_8888 background = { 0xE0, 0xE0, 0xE0, 0xE0 };
520#else
521    Pixel_8888 background = { transparent ? 0 : 0xFF,
522                               transparent ? 0 : 0xFF,
523                               transparent ? 0 : 0xFF,
524                               transparent ? 0 : 0xFF };
525#endif
526
527    // clear canvas background
528    vImageBufferFill_ARGB8888(&canvasRectToClear, background, kvImageNoFlags);
529}
530
531
532#pragma mark --- GlyphInfo Creation & Copy Functions ---
533
534/*
535 * Creates a GlyphInfo with exactly the correct size image and measurements.
536 */
537#define CGGI_GLYPH_BBOX_PADDING 2.0f
538static inline GlyphInfo *
539CGGI_CreateNewGlyphInfoFrom(CGSize advance, CGRect bbox,
540                            const AWTStrike *strike,
541                            const CGGI_GlyphInfoDescriptor *glyphDescriptor)
542{
543    size_t pixelSize = glyphDescriptor->pixelSize;
544
545    // adjust the bounding box to be 1px bigger on each side than what
546    // CGFont-whatever suggests - because it gives a bounding box that
547    // is too tight
548    bbox.size.width += CGGI_GLYPH_BBOX_PADDING * 2.0f;
549    bbox.size.height += CGGI_GLYPH_BBOX_PADDING * 2.0f;
550    bbox.origin.x -= CGGI_GLYPH_BBOX_PADDING;
551    bbox.origin.y -= CGGI_GLYPH_BBOX_PADDING;
552
553    vImagePixelCount width = ceilf(bbox.size.width);
554    vImagePixelCount height = ceilf(bbox.size.height);
555
556    // if the glyph is larger than 1MB, don't even try...
557    // the GlyphVector path should have taken over by now
558    // and zero pixels is ok
559    if (width * height > 1024 * 1024) {
560        width = 1;
561        height = 1;
562    }
563    advance = CGSizeApplyAffineTransform(advance, strike->fFontTx);
564    if (!JRSFontStyleUsesFractionalMetrics(strike->fStyle)) {
565        advance.width = round(advance.width);
566        advance.height = round(advance.height);
567    }
568    advance = CGSizeApplyAffineTransform(advance, strike->fDevTx);
569
570#ifdef USE_IMAGE_ALIGNED_MEMORY
571    // create separate memory
572    GlyphInfo *glyphInfo = (GlyphInfo *)malloc(sizeof(GlyphInfo));
573    void *image = (void *)malloc(height * width * pixelSize);
574#else
575    // create a GlyphInfo struct fused to the image it points to
576    GlyphInfo *glyphInfo = (GlyphInfo *)malloc(sizeof(GlyphInfo) +
577                                               height * width * pixelSize);
578#endif
579
580    glyphInfo->advanceX = advance.width;
581    glyphInfo->advanceY = advance.height;
582    glyphInfo->topLeftX = round(bbox.origin.x);
583    glyphInfo->topLeftY = round(bbox.origin.y);
584    glyphInfo->width = width;
585    glyphInfo->height = height;
586    glyphInfo->rowBytes = width * pixelSize;
587    glyphInfo->cellInfo = NULL;
588
589#ifdef USE_IMAGE_ALIGNED_MEMORY
590    glyphInfo->image = image;
591#else
592    glyphInfo->image = ((void *)glyphInfo) + sizeof(GlyphInfo);
593#endif
594
595    return glyphInfo;
596}
597
598
599#pragma mark --- Glyph Striking onto Canvas ---
600
601/*
602 * Clears the canvas, strikes the glyph with CoreGraphics, and then
603 * copies the struck pixels into the GlyphInfo image.
604 */
605static inline void
606CGGI_CreateImageForGlyph
607    (CGGI_GlyphCanvas *canvas, const CGGlyph glyph,
608     GlyphInfo *info, const CGGI_GlyphInfoDescriptor *glyphDescriptor, const AWTStrike *strike, CTFontRef font)
609{
610    if (isnan(info->topLeftX) || isnan(info->topLeftY)) {
611        // Explicitly set glyphInfo width/height to be 0 to ensure
612        // zero length glyph image is copied into GlyphInfo from canvas
613        info->width = 0;
614        info->height = 0;
615
616        // copy the "empty" glyph from the canvas into the info
617        (*glyphDescriptor->copyFxnPtr)(canvas, info);
618        return;
619    }
620
621    // clean the canvas
622    CGGI_ClearCanvas(canvas, info, glyphDescriptor == &argb);
623
624    // strike the glyph in the upper right corner
625    CGFloat x = -info->topLeftX;
626    CGFloat y = canvas->image->height + info->topLeftY;
627
628    if (glyphDescriptor == &argb) {
629        // Emoji glyphs are not rendered by CGContextShowGlyphsAtPoint.
630        // Also, it's not possible to use transformation matrix to get the emoji glyph
631        // rendered for the desired font size - actual-size font object is needed.
632        // The logic here must match the logic in CGGlyphImages_GetGlyphMetrics,
633        // which calculates glyph metrics.
634
635        CGAffineTransform matrix = CGContextGetTextMatrix(canvas->context);
636        CGFloat fontSize = sqrt(fabs(matrix.a * matrix.d - matrix.b * matrix.c));
637        CTFontRef sizedFont = CTFontCreateCopyWithSymbolicTraits(font, fontSize, NULL, 0, 0);
638
639        CGFloat normFactor = 1.0 / fontSize;
640        CGAffineTransform normalizedMatrix = CGAffineTransformScale(matrix, normFactor, normFactor);
641        CGContextSetTextMatrix(canvas->context, normalizedMatrix);
642
643        CGPoint userPoint = CGPointMake(x, y);
644        CGAffineTransform normalizedMatrixInv = CGAffineTransformInvert(normalizedMatrix);
645        CGPoint textPoint = CGPointApplyAffineTransform(userPoint, normalizedMatrixInv);
646
647        CTFontDrawGlyphs(sizedFont, &glyph, &textPoint, 1, canvas->context);
648
649        CFRelease(sizedFont);
650        // restore context's original state
651        CGContextSetTextMatrix(canvas->context, matrix);
652        CGContextSetFontSize(canvas->context, 1); // CTFontDrawGlyphs tampers with it
653    } else {
654        CGContextShowGlyphsAtPoint(canvas->context, x, y, &glyph, 1);
655    }
656
657    // copy the glyph from the canvas into the info
658    (*glyphDescriptor->copyFxnPtr)(canvas, info);
659}
660
661/*
662 * CoreText path...
663 */
664static inline GlyphInfo *
665CGGI_CreateImageForUnicode
666    (CGGI_GlyphCanvas *canvas, const AWTStrike *strike,
667     const CGGI_RenderingMode *mode, const UnicodeScalarValue uniChar)
668{
669    // save the state of the world
670    CGContextSaveGState(canvas->context);
671
672    // get the glyph, measure it using CG
673    CGGlyph glyph;
674    CTFontRef fallback;
675    if (uniChar > 0xFFFF) {
676        UTF16Char charRef[2];
677        CTS_BreakupUnicodeIntoSurrogatePairs(uniChar, charRef);
678        CGGlyph glyphTmp[2];
679        fallback = CTS_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, (CGGlyph *)&glyphTmp, 2);
680        glyph = glyphTmp[0];
681    } else {
682        UTF16Char charRef;
683        charRef = (UTF16Char) uniChar; // truncate.
684        fallback = CTS_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, &glyph, 1);
685    }
686
687    CGAffineTransform tx = strike->fTx;
688    JRSFontRenderingStyle style = JRSFontAlignStyleForFractionalMeasurement(strike->fStyle);
689
690    CGRect bbox;
691    CGSize advance;
692    CGGlyphImages_GetGlyphMetrics(fallback, &tx, style, &glyph, 1, &bbox, &advance);
693
694    CGGI_GlyphInfoDescriptor *glyphDescriptor = CGGI_GetGlyphInfoDescriptor(mode, fallback);
695
696    // create the Sun2D GlyphInfo we are going to strike into
697    GlyphInfo *info = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, glyphDescriptor);
698
699    // fix the context size, just in case the substituted character is unexpectedly large
700    CGGI_SizeCanvas(canvas, info->width, info->height, mode);
701
702    // align the transform for the real CoreText strike
703    CGContextSetTextMatrix(canvas->context, strike->fAltTx);
704
705    const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);
706    CGContextSetFont(canvas->context, cgFallback);
707    CFRelease(cgFallback);
708
709    // clean the canvas - align, strike, and copy the glyph from the canvas into the info
710    CGGI_CreateImageForGlyph(canvas, glyph, info, glyphDescriptor, strike, fallback);
711
712    // restore the state of the world
713    CGContextRestoreGState(canvas->context);
714
715    CFRelease(fallback);
716#ifdef CGGI_DEBUG
717    DUMP_GLYPHINFO(info);
718#endif
719
720#ifdef CGGI_DEBUG_DUMP
721    DUMP_IMG_PIXELS("CGGI Canvas", canvas->image);
722#if 0
723    PRINT_CGSTATES_INFO(NULL);
724#endif
725#endif
726
727    return info;
728}
729
730
731#pragma mark --- GlyphInfo Filling and Canvas Managment ---
732
733/*
734 * Sets all the per-run properties for the canvas, and then iterates through
735 * the character run, and creates images in the GlyphInfo structs.
736 *
737 * Not inlined because it would create two copies in the function below
738 */
739static void
740CGGI_FillImagesForGlyphsWithSizedCanvas(CGGI_GlyphCanvas *canvas,
741                                        const AWTStrike *strike,
742                                        const CGGI_RenderingMode *mode,
743                                        jlong glyphInfos[],
744                                        const UnicodeScalarValue uniChars[],
745                                        const CGGlyph glyphs[],
746                                        const CFIndex len)
747{
748    CGContextSetTextMatrix(canvas->context, strike->fAltTx);
749
750    CGContextSetFont(canvas->context, strike->fAWTFont->fNativeCGFont);
751    JRSFontSetRenderingStyleOnContext(canvas->context, strike->fStyle);
752
753    CTFontRef mainFont = (CTFontRef)strike->fAWTFont->fFont;
754    CGGI_GlyphInfoDescriptor* mainFontDescriptor = CGGI_GetGlyphInfoDescriptor(mode, mainFont);
755
756    CFIndex i;
757    for (i = 0; i < len; i++) {
758        GlyphInfo *info = (GlyphInfo *)jlong_to_ptr(glyphInfos[i]);
759        if (info != NULL) {
760            CGGI_CreateImageForGlyph(canvas, glyphs[i], info, mainFontDescriptor, strike, mainFont);
761        } else {
762            info = CGGI_CreateImageForUnicode(canvas, strike, mode, uniChars[i]);
763            glyphInfos[i] = ptr_to_jlong(info);
764        }
765#ifdef CGGI_DEBUG
766        DUMP_GLYPHINFO(info);
767#endif
768
769#ifdef CGGI_DEBUG_DUMP
770        DUMP_IMG_PIXELS("CGGI Canvas", canvas->image);
771#endif
772    }
773#ifdef CGGI_DEBUG_DUMP
774    DUMP_IMG_PIXELS("CGGI Canvas", canvas->image);
775    PRINT_CGSTATES_INFO(canvas->context);
776#endif
777}
778
779static NSString *threadLocalAACanvasKey =
780    @"Java CoreGraphics Text Renderer Cached Canvas for AA";
781
782static NSString *threadLocalLCDCanvasKey =
783    @"Java CoreGraphics Text Renderer Cached Canvas for LCD";
784
785/*
786 * This is the maximum length and height times the above slack squared
787 * to determine if we go with the global canvas, or malloc one on the spot.
788 */
789#define CGGI_GLYPH_CANVAS_MAX 100
790
791/*
792 * Based on the space needed to strike the largest character in the run,
793 * either use the global shared canvas, or make one up on the spot, strike
794 * the glyphs, and destroy it.
795 */
796static inline void
797CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
798                         const CGGI_RenderingMode *mode,
799                         const UnicodeScalarValue uniChars[], const CGGlyph glyphs[],
800                         const size_t maxWidth, const size_t maxHeight,
801                         const CFIndex len)
802{
803    if (maxWidth*maxHeight*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK >
804        CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK)
805    {
806        CGGI_GlyphCanvas *tmpCanvas = [[CGGI_GlyphCanvas alloc] init];
807        CGGI_InitCanvas(tmpCanvas, maxWidth, maxHeight, mode);
808        CGGI_FillImagesForGlyphsWithSizedCanvas(tmpCanvas, strike,
809                mode, glyphInfos, uniChars,
810                glyphs, len);
811        CGGI_FreeCanvas(tmpCanvas);
812
813        [tmpCanvas release];
814        return;
815    }
816    NSMutableDictionary *threadDict =
817        [[NSThread currentThread] threadDictionary];
818
819    NSString* theKey = (mode->glyphDescriptor == &rgb) ?
820        threadLocalLCDCanvasKey : threadLocalAACanvasKey;
821
822    CGGI_GlyphCanvas *canvas = [threadDict objectForKey:theKey];
823    if (canvas == nil) {
824        canvas = [[CGGI_GlyphCanvas alloc] init];
825        [threadDict setObject:canvas forKey:theKey];
826    }
827
828    CGGI_SizeCanvas(canvas, maxWidth, maxHeight, mode);
829    CGGI_FillImagesForGlyphsWithSizedCanvas(canvas, strike, mode,
830                                            glyphInfos, uniChars, glyphs, len);
831}
832
833/*
834 * Finds the advances and bounding boxes of the characters in the run,
835 * cycles through all the bounds and calculates the maximum canvas space
836 * required by the largest glyph.
837 *
838 * Creates a GlyphInfo struct with a malloc that also encapsulates the
839 * image the struct points to.  This is done to meet memory layout
840 * expectations in the Sun text rasterizer memory managment code.
841 * The image immediately follows the struct physically in memory.
842 */
843static inline void
844CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
845                      const CGGI_RenderingMode *mode,
846                      const UnicodeScalarValue uniChars[], const CGGlyph glyphs[],
847                      CGSize advances[], CGRect bboxes[], const CFIndex len)
848{
849    AWTFont *font = strike->fAWTFont;
850    CGAffineTransform tx = strike->fTx;
851    JRSFontRenderingStyle bboxCGMode = JRSFontAlignStyleForFractionalMeasurement(strike->fStyle);
852
853    CTFontRef fontRef = (CTFontRef)font->fFont;
854    CGGlyphImages_GetGlyphMetrics(fontRef, &tx, bboxCGMode, glyphs, len, bboxes, advances);
855    CGGI_GlyphInfoDescriptor* mainFontDescriptor = CGGI_GetGlyphInfoDescriptor(mode, fontRef);
856
857    size_t maxWidth = 1;
858    size_t maxHeight = 1;
859
860    CFIndex i;
861    for (i = 0; i < len; i++)
862    {
863        if (uniChars[i] != 0)
864        {
865            glyphInfos[i] = 0L;
866            continue; // will be handled later
867        }
868
869        CGSize advance = advances[i];
870        CGRect bbox = bboxes[i];
871
872        GlyphInfo *glyphInfo = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mainFontDescriptor);
873
874        if (maxWidth < glyphInfo->width)   maxWidth = glyphInfo->width;
875        if (maxHeight < glyphInfo->height) maxHeight = glyphInfo->height;
876
877        glyphInfos[i] = ptr_to_jlong(glyphInfo);
878    }
879
880    CGGI_FillImagesForGlyphs(glyphInfos, strike, mode, uniChars,
881                             glyphs, maxWidth, maxHeight, len);
882}
883
884
885#pragma mark --- Temporary Buffer Allocations and Initialization ---
886
887/*
888 * This stage separates the already valid glyph codes from the unicode values
889 * that need special handling - the rawGlyphCodes array is no longer used
890 * after this stage.
891 */
892static void
893CGGI_CreateGlyphsAndScanForComplexities(jlong *glyphInfos,
894                                        const AWTStrike *strike,
895                                        const CGGI_RenderingMode *mode,
896                                        jint rawGlyphCodes[],
897                                        UnicodeScalarValue uniChars[], CGGlyph glyphs[],
898                                        CGSize advances[], CGRect bboxes[],
899                                        const CFIndex len)
900{
901    CFIndex i;
902    for (i = 0; i < len; i++) {
903        jint code = rawGlyphCodes[i];
904        if (code < 0) {
905            glyphs[i] = 0;
906            uniChars[i] = -code;
907        } else {
908            glyphs[i] = code;
909            uniChars[i] = 0;
910        }
911    }
912
913    CGGI_CreateGlyphInfos(glyphInfos, strike, mode,
914                          uniChars, glyphs, advances, bboxes, len);
915
916#ifdef CGGI_DEBUG_HIT_COUNT
917    static size_t hitCount = 0;
918    hitCount++;
919    printf("%d\n", (int)hitCount);
920#endif
921}
922
923/*
924 * Conditionally stack allocates buffers for glyphs, bounding boxes,
925 * and advances.  Unfortunately to use CG or CT in bulk runs (which is
926 * faster than calling them per character), we have to copy into and out
927 * of these buffers. Still a net win though.
928 */
929void
930CGGlyphImages_GetGlyphImagePtrs(jlong glyphInfos[],
931                                const AWTStrike *strike,
932                                jint rawGlyphCodes[], const CFIndex len)
933{
934    const CGGI_RenderingMode mode = CGGI_GetRenderingMode(strike);
935
936    if (len < MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE) {
937        CGRect bboxes[len];
938        CGSize advances[len];
939        CGGlyph glyphs[len];
940        UnicodeScalarValue uniChars[len];
941
942        CGGI_CreateGlyphsAndScanForComplexities(glyphInfos, strike, &mode,
943                                                rawGlyphCodes, uniChars, glyphs,
944                                                advances, bboxes, len);
945
946        return;
947    }
948
949    // just do one malloc, and carve it up for all the buffers
950    void *buffer = malloc(sizeof(CGRect) * sizeof(CGSize) *
951                          sizeof(CGGlyph) * sizeof(UnicodeScalarValue) * len);
952    if (buffer == NULL) {
953        [[NSException exceptionWithName:NSMallocException
954            reason:@"Failed to allocate memory for the temporary glyph strike and measurement buffers." userInfo:nil] raise];
955    }
956
957    CGRect *bboxes = (CGRect *)(buffer);
958    CGSize *advances = (CGSize *)(bboxes + sizeof(CGRect) * len);
959    CGGlyph *glyphs = (CGGlyph *)(advances + sizeof(CGGlyph) * len);
960    UnicodeScalarValue *uniChars = (UnicodeScalarValue *)(glyphs + sizeof(UnicodeScalarValue) * len);
961
962    CGGI_CreateGlyphsAndScanForComplexities(glyphInfos, strike, &mode,
963                                            rawGlyphCodes, uniChars, glyphs,
964                                            advances, bboxes, len);
965
966    free(buffer);
967}
968
969/*
970 * Calculates bounding boxes (for given transform) and advance (for untransformed 1pt-size font) for specified glyphs.
971 */
972void
973CGGlyphImages_GetGlyphMetrics(const CTFontRef font,
974                              const CGAffineTransform *tx,
975                              const JRSFontRenderingStyle style,
976                              const CGGlyph glyphs[],
977                              size_t count,
978                              CGRect bboxes[],
979                              CGSize advances[]) {
980    if (IsEmojiFont(font)) {
981        // Glyph metrics for emoji font are not strictly proportional to font size,
982        // so we need to construct real-sized font object to calculate them.
983        // The logic here must match the logic in CGGI_CreateImageForGlyph,
984        // which performs glyph drawing.
985
986        CGFloat fontSize = sqrt(fabs(tx->a * tx->d - tx->b * tx->c));
987        CTFontRef sizedFont = CTFontCreateCopyWithSymbolicTraits(font, fontSize, NULL, 0, 0);
988
989        if (bboxes) {
990            // JRSFontGetBoundingBoxesForGlyphsAndStyle works incorrectly for AppleColorEmoji font:
991            // it uses bottom left corner of the glyph's bounding box as a fixed point of transformation
992            // instead of glyph's origin point (used at drawing). So, as a workaround,
993            // we request a bounding box for the untransformed glyph, and apply the transform ourselves.
994            JRSFontGetBoundingBoxesForGlyphsAndStyle(sizedFont, &CGAffineTransformIdentity, style, glyphs, count, bboxes);
995            CGAffineTransform txNormalized = CGAffineTransformMake(tx->a / fontSize,
996                                                                   tx->b / fontSize,
997                                                                   tx->c / fontSize,
998                                                                   tx->d / fontSize,
999                                                                   0, 0);
1000            for (int i = 0; i < count; i++) {
1001                bboxes[i] = CGRectApplyAffineTransform(bboxes[i], txNormalized);
1002            }
1003        }
1004
1005        if (advances) {
1006            CTFontGetAdvancesForGlyphs(sizedFont, kCTFontDefaultOrientation, glyphs, advances, count);
1007            for (int i = 0; i < count; i++) {
1008                // Calling code will scale the result back
1009                advances[i].width /= fontSize;
1010                advances[i].height /= fontSize;
1011            }
1012        }
1013
1014        CFRelease(sizedFont);
1015    } else {
1016        if (bboxes) {
1017            JRSFontGetBoundingBoxesForGlyphsAndStyle(font, tx, style, glyphs, count, bboxes);
1018        }
1019        if (advances) {
1020            CTFontGetAdvancesForGlyphs(font, kCTFontDefaultOrientation, glyphs, advances, count);
1021        }
1022    }
1023}