191 #endif
192 }
193
194 #endif
195
196
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 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
225 static inline void
226 CGGI_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
235 static void
236 CGGI_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;
279 //}
280
281 static inline UInt8
282 CGGI_ConvertBWPixelToByteGray(UInt32 p)
283 {
284 return 0xFF - (((p >> 24 & 0xFF) + (p >> 16 & 0xFF) + (p >> 8 & 0xFF)) / 3);
285 }
286
287 static void
288 CGGI_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
312
313 #pragma mark --- Pixel Size, Modes, and Canvas Shaping Helper Functions ---
314
315 typedef struct CGGI_GlyphInfoDescriptor {
316 size_t pixelSize;
317 void (*copyFxnPtr)(CGGI_GlyphCanvas *canvas, GlyphInfo *info);
318 } CGGI_GlyphInfoDescriptor;
319
384
385 canvas->image->data = (void *)calloc(byteCount, sizeof(UInt8));
386 if (canvas->image->data == NULL) {
387 [[NSException exceptionWithName:NSMallocException
388 reason:@"Failed to allocate memory for the buffer which backs the CGContext for glyph strikes." userInfo:nil] raise];
389 }
390
391 uint32_t bmpInfo = kCGImageAlphaPremultipliedFirst;
392 if (mode->glyphDescriptor == &rgb) {
393 bmpInfo |= kCGBitmapByteOrder32Host;
394 }
395
396 CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
397 canvas->context = CGBitmapContextCreate(canvas->image->data,
398 width, height, 8, bytesPerRow,
399 colorSpace,
400 bmpInfo);
401
402 // set foreground color
403 CGContextSetRGBFillColor(canvas->context, 0.0f, 0.0f, 0.0f, 1.0f);
404
405 CGContextSetFontSize(canvas->context, 1);
406 CGContextSaveGState(canvas->context);
407
408 CGColorSpaceRelease(colorSpace);
409 }
410
411 /*
412 * Releases the BitmapContext and the associated memory backing it.
413 */
414 static inline void
415 CGGI_FreeCanvas(CGGI_GlyphCanvas *canvas)
416 {
417 if (canvas->context != NULL) {
418 CGContextRelease(canvas->context);
419 }
420
421 if (canvas->image != NULL) {
422 if (canvas->image->data != NULL) {
423 free(canvas->image->data);
424 }
725 const CFIndex len)
726 {
727 if (maxWidth*maxHeight*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK >
728 CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK)
729 {
730 CGGI_GlyphCanvas *tmpCanvas = [[CGGI_GlyphCanvas alloc] init];
731 CGGI_InitCanvas(tmpCanvas, maxWidth, maxHeight, mode);
732 CGGI_FillImagesForGlyphsWithSizedCanvas(tmpCanvas, strike,
733 mode, glyphInfos, uniChars,
734 glyphs, len);
735 CGGI_FreeCanvas(tmpCanvas);
736
737 [tmpCanvas release];
738 return;
739 }
740 NSMutableDictionary *threadDict =
741 [[NSThread currentThread] threadDictionary];
742
743 NSString* theKey = (mode->glyphDescriptor == &rgb) ?
744 threadLocalLCDCanvasKey : threadLocalAACanvasKey;
745
746 CGGI_GlyphCanvas *canvas = [threadDict objectForKey:theKey];
747 if (canvas == nil) {
748 canvas = [[CGGI_GlyphCanvas alloc] init];
749 [threadDict setObject:canvas forKey:theKey];
750 }
751
752 CGGI_SizeCanvas(canvas, maxWidth, maxHeight, mode);
753 CGGI_FillImagesForGlyphsWithSizedCanvas(canvas, strike, mode,
754 glyphInfos, uniChars, glyphs, len);
755 }
756
757 /*
758 * Finds the advances and bounding boxes of the characters in the run,
759 * cycles through all the bounds and calculates the maximum canvas space
760 * required by the largest glyph.
761 *
762 * Creates a GlyphInfo struct with a malloc that also encapsulates the
763 * image the struct points to. This is done to meet memory layout
764 * expectations in the Sun text rasterizer memory managment code.
765 * The image immediately follows the struct physically in memory.
|
191 #endif
192 }
193
194 #endif
195
196
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 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
225 static inline void
226 CGGI_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
235 static void
236 CGGI_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;
279 //}
280
281 static inline UInt8
282 CGGI_ConvertBWPixelToByteGray(UInt32 p)
283 {
284 return 0xFF - (((p >> 24 & 0xFF) + (p >> 16 & 0xFF) + (p >> 8 & 0xFF)) / 3);
285 }
286
287 static void
288 CGGI_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
312
313 #pragma mark --- Pixel Size, Modes, and Canvas Shaping Helper Functions ---
314
315 typedef struct CGGI_GlyphInfoDescriptor {
316 size_t pixelSize;
317 void (*copyFxnPtr)(CGGI_GlyphCanvas *canvas, GlyphInfo *info);
318 } CGGI_GlyphInfoDescriptor;
319
384
385 canvas->image->data = (void *)calloc(byteCount, sizeof(UInt8));
386 if (canvas->image->data == NULL) {
387 [[NSException exceptionWithName:NSMallocException
388 reason:@"Failed to allocate memory for the buffer which backs the CGContext for glyph strikes." userInfo:nil] raise];
389 }
390
391 uint32_t bmpInfo = kCGImageAlphaPremultipliedFirst;
392 if (mode->glyphDescriptor == &rgb) {
393 bmpInfo |= kCGBitmapByteOrder32Host;
394 }
395
396 CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
397 canvas->context = CGBitmapContextCreate(canvas->image->data,
398 width, height, 8, bytesPerRow,
399 colorSpace,
400 bmpInfo);
401
402 // set foreground color
403 CGContextSetRGBFillColor(canvas->context, 0.0f, 0.0f, 0.0f, 1.0f);
404
405 CGContextSetFontSize(canvas->context, 1);
406 CGContextSaveGState(canvas->context);
407
408 CGColorSpaceRelease(colorSpace);
409 }
410
411 /*
412 * Releases the BitmapContext and the associated memory backing it.
413 */
414 static inline void
415 CGGI_FreeCanvas(CGGI_GlyphCanvas *canvas)
416 {
417 if (canvas->context != NULL) {
418 CGContextRelease(canvas->context);
419 }
420
421 if (canvas->image != NULL) {
422 if (canvas->image->data != NULL) {
423 free(canvas->image->data);
424 }
725 const CFIndex len)
726 {
727 if (maxWidth*maxHeight*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK >
728 CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK)
729 {
730 CGGI_GlyphCanvas *tmpCanvas = [[CGGI_GlyphCanvas alloc] init];
731 CGGI_InitCanvas(tmpCanvas, maxWidth, maxHeight, mode);
732 CGGI_FillImagesForGlyphsWithSizedCanvas(tmpCanvas, strike,
733 mode, glyphInfos, uniChars,
734 glyphs, len);
735 CGGI_FreeCanvas(tmpCanvas);
736
737 [tmpCanvas release];
738 return;
739 }
740 NSMutableDictionary *threadDict =
741 [[NSThread currentThread] threadDictionary];
742
743 NSString* theKey = (mode->glyphDescriptor == &rgb) ?
744 threadLocalLCDCanvasKey : threadLocalAACanvasKey;
745
746 CGGI_GlyphCanvas *canvas = [threadDict objectForKey:theKey];
747 if (canvas == nil) {
748 canvas = [[CGGI_GlyphCanvas alloc] init];
749 [threadDict setObject:canvas forKey:theKey];
750 }
751
752 CGGI_SizeCanvas(canvas, maxWidth, maxHeight, mode);
753 CGGI_FillImagesForGlyphsWithSizedCanvas(canvas, strike, mode,
754 glyphInfos, uniChars, glyphs, len);
755 }
756
757 /*
758 * Finds the advances and bounding boxes of the characters in the run,
759 * cycles through all the bounds and calculates the maximum canvas space
760 * required by the largest glyph.
761 *
762 * Creates a GlyphInfo struct with a malloc that also encapsulates the
763 * image the struct points to. This is done to meet memory layout
764 * expectations in the Sun text rasterizer memory managment code.
765 * The image immediately follows the struct physically in memory.
|