< prev index next >

src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m

Print this page

        

*** 46,63 **** --- 46,77 ---- * the canvas is cleared for the next glyph. * * If the necessary canvas is too large, the shared one will not be used and a * temporary one will be provided. */ + typedef enum { + BLACK_ON_WHITE_STAGE, + WHITE_ON_BLACK_STAGE + } CGGI_GlyphRenderingStage; + @interface CGGI_GlyphCanvas : NSObject { @public CGContextRef context; vImage_Buffer *image; + CGGI_GlyphRenderingStage stage; } @end; @implementation CGGI_GlyphCanvas + - (id) init { + if (self = [super init]) { + context = NULL; + image = NULL; + stage = BLACK_ON_WHITE_STAGE; + } + return self; + } @end #pragma mark --- Debugging Helpers ---
*** 197,215 **** #pragma mark --- Font Rendering Mode Descriptors --- static inline void CGGI_CopyARGBPixelToRGBPixel(const UInt32 p, UInt8 *dst) { ! #if __LITTLE_ENDIAN__ ! *(dst + 2) = 0xFF - (p >> 24 & 0xFF); ! *(dst + 1) = 0xFF - (p >> 16 & 0xFF); ! *(dst) = 0xFF - (p >> 8 & 0xFF); ! #else ! *(dst) = 0xFF - (p >> 16 & 0xFF); ! *(dst + 1) = 0xFF - (p >> 8 & 0xFF); ! *(dst + 2) = 0xFF - (p & 0xFF); ! #endif } static void CGGI_CopyImageFromCanvasToRGBInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info) { --- 211,223 ---- #pragma mark --- Font Rendering Mode Descriptors --- static inline void CGGI_CopyARGBPixelToRGBPixel(const UInt32 p, UInt8 *dst) { ! *(dst + 0) = 0xFF - (p >> 16 & 0xFF); // red ! *(dst + 1) = 0xFF - (p >> 8 & 0xFF); // green ! *(dst + 2) = 0xFF - (p & 0xFF); // blue } static void CGGI_CopyImageFromCanvasToRGBInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info) {
*** 220,244 **** size_t destRowWidth = info->width; size_t height = info->height; size_t y; for (y = 0; y < height; y++) { size_t destRow = y * destRowWidth * 3; size_t srcRow = y * srcRowWidth; size_t x; for (x = 0; x < destRowWidth; x++) { - // size_t x3 = x * 3; - // UInt32 p = src[srcRow + x]; - // dest[destRow + x3] = 0xFF - (p >> 16 & 0xFF); - // dest[destRow + x3 + 1] = 0xFF - (p >> 8 & 0xFF); - // dest[destRow + x3 + 2] = 0xFF - (p & 0xFF); CGGI_CopyARGBPixelToRGBPixel(src[srcRow + x], dest + destRow + x * 3); } } } //static void CGGI_copyImageFromCanvasToAlphaInfo //(CGGI_GlyphCanvas *canvas, GlyphInfo *info) //{ --- 228,273 ---- size_t destRowWidth = info->width; size_t height = info->height; size_t y; + switch (canvas->stage) { + case BLACK_ON_WHITE_STAGE: + // fill empty glyph image with black-on-white glyph for (y = 0; y < height; y++) { size_t destRow = y * destRowWidth * 3; size_t srcRow = y * srcRowWidth; size_t x; for (x = 0; x < destRowWidth; x++) { CGGI_CopyARGBPixelToRGBPixel(src[srcRow + x], dest + destRow + x * 3); } } + break; + case WHITE_ON_BLACK_STAGE: + // merge black-on-white glyph (which is already in the glyph image) + // with white-on-black glyph + for (y = 0; y < height; y++) { + size_t destRow = y * destRowWidth * 3; + size_t srcRow = y * srcRowWidth; + + size_t x; + for (x = 0; x < destRowWidth; x++) { + UInt8* pDst = dest + destRow + x * 3; + UInt32 srcPixel = src[srcRow + x]; + + UInt16 r = *(pDst + 0) + (0xff & (srcPixel >> 16)); + *(pDst + 0) = (UInt8)(r >> 1); + UInt16 g = *(pDst + 1) + (0xff & (srcPixel >> 8)); + *(pDst + 1) = (UInt8)(g >> 1); + UInt16 b = *(pDst + 2) + (0xff & (srcPixel )); + *(pDst + 2) = (UInt8)(b >> 1); + } + } + break; + } } //static void CGGI_copyImageFromCanvasToAlphaInfo //(CGGI_GlyphCanvas *canvas, GlyphInfo *info) //{
*** 258,274 **** // vImageConvert_ARGB8888toPlanar8(canvas->image, &infoBuffer, // &scrapBuffer, &scrapBuffer, &scrapBuffer, kvImageNoFlags); //} static inline UInt8 ! CGGI_ConvertPixelToGreyBit(UInt32 p) { ! #ifdef __LITTLE_ENDIAN__ ! return 0xFF - ((p >> 24 & 0xFF) + (p >> 16 & 0xFF) + (p >> 8 & 0xFF)) / 3; ! #else ! return 0xFF - ((p >> 16 & 0xFF) + (p >> 8 & 0xFF) + (p & 0xFF)) / 3; ! #endif } static void CGGI_CopyImageFromCanvasToAlphaInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info) { --- 287,304 ---- // vImageConvert_ARGB8888toPlanar8(canvas->image, &infoBuffer, // &scrapBuffer, &scrapBuffer, &scrapBuffer, kvImageNoFlags); //} static inline UInt8 ! CGGI_ConvertWBPixelToByteGray(UInt32 p) { ! return ((p >> 16 & 0xFF) + (p >> 8 & 0xFF) + (p & 0xFF)) / 3; ! } ! ! static inline UInt8 ! CGGI_ConvertBWPixelToByteGray(UInt32 p) { ! return 0xFF - CGGI_ConvertWBPixelToByteGray(p); } static void CGGI_CopyImageFromCanvasToAlphaInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info) {
*** 279,297 **** size_t destRowWidth = info->width; size_t height = info->height; size_t y; for (y = 0; y < height; y++) { size_t destRow = y * destRowWidth; size_t srcRow = y * srcRowWidth; size_t x; for (x = 0; x < destRowWidth; x++) { UInt32 p = src[srcRow + x]; ! dest[destRow + x] = CGGI_ConvertPixelToGreyBit(p); } } } #pragma mark --- Pixel Size, Modes, and Canvas Shaping Helper Functions --- --- 309,346 ---- size_t destRowWidth = info->width; size_t height = info->height; size_t y; + switch (canvas->stage) { + case BLACK_ON_WHITE_STAGE: + // fill empty glyph image with black-on-white glyph + for (y = 0; y < height; y++) { + size_t destRow = y * destRowWidth; + size_t srcRow = y * srcRowWidth; + size_t x; + for (x = 0; x < destRowWidth; x++) { + UInt32 p = src[srcRow + x]; + dest[destRow + x] = CGGI_ConvertBWPixelToByteGray(p); + } + } + break; + case WHITE_ON_BLACK_STAGE: + // merge black-on-white glyph (which is already in the glyph image) + // with white-on-black glyph for (y = 0; y < height; y++) { size_t destRow = y * destRowWidth; size_t srcRow = y * srcRowWidth; size_t x; for (x = 0; x < destRowWidth; x++) { UInt32 p = src[srcRow + x]; ! UInt16 gray = dest[destRow + x] + CGGI_ConvertWBPixelToByteGray(p); ! dest[destRow + x] = (UInt8)(gray >> 1); ! } } + break; } } #pragma mark --- Pixel Size, Modes, and Canvas Shaping Helper Functions ---
*** 314,338 **** static inline CGGI_RenderingMode CGGI_GetRenderingMode(const AWTStrike *strike) { CGGI_RenderingMode mode; mode.cgFontMode = strike->fStyle; switch (strike->fAAStyle) { - case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_DEFAULT: case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_OFF: case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_ON: - case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_GASP: - default: mode.glyphDescriptor = &grey; break; case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HRGB: case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HBGR: case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VRGB: case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VBGR: mode.glyphDescriptor = &rgb; break; } return mode; } --- 363,393 ---- static inline CGGI_RenderingMode CGGI_GetRenderingMode(const AWTStrike *strike) { CGGI_RenderingMode mode; mode.cgFontMode = strike->fStyle; + NSException *e = nil; switch (strike->fAAStyle) { case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_OFF: case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_ON: mode.glyphDescriptor = &grey; break; case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HRGB: case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HBGR: case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VRGB: case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VBGR: mode.glyphDescriptor = &rgb; break; + case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_GASP: + case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_DEFAULT: + default: + e = [NSException + exceptionWithName:@"IllegalArgumentException" + reason:@"Invalid hint value" + userInfo:nil]; + @throw e; } return mode; }
*** 343,376 **** * Creates a new canvas of a fixed size, and initializes the CGContext as * an 32-bit ARGB BitmapContext with some generic RGB color space. */ static inline void CGGI_InitCanvas(CGGI_GlyphCanvas *canvas, ! const vImagePixelCount width, const vImagePixelCount height) { // our canvas is *always* 4-byte ARGB size_t bytesPerRow = width * sizeof(UInt32); size_t byteCount = bytesPerRow * height; canvas->image = malloc(sizeof(vImage_Buffer)); canvas->image->width = width; canvas->image->height = height; canvas->image->rowBytes = bytesPerRow; ! canvas->image->data = (void *)calloc(byteCount, sizeof(UInt32)); if (canvas->image->data == NULL) { [[NSException exceptionWithName:NSMallocException reason:@"Failed to allocate memory for the buffer which backs the CGContext for glyph strikes." userInfo:nil] raise]; } CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); canvas->context = CGBitmapContextCreate(canvas->image->data, width, height, 8, bytesPerRow, colorSpace, ! kCGImageAlphaPremultipliedFirst); CGContextSetRGBFillColor(canvas->context, 0.0f, 0.0f, 0.0f, 1.0f); CGContextSetFontSize(canvas->context, 1); CGContextSaveGState(canvas->context); CGColorSpaceRelease(colorSpace); } --- 398,441 ---- * Creates a new canvas of a fixed size, and initializes the CGContext as * an 32-bit ARGB BitmapContext with some generic RGB color space. */ static inline void CGGI_InitCanvas(CGGI_GlyphCanvas *canvas, ! const vImagePixelCount width, const vImagePixelCount height, ! const CGGI_RenderingMode* mode) { // our canvas is *always* 4-byte ARGB size_t bytesPerRow = width * sizeof(UInt32); size_t byteCount = bytesPerRow * height; canvas->image = malloc(sizeof(vImage_Buffer)); canvas->image->width = width; canvas->image->height = height; canvas->image->rowBytes = bytesPerRow; ! canvas->image->data = (void *)calloc(byteCount, sizeof(UInt8)); if (canvas->image->data == NULL) { [[NSException exceptionWithName:NSMallocException reason:@"Failed to allocate memory for the buffer which backs the CGContext for glyph strikes." userInfo:nil] raise]; } + canvas->stage = BLACK_ON_WHITE_STAGE; + + uint32_t bmpInfo = kCGImageAlphaPremultipliedFirst; + if (mode->glyphDescriptor == &rgb) { + bmpInfo |= kCGBitmapByteOrder32Host; + } + CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); canvas->context = CGBitmapContextCreate(canvas->image->data, width, height, 8, bytesPerRow, colorSpace, ! bmpInfo); + // set foreground color CGContextSetRGBFillColor(canvas->context, 0.0f, 0.0f, 0.0f, 1.0f); + CGContextSetFontSize(canvas->context, 1); CGContextSaveGState(canvas->context); CGColorSpaceRelease(colorSpace); }
*** 402,412 **** /* * Quick and easy inline to check if this canvas is big enough. */ static inline void ! CGGI_SizeCanvas(CGGI_GlyphCanvas *canvas, const vImagePixelCount width, const vImagePixelCount height, const JRSFontRenderingStyle style) { if (canvas->image != NULL && width < canvas->image->width && height < canvas->image->height) { --- 467,479 ---- /* * Quick and easy inline to check if this canvas is big enough. */ static inline void ! CGGI_SizeCanvas(CGGI_GlyphCanvas *canvas, const vImagePixelCount width, ! const vImagePixelCount height, ! const CGGI_RenderingMode* mode) { if (canvas->image != NULL && width < canvas->image->width && height < canvas->image->height) {
*** 416,427 **** // if we don't have enough space to strike the largest glyph in the // run, resize the canvas CGGI_FreeCanvas(canvas); CGGI_InitCanvas(canvas, width * CGGI_GLYPH_CANVAS_SLACK, ! height * CGGI_GLYPH_CANVAS_SLACK); ! JRSFontSetRenderingStyleOnContext(canvas->context, style); } /* * Clear the canvas by blitting white only into the region of interest * (the rect which we will copy out of once the glyph is struck). --- 483,495 ---- // if we don't have enough space to strike the largest glyph in the // run, resize the canvas CGGI_FreeCanvas(canvas); CGGI_InitCanvas(canvas, width * CGGI_GLYPH_CANVAS_SLACK, ! height * CGGI_GLYPH_CANVAS_SLACK, ! mode); ! JRSFontSetRenderingStyleOnContext(canvas->context, mode->cgFontMode); } /* * Clear the canvas by blitting white only into the region of interest * (the rect which we will copy out of once the glyph is struck).
*** 437,451 **** --- 505,532 ---- canvasRectToClear.rowBytes = canvas->image->rowBytes; // clean the canvas #ifdef CGGI_DEBUG Pixel_8888 opaqueWhite = { 0xE0, 0xE0, 0xE0, 0xE0 }; + Pixel_8888 opaqueBlack = { 0x10, 0x10, 0x10, 0xF0 }; #else Pixel_8888 opaqueWhite = { 0xFF, 0xFF, 0xFF, 0xFF }; + Pixel_8888 opaqueBlack = { 0x00, 0x00, 0x00, 0xFF }; #endif + // clear canvas background and set foreground color + switch(canvas->stage) { + case BLACK_ON_WHITE_STAGE: vImageBufferFill_ARGB8888(&canvasRectToClear, opaqueWhite, kvImageNoFlags); + CGContextSetRGBFillColor(canvas->context, 0.0f, 0.0f, 0.0f, 1.0f); + break; + case WHITE_ON_BLACK_STAGE: + vImageBufferFill_ARGB8888(&canvasRectToClear, opaqueBlack, kvImageNoFlags); + CGContextSetRGBFillColor(canvas->context, 1.0f, 1.0f, 1.0f, 1.0f); + break; + } + CGContextSaveGState(canvas->context); } #pragma mark --- GlyphInfo Creation & Copy Functions ---
*** 575,585 **** // create the Sun2D GlyphInfo we are going to strike into GlyphInfo *info = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mode); // fix the context size, just in case the substituted character is unexpectedly large ! CGGI_SizeCanvas(canvas, info->width, info->height, mode->cgFontMode); // align the transform for the real CoreText strike CGContextSetTextMatrix(canvas->context, strike->fAltTx); const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL); --- 656,666 ---- // create the Sun2D GlyphInfo we are going to strike into GlyphInfo *info = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mode); // fix the context size, just in case the substituted character is unexpectedly large ! CGGI_SizeCanvas(canvas, info->width, info->height, mode); // align the transform for the real CoreText strike CGContextSetTextMatrix(canvas->context, strike->fAltTx); const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);
*** 651,662 **** DUMP_IMG_PIXELS("CGGI Canvas", canvas->image); PRINT_CGSTATES_INFO(canvas->context); #endif } ! static NSString *threadLocalCanvasKey = ! @"Java CoreGraphics Text Renderer Cached Canvas"; /* * This is the maximum length and height times the above slack squared * to determine if we go with the global canvas, or malloc one on the spot. */ --- 732,746 ---- DUMP_IMG_PIXELS("CGGI Canvas", canvas->image); PRINT_CGSTATES_INFO(canvas->context); #endif } ! static NSString *threadLocalAACanvasKey = ! @"Java CoreGraphics Text Renderer Cached Canvas for AA"; ! ! static NSString *threadLocalLCDCanvasKey = ! @"Java CoreGraphics Text Renderer Cached Canvas for LCD"; /* * This is the maximum length and height times the above slack squared * to determine if we go with the global canvas, or malloc one on the spot. */
*** 676,706 **** { if (maxWidth*maxHeight*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK > CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK) { CGGI_GlyphCanvas *tmpCanvas = [[CGGI_GlyphCanvas alloc] init]; ! CGGI_InitCanvas(tmpCanvas, maxWidth, maxHeight); CGGI_FillImagesForGlyphsWithSizedCanvas(tmpCanvas, strike, mode, glyphInfos, uniChars, glyphs, len); CGGI_FreeCanvas(tmpCanvas); [tmpCanvas release]; return; } - NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary]; ! CGGI_GlyphCanvas *canvas = [threadDict objectForKey:threadLocalCanvasKey]; if (canvas == nil) { canvas = [[CGGI_GlyphCanvas alloc] init]; ! [threadDict setObject:canvas forKey:threadLocalCanvasKey]; } ! CGGI_SizeCanvas(canvas, maxWidth, maxHeight, mode->cgFontMode); CGGI_FillImagesForGlyphsWithSizedCanvas(canvas, strike, mode, glyphInfos, uniChars, glyphs, len); } /* * Finds the advances and bounding boxes of the characters in the run, * cycles through all the bounds and calculates the maximum canvas space --- 760,808 ---- { if (maxWidth*maxHeight*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK > CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK) { CGGI_GlyphCanvas *tmpCanvas = [[CGGI_GlyphCanvas alloc] init]; ! CGGI_InitCanvas(tmpCanvas, maxWidth, maxHeight, mode); ! // create black-on-white glyph image ! CGGI_FillImagesForGlyphsWithSizedCanvas(tmpCanvas, strike, ! mode, glyphInfos, uniChars, ! glyphs, len); ! ! // merge glyph image with white-on-black glyph ! tmpCanvas->stage = WHITE_ON_BLACK_STAGE; CGGI_FillImagesForGlyphsWithSizedCanvas(tmpCanvas, strike, mode, glyphInfos, uniChars, glyphs, len); CGGI_FreeCanvas(tmpCanvas); [tmpCanvas release]; return; } NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary]; ! ! NSString* theKey = (mode->glyphDescriptor == &rgb) ? ! threadLocalLCDCanvasKey : threadLocalAACanvasKey; ! ! CGGI_GlyphCanvas *canvas = [threadDict objectForKey:theKey]; if (canvas == nil) { canvas = [[CGGI_GlyphCanvas alloc] init]; ! [threadDict setObject:canvas forKey:theKey]; } ! CGGI_SizeCanvas(canvas, maxWidth, maxHeight, mode); ! // create black-on-white glyph image ! canvas->stage = BLACK_ON_WHITE_STAGE; CGGI_FillImagesForGlyphsWithSizedCanvas(canvas, strike, mode, glyphInfos, uniChars, glyphs, len); + + // merge glyph image with white-on-black glyph + canvas->stage = WHITE_ON_BLACK_STAGE; + CGGI_FillImagesForGlyphsWithSizedCanvas(canvas, strike, mode, + glyphInfos, uniChars, glyphs, len); + } /* * Finds the advances and bounding boxes of the characters in the run, * cycles through all the bounds and calculates the maximum canvas space
< prev index next >