blob: 29a579f66b4f5dd7ddbc2fb42d13c8a5c4718122 [file] [log] [blame]
/*
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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 "CGGlyphOutlines.h"
static void
AWTPathGetMoreSpaceIfNecessary(AWTPathRef path)
{
while ((path->fAllocatedSegmentTypeSpace - path->fNumberOfSegments) < 1) {
size_t growth = sizeof(jbyte)*path->fAllocatedSegmentTypeSpace*kStorageSizeChangeOnGetMoreFactor;
path->fSegmentType = (jbyte*) realloc(path->fSegmentType, growth);
path->fAllocatedSegmentTypeSpace *= kStorageSizeChangeOnGetMoreFactor;
}
while ((path->fAllocatedSegmentDataSpace - path->fNumberOfDataElements) < 7) {
size_t growth = sizeof(jfloat)*path->fAllocatedSegmentDataSpace*kStorageSizeChangeOnGetMoreFactor;
path->fSegmentData = (jfloat*) realloc(path->fSegmentData, growth);
path->fAllocatedSegmentDataSpace *= kStorageSizeChangeOnGetMoreFactor;
}
}
static void
AWTPathMoveTo(void* data, CGPoint p)
{
CGFloat x = p.x;
CGFloat y = p.y;
AWTPathRef path = (AWTPathRef)data;
CGFloat tx = path->fTranslate.width;
CGFloat ty = path->fTranslate.height;
CGFloat pathX = x+tx;
CGFloat pathY = -y+ty;
#ifdef AWT_GV_DEBUG
fprintf(stderr, "eMoveTo \n");
fprintf(stderr, " tx=%f, ty=%f\n", tx, ty);
fprintf(stderr, " x=%f, y=%f\n", x, y);
fprintf(stderr, " pathX=%f, pathY=%f\n", pathX, pathY);
#endif
AWTPathGetMoreSpaceIfNecessary(path);
path->fSegmentType[path->fNumberOfSegments++] = (jbyte)eMoveTo;
path->fSegmentData[path->fNumberOfDataElements++] = pathX;
path->fSegmentData[path->fNumberOfDataElements++] = pathY;
}
static void
AWTPathLineTo(void* data, CGPoint p)
{
CGFloat x = p.x;
CGFloat y = p.y;
AWTPathRef path = (AWTPathRef)data;
CGFloat tx = path->fTranslate.width;
CGFloat ty = path->fTranslate.height;
CGFloat pathX = x+tx;
CGFloat pathY = -y+ty;
#ifdef AWT_GV_DEBUG
fprintf(stderr, "eLineTo \n");
fprintf(stderr, " tx=%f, ty=%f\n", tx, ty);
fprintf(stderr, " x=%f, y=%f\n", x, y);
fprintf(stderr, " pathX=%f, pathY=%f\n", pathX, pathY);
#endif
AWTPathGetMoreSpaceIfNecessary(path);
path->fSegmentType[path->fNumberOfSegments++] = (jbyte)eLineTo;
path->fSegmentData[path->fNumberOfDataElements++] = pathX;
path->fSegmentData[path->fNumberOfDataElements++] = pathY;
}
static void
AWTPathQuadTo(void* data, CGPoint p1, CGPoint p2)
{
CGFloat x1 = p1.x;
CGFloat y1 = p1.y;
CGFloat x2 = p2.x;
CGFloat y2 = p2.y;
AWTPathRef path = (AWTPathRef)data;
CGFloat tx = path->fTranslate.width;
CGFloat ty = path->fTranslate.height;
CGFloat pathX1 = x1+tx;
CGFloat pathY1 = -y1+ty;
CGFloat pathX2 = x2+tx;
CGFloat pathY2 = -y2+ty;
#ifdef AWT_GV_DEBUG
fprintf(stderr, "eQuadTo \n");
fprintf(stderr, " tx=%f, ty=%f\n", tx, ty);
fprintf(stderr, " x1=%f, y1=%f\n", x1, y1);
fprintf(stderr, " x2=%f, y2=%f\n", x2, y2);
fprintf(stderr, " pathX1=%f, path1Y=%f\n", pathX1, pathY1);
fprintf(stderr, " pathX2=%f, pathY2=%f\n", pathX2, pathY2);
#endif
AWTPathGetMoreSpaceIfNecessary(path);
path->fSegmentType[path->fNumberOfSegments++] = (jbyte)eQuadTo;
path->fSegmentData[path->fNumberOfDataElements++] = pathX1;
path->fSegmentData[path->fNumberOfDataElements++] = pathY1;
path->fSegmentData[path->fNumberOfDataElements++] = pathX2;
path->fSegmentData[path->fNumberOfDataElements++] = pathY2;
}
static void
AWTPathCubicTo(void* data, CGPoint p1, CGPoint p2, CGPoint p3)
{
CGFloat x1 = p1.x;
CGFloat y1 = p1.y;
CGFloat x2 = p2.x;
CGFloat y2 = p2.y;
CGFloat x3 = p3.x;
CGFloat y3 = p3.y;
AWTPathRef path = (AWTPathRef)data;
CGFloat tx = path->fTranslate.width;
CGFloat ty = path->fTranslate.height;
CGFloat pathX1 = x1+tx;
CGFloat pathY1 = -y1+ty;
CGFloat pathX2 = x2+tx;
CGFloat pathY2 = -y2+ty;
CGFloat pathX3 = x3+tx;
CGFloat pathY3 = -y3+ty;
#ifdef AWT_GV_DEBUG
fprintf(stderr, "eCubicTo \n");
fprintf(stderr, " tx=%f, ty=%f\n", tx, ty);
fprintf(stderr, " x1=%f, y1=%f\n", x1, y1);
fprintf(stderr, " x2=%f, y2=%f\n", x2, y2);
fprintf(stderr, " x3=%f, y3=%f\n", x3, y3);
fprintf(stderr, " pathX1=%f, path1Y=%f\n", pathX1, pathY1);
fprintf(stderr, " pathX2=%f, pathY2=%f\n", pathX2, pathY2);
fprintf(stderr, " pathX3=%f, pathY3=%f\n", pathX3, pathY3);
#endif
AWTPathGetMoreSpaceIfNecessary(path);
path->fSegmentType[path->fNumberOfSegments++] = (jbyte)eCubicTo;
path->fSegmentData[path->fNumberOfDataElements++] = pathX1;
path->fSegmentData[path->fNumberOfDataElements++] = pathY1;
path->fSegmentData[path->fNumberOfDataElements++] = pathX2;
path->fSegmentData[path->fNumberOfDataElements++] = pathY2;
path->fSegmentData[path->fNumberOfDataElements++] = pathX3;
path->fSegmentData[path->fNumberOfDataElements++] = pathY3;
}
static void
AWTPathClose(void* data)
{
#ifdef AWT_GV_DEBUG
fprintf(stderr, "GVGlyphPathCallBackClosePath \n");
#endif
AWTPathRef path = (AWTPathRef) data;
AWTPathGetMoreSpaceIfNecessary(path);
path->fSegmentType[path->fNumberOfSegments++] = (jbyte)eClosePath;
}
AWTPathRef
AWTPathCreate(CGSize translate)
{
#ifdef AWT_GV_DEBUG
fprintf(stderr, "AWTPathCreate \n");
fprintf(stderr, " translate.width=%f \n", translate.width);
fprintf(stderr, " translate.height=%f \n", translate.height);
#endif
AWTPathRef path = (AWTPathRef) malloc(sizeof(AWTPath));
path->fTranslate = translate;
path->fSegmentData = (jfloat*)malloc(sizeof(jfloat) * kInitialAllocatedPathSegments);
path->fSegmentType = (jbyte*)malloc(sizeof(jbyte) * kInitialAllocatedPathSegments);
path->fNumberOfDataElements = 0;
path->fNumberOfSegments = 0;
path->fAllocatedSegmentTypeSpace = kInitialAllocatedPathSegments;
path->fAllocatedSegmentDataSpace = kInitialAllocatedPathSegments;
return path;
}
void
AWTPathFree(AWTPathRef pathRef)
{
#ifdef AWT_GV_DEBUG
fprintf(stderr, "--B--AWTPathFree\n");
fprintf(stderr, "pathRef->fSegmentData (%p)\n",pathRef->fSegmentData);
#endif
free(pathRef->fSegmentData);
//fprintf(stderr, "pathRef->fSegmentType (%d)\n",pathRef->fSegmentType);
free(pathRef->fSegmentType);
//fprintf(stderr, "pathRef (%d)\n", pathRef);
free(pathRef);
//fprintf(stderr, "--E--AWTPathFree\n");
}
static void
AWTPathApplierCallback(void *info, const CGPathElement *element)
{
switch (element->type) {
case kCGPathElementMoveToPoint:
AWTPathMoveTo(info, element->points[0]);
break;
case kCGPathElementAddLineToPoint:
AWTPathLineTo(info, element->points[0]);
break;
case kCGPathElementAddQuadCurveToPoint:
AWTPathQuadTo(info, element->points[0], element->points[1]);
break;
case kCGPathElementAddCurveToPoint:
AWTPathCubicTo(info, element->points[0],
element->points[1], element->points[2]);
break;
case kCGPathElementCloseSubpath:
AWTPathClose(info);
break;
}
}
OSStatus
AWTGetGlyphOutline(CGGlyph *glyphs, NSFont *font,
CGSize *advanceArray, CGAffineTransform *tx,
UInt32 inStartIndex, size_t length,
AWTPathRef* outPath)
{
#ifdef AWT_GV_DEBUG
fprintf(stderr, "AWTGetGlyphOutline\n");
fprintf(stderr, " inAffineTransform a=%f, b=%f, c=%f, d=%f, tx=%f, ty=%f \n", tx->a, tx->b, tx->c, tx->d, tx->tx, tx->ty);
#endif
OSStatus status = noErr;
glyphs = glyphs + inStartIndex;
// advanceArray = advanceArray + inStartIndex; // TODO(cpc): use advance
CGPathRef cgPath = CTFontCreatePathForGlyph((CTFontRef)font, glyphs[0], tx);
CGPathApply(cgPath, *outPath, AWTPathApplierCallback);
CGPathRelease(cgPath);
return status;
}