| /* |
| * 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; |
| } |