/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import <Accelerate/Accelerate.h> // for vImage_Buffer
#import "CGGlyphImages.h"
#import "CoreTextSupport.h"
#import "fontscalerdefs.h" // contains the definition of GlyphInfo struct
#import "sun_awt_SunHints.h"
//#define USE_IMAGE_ALIGNED_MEMORY 1
//#define CGGI_DEBUG 1
//#define CGGI_DEBUG_DUMP 1
//#define CGGI_DEBUG_HIT_COUNT 1
/*
* The GlyphCanvas is a global shared CGContext that characters are struck into.
* For each character, the glyph is struck, copied into a GlyphInfo struct, and
* 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.
*/
@interface CGGI_GlyphCanvas : NSObject {
@public
}
@end;
@end
/*
* These debug functions are only compiled when CGGI_DEBUG is activated.
* They will print out a full UInt8 canvas and any pixels struck (assuming
* the canvas is not too big).
*
* As another debug feature, the entire canvas will be filled with a light
* alpha value so it is easy to see where the glyph painting regions are
* at runtime.
*/
static void
{
printf("| too big\n");
return;
}
for (i = 0; i < size; i++) {
for (k = 0; k < bytesPerPixel; k++) {
}
}
if (j == 0) {
printf("| empty\n");
return;
}
printf("|_");
int x, y;
for (x = 0; x < width; x++) {
printf("__");
}
printf("_\n");
for (y = 0; y < height; y++) {
printf("| ");
for (x = 0; x < width; x++) {
int p = 0;
for(k = 0; k < bytesPerPixel; k++) {
}
if (p < 0x80) {
printf(" ");
} else {
printf("[]");
}
}
printf(" |\n");
}
}
static void
{
}
static void
{
#if 0
}
fprintf(stderr, " [linewidth: %f] [linecap: %d] [linejoin: %d] [miterlimit: %f] [dashcount: %lu]\n",
}
static void
{
printf("size: (%d, %d) pixelSize: %d\n",
printf("adv: (%f, %f) top: (%f, %f)\n",
DUMP_PIXELS("Glyph Info Struct",
}
static inline void
{
#else
}
static void
{
size_t y;
for (y = 0; y < height; y++) {
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);
}
}
}
//static void CGGI_copyImageFromCanvasToAlphaInfo
//(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
//{
// vImage_Buffer infoBuffer;
// infoBuffer.data = info->image;
// infoBuffer.width = info->width;
// infoBuffer.height = info->height;
// infoBuffer.rowBytes = info->width; // three bytes per RGB pixel
//
// UInt8 scrapPixel[info->width * info->height];
// vImage_Buffer scrapBuffer;
// scrapBuffer.data = &scrapPixel;
// scrapBuffer.width = info->width;
// scrapBuffer.height = info->height;
// scrapBuffer.rowBytes = info->width;
//
// vImageConvert_ARGB8888toPlanar8(canvas->image, &infoBuffer,
// &scrapBuffer, &scrapBuffer, &scrapBuffer, kvImageNoFlags);
//}
{
return 0xFF - ((p >> 24 & 0xFF) + (p >> 16 & 0xFF) + (p >> 8 & 0xFF)) / 3;
#else
return 0xFF - ((p >> 16 & 0xFF) + (p >> 8 & 0xFF) + (p & 0xFF)) / 3;
}
static void
{
size_t y;
for (y = 0; y < height; y++) {
size_t x;
for (x = 0; x < destRowWidth; x++) {
}
}
}
static CGGI_GlyphInfoDescriptor grey =
{ 1, &CGGI_CopyImageFromCanvasToAlphaInfo };
static CGGI_GlyphInfoDescriptor rgb =
{ 3, &CGGI_CopyImageFromCanvasToRGBInfo };
static inline CGGI_RenderingMode
{
default:
break;
break;
}
return mode;
}
/*
* 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
{
// our canvas is *always* 4-byte ARGB
reason:@"Failed to allocate memory for the buffer which backs the CGContext for glyph strikes." userInfo:nil] raise];
}
}
/*
* Releases the BitmapContext and the associated memory backing it.
*/
static inline void
{
}
}
}
}
/*
* This is the slack space that is preallocated for the global GlyphCanvas
* when it needs to be expanded. It has been set somewhat liberally to
* avoid re-upsizing frequently.
*/
/*
* 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)
{
{
return;
}
// if we don't have enough space to strike the largest glyph in the
// run, resize the canvas
}
/*
* 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).
*/
static inline void
{
// use the row stride of the canvas, not the info
// clean the canvas
#else
}
/*
* Creates a GlyphInfo with exactly the correct size image and measurements.
*/
const CGGI_RenderingMode *mode)
{
// adjust the bounding box to be 1px bigger on each side than what
// CGFont-whatever suggests - because it gives a bounding box that
// is too tight
// if the glyph is larger than 1MB, don't even try...
// the GlyphVector path should have taken over by now
// and zero pixels is ok
width = 1;
height = 1;
}
// create separate memory
#else
// create a GlyphInfo struct fused to the image it points to
#else
return glyphInfo;
}
/*
* Clears the canvas, strikes the glyph with CoreGraphics, and then
* copies the struck pixels into the GlyphInfo image.
*/
static inline void
{
// clean the canvas
// strike the glyph in the upper right corner
&glyph, 1);
// copy the glyph from the canvas into the info
}
/*
* CoreText path...
*/
{
// save the state of the world
// get the glyph, measure it using CG
if (uniChar > 0xFFFF) {
fallback = CTS_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, (CGGlyph *)&glyphTmp, 2);
} else {
fallback = CTS_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, &glyph, 1);
}
// create the Sun2D GlyphInfo we are going to strike into
// fix the context size, just in case the substituted character is unexpectedly large
// align the transform for the real CoreText strike
// clean the canvas - align, strike, and copy the glyph from the canvas into the info
// restore the state of the world
#if 0
return info;
}
/*
* Sets all the per-run properties for the canvas, and then iterates through
* the character run, and creates images in the GlyphInfo structs.
*
* Not inlined because it would create two copies in the function below
*/
static void
const CGGI_RenderingMode *mode,
jlong glyphInfos[],
{
CFIndex i;
for (i = 0; i < len; i++) {
} else {
}
}
}
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.
*/
/*
* Based on the space needed to strike the largest character in the run,
* either use the global shared canvas, or make one up on the spot, strike
* the glyphs, and destroy it.
*/
static inline void
const CGGI_RenderingMode *mode,
{
{
return;
}
}
}
/*
* Finds the advances and bounding boxes of the characters in the run,
* cycles through all the bounds and calculates the maximum canvas space
* required by the largest glyph.
*
* Creates a GlyphInfo struct with a malloc that also encapsulates the
* image the struct points to. This is done to meet memory layout
* expectations in the Sun text rasterizer memory managment code.
* The image immediately follows the struct physically in memory.
*/
static inline void
const CGGI_RenderingMode *mode,
{
JRSFontGetBoundingBoxesForGlyphsAndStyle((CTFontRef)font->fFont, &tx, bboxCGMode, glyphs, len, bboxes);
JRSFontGetAdvancesForGlyphsAndStyle((CTFontRef)font->fFont, &tx, strike->fStyle, glyphs, len, advances);
CFIndex i;
for (i = 0; i < len; i++)
{
if (uniChars[i] != 0)
{
glyphInfos[i] = 0L;
continue; // will be handled later
}
}
}
/*
* This stage separates the already valid glyph codes from the unicode values
* that need special handling - the rawGlyphCodes array is no longer used
* after this stage.
*/
static void
const CGGI_RenderingMode *mode,
{
CFIndex i;
for (i = 0; i < len; i++) {
if (code < 0) {
glyphs[i] = 0;
} else {
uniChars[i] = 0;
}
}
hitCount++;
}
/*
* Conditionally stack allocates buffers for glyphs, bounding boxes,
* and advances. Unfortunately to use CG or CT in bulk runs (which is
* faster than calling them per character), we have to copy into and out
* of these buffers. Still a net win though.
*/
void
{
if (len < MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE) {
return;
}
// just do one malloc, and carve it up for all the buffers
reason:@"Failed to allocate memory for the temporary glyph strike and measurement buffers." userInfo:nil] raise];
}
}