jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m
changeset 31158 062c7363dd12
parent 26751 70bac69b37c9
child 31167 4fe9ebd79f86
equal deleted inserted replaced
31157:25a62bb54efa 31158:062c7363dd12
   193 
   193 
   194 #endif
   194 #endif
   195 
   195 
   196 
   196 
   197 #pragma mark --- Font Rendering Mode Descriptors ---
   197 #pragma mark --- Font Rendering Mode Descriptors ---
       
   198 static Int32 reverseGamma = 0;
       
   199 
       
   200 static UInt8 reverseGammaLut[256] = { 0 };
       
   201 
       
   202 static inline UInt8* getReverseGammaLut() {
       
   203     if (reverseGamma == 0) {
       
   204         // initialize gamma lut
       
   205         double gamma;
       
   206         const char* pGammaEnv = getenv("J2D_LCD_REVERSE_GAMMA");
       
   207         if (pGammaEnv != NULL) {
       
   208             reverseGamma = atol(pGammaEnv);
       
   209         }
       
   210         
       
   211         if (reverseGamma < 100 || reverseGamma > 250) {
       
   212             reverseGamma = 180;
       
   213         }
       
   214         
       
   215         gamma = 100.0 / reverseGamma;
       
   216         for (int i = 0; i < 256; i++) {
       
   217             double x = ((double)i) / 255.0;
       
   218             reverseGammaLut[i] = (UInt8)(255 * pow(x, gamma));
       
   219         }
       
   220     }
       
   221     return reverseGammaLut;
       
   222 }
   198 
   223 
   199 static inline void
   224 static inline void
   200 CGGI_CopyARGBPixelToRGBPixel(const UInt32 p, UInt8 *dst)
   225 CGGI_CopyARGBPixelToRGBPixel(const UInt32 p, UInt8 *dst)
   201 {
   226 {
   202 #if __LITTLE_ENDIAN__
   227     UInt8* lut = getReverseGammaLut();
   203     *(dst + 2) = 0xFF - (p >> 24 & 0xFF);
   228     
   204     *(dst + 1) = 0xFF - (p >> 16 & 0xFF);
   229     *(dst + 0) = lut[0xFF - (p >> 16 & 0xFF)];  // red
   205     *(dst) = 0xFF - (p >> 8 & 0xFF);
   230     *(dst + 1) = lut[0xFF - (p >>  8 & 0xFF)];  // green
   206 #else
   231     *(dst + 2) = lut[0xFF - (p & 0xFF)];        // blue
   207     *(dst) = 0xFF - (p >> 16 & 0xFF);
       
   208     *(dst + 1) = 0xFF - (p >> 8 & 0xFF);
       
   209     *(dst + 2) = 0xFF - (p & 0xFF);
       
   210 #endif
       
   211 }
   232 }
   212 
   233 
   213 static void
   234 static void
   214 CGGI_CopyImageFromCanvasToRGBInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
   235 CGGI_CopyImageFromCanvasToRGBInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
   215 {
   236 {
   220     size_t destRowWidth = info->width;
   241     size_t destRowWidth = info->width;
   221 
   242 
   222     size_t height = info->height;
   243     size_t height = info->height;
   223 
   244 
   224     size_t y;
   245     size_t y;
       
   246     
       
   247     // fill empty glyph image with black-on-white glyph
   225     for (y = 0; y < height; y++) {
   248     for (y = 0; y < height; y++) {
   226         size_t destRow = y * destRowWidth * 3;
   249         size_t destRow = y * destRowWidth * 3;
   227         size_t srcRow = y * srcRowWidth;
   250         size_t srcRow = y * srcRowWidth;
   228 
   251 
   229         size_t x;
   252         size_t x;
   230         for (x = 0; x < destRowWidth; x++) {
   253         for (x = 0; x < destRowWidth; x++) {
   231             // size_t x3 = x * 3;
       
   232             // UInt32 p = src[srcRow + x];
       
   233             // dest[destRow + x3] = 0xFF - (p >> 16 & 0xFF);
       
   234             // dest[destRow + x3 + 1] = 0xFF - (p >> 8 & 0xFF);
       
   235             // dest[destRow + x3 + 2] = 0xFF - (p & 0xFF);
       
   236             CGGI_CopyARGBPixelToRGBPixel(src[srcRow + x],
   254             CGGI_CopyARGBPixelToRGBPixel(src[srcRow + x],
   237                                          dest + destRow + x * 3);
   255                                          dest + destRow + x * 3);
   238         }
   256         }
   239     }
   257     }
   240 }
   258 }
   258 //    vImageConvert_ARGB8888toPlanar8(canvas->image, &infoBuffer,
   276 //    vImageConvert_ARGB8888toPlanar8(canvas->image, &infoBuffer,
   259 //        &scrapBuffer, &scrapBuffer, &scrapBuffer, kvImageNoFlags);
   277 //        &scrapBuffer, &scrapBuffer, &scrapBuffer, kvImageNoFlags);
   260 //}
   278 //}
   261 
   279 
   262 static inline UInt8
   280 static inline UInt8
   263 CGGI_ConvertPixelToGreyBit(UInt32 p)
   281 CGGI_ConvertBWPixelToByteGray(UInt32 p)
   264 {
   282 {
   265 #ifdef __LITTLE_ENDIAN__
   283     return 0xFF - (((p >> 24 & 0xFF) + (p >> 16 & 0xFF) + (p >> 8 & 0xFF)) / 3);
   266     return 0xFF - ((p >> 24 & 0xFF) + (p >> 16 & 0xFF) + (p >> 8 & 0xFF)) / 3;
       
   267 #else
       
   268     return 0xFF - ((p >> 16 & 0xFF) + (p >> 8 & 0xFF) + (p & 0xFF)) / 3;
       
   269 #endif
       
   270 }
   284 }
   271 
   285 
   272 static void
   286 static void
   273 CGGI_CopyImageFromCanvasToAlphaInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
   287 CGGI_CopyImageFromCanvasToAlphaInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
   274 {
   288 {
   279     size_t destRowWidth = info->width;
   293     size_t destRowWidth = info->width;
   280 
   294 
   281     size_t height = info->height;
   295     size_t height = info->height;
   282 
   296 
   283     size_t y;
   297     size_t y;
       
   298     
       
   299     // fill empty glyph image with black-on-white glyph
   284     for (y = 0; y < height; y++) {
   300     for (y = 0; y < height; y++) {
   285         size_t destRow = y * destRowWidth;
   301         size_t destRow = y * destRowWidth;
   286         size_t srcRow = y * srcRowWidth;
   302         size_t srcRow = y * srcRowWidth;
   287 
       
   288         size_t x;
   303         size_t x;
   289         for (x = 0; x < destRowWidth; x++) {
   304         for (x = 0; x < destRowWidth; x++) {
   290             UInt32 p = src[srcRow + x];
   305             UInt32 p = src[srcRow + x];
   291             dest[destRow + x] = CGGI_ConvertPixelToGreyBit(p);
   306             dest[destRow + x] = CGGI_ConvertBWPixelToByteGray(p);
   292         }
   307         }
   293     }
   308     }
   294 }
   309 }
   295 
   310 
   296 
   311 
   314 static inline CGGI_RenderingMode
   329 static inline CGGI_RenderingMode
   315 CGGI_GetRenderingMode(const AWTStrike *strike)
   330 CGGI_GetRenderingMode(const AWTStrike *strike)
   316 {
   331 {
   317     CGGI_RenderingMode mode;
   332     CGGI_RenderingMode mode;
   318     mode.cgFontMode = strike->fStyle;
   333     mode.cgFontMode = strike->fStyle;
       
   334     NSException *e = nil;
   319 
   335 
   320     switch (strike->fAAStyle) {
   336     switch (strike->fAAStyle) {
   321     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_DEFAULT:
       
   322     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_OFF:
   337     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_OFF:
   323     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_ON:
   338     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_ON:
   324     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_GASP:
       
   325     default:
       
   326         mode.glyphDescriptor = &grey;
   339         mode.glyphDescriptor = &grey;
   327         break;
   340         break;
   328     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HRGB:
   341     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HRGB:
   329     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HBGR:
   342     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HBGR:
   330     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VRGB:
   343     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VRGB:
   331     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VBGR:
   344     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VBGR:
   332         mode.glyphDescriptor = &rgb;
   345         mode.glyphDescriptor = &rgb;
   333         break;
   346         break;
       
   347     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_GASP:
       
   348     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_DEFAULT:
       
   349     default:
       
   350         /* we expect that text antialiasing hint has been already
       
   351          * evaluated. Report an error if we get 'unevaluated' hint here.
       
   352          */
       
   353         e = [NSException
       
   354                 exceptionWithName:@"IllegalArgumentException"
       
   355                 reason:@"Invalid hint value"
       
   356                 userInfo:nil];
       
   357         @throw e;
   334     }
   358     }
   335 
   359 
   336     return mode;
   360     return mode;
   337 }
   361 }
   338 
   362 
   343  * Creates a new canvas of a fixed size, and initializes the CGContext as
   367  * Creates a new canvas of a fixed size, and initializes the CGContext as
   344  * an 32-bit ARGB BitmapContext with some generic RGB color space.
   368  * an 32-bit ARGB BitmapContext with some generic RGB color space.
   345  */
   369  */
   346 static inline void
   370 static inline void
   347 CGGI_InitCanvas(CGGI_GlyphCanvas *canvas,
   371 CGGI_InitCanvas(CGGI_GlyphCanvas *canvas,
   348                 const vImagePixelCount width, const vImagePixelCount height)
   372                 const vImagePixelCount width, const vImagePixelCount height,
       
   373                 const CGGI_RenderingMode* mode)
   349 {
   374 {
   350     // our canvas is *always* 4-byte ARGB
   375     // our canvas is *always* 4-byte ARGB
   351     size_t bytesPerRow = width * sizeof(UInt32);
   376     size_t bytesPerRow = width * sizeof(UInt32);
   352     size_t byteCount = bytesPerRow * height;
   377     size_t byteCount = bytesPerRow * height;
   353 
   378 
   354     canvas->image = malloc(sizeof(vImage_Buffer));
   379     canvas->image = malloc(sizeof(vImage_Buffer));
   355     canvas->image->width = width;
   380     canvas->image->width = width;
   356     canvas->image->height = height;
   381     canvas->image->height = height;
   357     canvas->image->rowBytes = bytesPerRow;
   382     canvas->image->rowBytes = bytesPerRow;
   358 
   383 
   359     canvas->image->data = (void *)calloc(byteCount, sizeof(UInt32));
   384     canvas->image->data = (void *)calloc(byteCount, sizeof(UInt8));
   360     if (canvas->image->data == NULL) {
   385     if (canvas->image->data == NULL) {
   361         [[NSException exceptionWithName:NSMallocException
   386         [[NSException exceptionWithName:NSMallocException
   362             reason:@"Failed to allocate memory for the buffer which backs the CGContext for glyph strikes." userInfo:nil] raise];
   387             reason:@"Failed to allocate memory for the buffer which backs the CGContext for glyph strikes." userInfo:nil] raise];
   363     }
   388     }
   364 
   389 
   365     CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
   390     uint32_t bmpInfo = kCGImageAlphaPremultipliedFirst;
       
   391     if (mode->glyphDescriptor == &rgb) {
       
   392         bmpInfo |= kCGBitmapByteOrder32Host;
       
   393     }
       
   394 
       
   395     CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
   366     canvas->context = CGBitmapContextCreate(canvas->image->data,
   396     canvas->context = CGBitmapContextCreate(canvas->image->data,
   367                                             width, height, 8, bytesPerRow,
   397                                             width, height, 8, bytesPerRow,
   368                                             colorSpace,
   398                                             colorSpace,
   369                                             kCGImageAlphaPremultipliedFirst);
   399                                             bmpInfo);
   370 
   400 
       
   401     // set foreground color
   371     CGContextSetRGBFillColor(canvas->context, 0.0f, 0.0f, 0.0f, 1.0f);
   402     CGContextSetRGBFillColor(canvas->context, 0.0f, 0.0f, 0.0f, 1.0f);
       
   403     
   372     CGContextSetFontSize(canvas->context, 1);
   404     CGContextSetFontSize(canvas->context, 1);
   373     CGContextSaveGState(canvas->context);
   405     CGContextSaveGState(canvas->context);
   374 
   406 
   375     CGColorSpaceRelease(colorSpace);
   407     CGColorSpaceRelease(colorSpace);
   376 }
   408 }
   402 
   434 
   403 /*
   435 /*
   404  * Quick and easy inline to check if this canvas is big enough.
   436  * Quick and easy inline to check if this canvas is big enough.
   405  */
   437  */
   406 static inline void
   438 static inline void
   407 CGGI_SizeCanvas(CGGI_GlyphCanvas *canvas, const vImagePixelCount width, const vImagePixelCount height, const JRSFontRenderingStyle style)
   439 CGGI_SizeCanvas(CGGI_GlyphCanvas *canvas, const vImagePixelCount width,
       
   440         const vImagePixelCount height,
       
   441         const CGGI_RenderingMode* mode)
   408 {
   442 {
   409     if (canvas->image != NULL &&
   443     if (canvas->image != NULL &&
   410         width  < canvas->image->width &&
   444         width  < canvas->image->width &&
   411         height < canvas->image->height)
   445         height < canvas->image->height)
   412     {
   446     {
   416     // if we don't have enough space to strike the largest glyph in the
   450     // if we don't have enough space to strike the largest glyph in the
   417     // run, resize the canvas
   451     // run, resize the canvas
   418     CGGI_FreeCanvas(canvas);
   452     CGGI_FreeCanvas(canvas);
   419     CGGI_InitCanvas(canvas,
   453     CGGI_InitCanvas(canvas,
   420                     width * CGGI_GLYPH_CANVAS_SLACK,
   454                     width * CGGI_GLYPH_CANVAS_SLACK,
   421                     height * CGGI_GLYPH_CANVAS_SLACK);
   455                     height * CGGI_GLYPH_CANVAS_SLACK,
   422     JRSFontSetRenderingStyleOnContext(canvas->context, style);
   456                     mode);
       
   457     JRSFontSetRenderingStyleOnContext(canvas->context, mode->cgFontMode);
   423 }
   458 }
   424 
   459 
   425 /*
   460 /*
   426  * Clear the canvas by blitting white only into the region of interest
   461  * Clear the canvas by blitting white only into the region of interest
   427  * (the rect which we will copy out of once the glyph is struck).
   462  * (the rect which we will copy out of once the glyph is struck).
   441     Pixel_8888 opaqueWhite = { 0xE0, 0xE0, 0xE0, 0xE0 };
   476     Pixel_8888 opaqueWhite = { 0xE0, 0xE0, 0xE0, 0xE0 };
   442 #else
   477 #else
   443     Pixel_8888 opaqueWhite = { 0xFF, 0xFF, 0xFF, 0xFF };
   478     Pixel_8888 opaqueWhite = { 0xFF, 0xFF, 0xFF, 0xFF };
   444 #endif
   479 #endif
   445 
   480 
       
   481     // clear canvas background and set foreground color
   446     vImageBufferFill_ARGB8888(&canvasRectToClear, opaqueWhite, kvImageNoFlags);
   482     vImageBufferFill_ARGB8888(&canvasRectToClear, opaqueWhite, kvImageNoFlags);
   447 }
   483 }
   448 
   484 
   449 
   485 
   450 #pragma mark --- GlyphInfo Creation & Copy Functions ---
   486 #pragma mark --- GlyphInfo Creation & Copy Functions ---
   575 
   611 
   576     // create the Sun2D GlyphInfo we are going to strike into
   612     // create the Sun2D GlyphInfo we are going to strike into
   577     GlyphInfo *info = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mode);
   613     GlyphInfo *info = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mode);
   578 
   614 
   579     // fix the context size, just in case the substituted character is unexpectedly large
   615     // fix the context size, just in case the substituted character is unexpectedly large
   580     CGGI_SizeCanvas(canvas, info->width, info->height, mode->cgFontMode);
   616     CGGI_SizeCanvas(canvas, info->width, info->height, mode);
   581 
   617 
   582     // align the transform for the real CoreText strike
   618     // align the transform for the real CoreText strike
   583     CGContextSetTextMatrix(canvas->context, strike->fAltTx);
   619     CGContextSetTextMatrix(canvas->context, strike->fAltTx);
   584 
   620 
   585     const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);
   621     const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);
   651     DUMP_IMG_PIXELS("CGGI Canvas", canvas->image);
   687     DUMP_IMG_PIXELS("CGGI Canvas", canvas->image);
   652     PRINT_CGSTATES_INFO(canvas->context);
   688     PRINT_CGSTATES_INFO(canvas->context);
   653 #endif
   689 #endif
   654 }
   690 }
   655 
   691 
   656 static NSString *threadLocalCanvasKey =
   692 static NSString *threadLocalAACanvasKey =
   657     @"Java CoreGraphics Text Renderer Cached Canvas";
   693     @"Java CoreGraphics Text Renderer Cached Canvas for AA";
       
   694 
       
   695 static NSString *threadLocalLCDCanvasKey =
       
   696     @"Java CoreGraphics Text Renderer Cached Canvas for LCD";
   658 
   697 
   659 /*
   698 /*
   660  * This is the maximum length and height times the above slack squared
   699  * This is the maximum length and height times the above slack squared
   661  * to determine if we go with the global canvas, or malloc one on the spot.
   700  * to determine if we go with the global canvas, or malloc one on the spot.
   662  */
   701  */
   676 {
   715 {
   677     if (maxWidth*maxHeight*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK >
   716     if (maxWidth*maxHeight*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK >
   678         CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK)
   717         CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK)
   679     {
   718     {
   680         CGGI_GlyphCanvas *tmpCanvas = [[CGGI_GlyphCanvas alloc] init];
   719         CGGI_GlyphCanvas *tmpCanvas = [[CGGI_GlyphCanvas alloc] init];
   681         CGGI_InitCanvas(tmpCanvas, maxWidth, maxHeight);
   720         CGGI_InitCanvas(tmpCanvas, maxWidth, maxHeight, mode);
   682         CGGI_FillImagesForGlyphsWithSizedCanvas(tmpCanvas, strike,
   721         CGGI_FillImagesForGlyphsWithSizedCanvas(tmpCanvas, strike,
   683                                                 mode, glyphInfos, uniChars,
   722                 mode, glyphInfos, uniChars,
   684                                                 glyphs, len);
   723                 glyphs, len);
   685         CGGI_FreeCanvas(tmpCanvas);
   724         CGGI_FreeCanvas(tmpCanvas);
   686 
   725 
   687         [tmpCanvas release];
   726         [tmpCanvas release];
   688         return;
   727         return;
   689     }
   728     }
   690 
       
   691     NSMutableDictionary *threadDict =
   729     NSMutableDictionary *threadDict =
   692         [[NSThread currentThread] threadDictionary];
   730         [[NSThread currentThread] threadDictionary];
   693     CGGI_GlyphCanvas *canvas = [threadDict objectForKey:threadLocalCanvasKey];
   731 
       
   732     NSString* theKey = (mode->glyphDescriptor == &rgb) ?
       
   733         threadLocalLCDCanvasKey : threadLocalAACanvasKey;
       
   734     
       
   735     CGGI_GlyphCanvas *canvas = [threadDict objectForKey:theKey];
   694     if (canvas == nil) {
   736     if (canvas == nil) {
   695         canvas = [[CGGI_GlyphCanvas alloc] init];
   737         canvas = [[CGGI_GlyphCanvas alloc] init];
   696         [threadDict setObject:canvas forKey:threadLocalCanvasKey];
   738         [threadDict setObject:canvas forKey:theKey];
   697     }
   739     }
   698 
   740 
   699     CGGI_SizeCanvas(canvas, maxWidth, maxHeight, mode->cgFontMode);
   741     CGGI_SizeCanvas(canvas, maxWidth, maxHeight, mode);
   700     CGGI_FillImagesForGlyphsWithSizedCanvas(canvas, strike, mode,
   742     CGGI_FillImagesForGlyphsWithSizedCanvas(canvas, strike, mode,
   701                                             glyphInfos, uniChars, glyphs, len);
   743                                             glyphInfos, uniChars, glyphs, len);
   702 }
   744 }
   703 
   745 
   704 /*
   746 /*