4632N/A/*
4632N/A * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
4632N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4632N/A *
4632N/A * This code is free software; you can redistribute it and/or modify it
4632N/A * under the terms of the GNU General Public License version 2 only, as
4632N/A * published by the Free Software Foundation. Oracle designates this
4632N/A * particular file as subject to the "Classpath" exception as provided
4632N/A * by Oracle in the LICENSE file that accompanied this code.
4632N/A *
4632N/A * This code is distributed in the hope that it will be useful, but WITHOUT
4632N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4632N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
4632N/A * version 2 for more details (a copy is included in the LICENSE file that
4632N/A * accompanied this code).
4632N/A *
4632N/A * You should have received a copy of the GNU General Public License version
4632N/A * 2 along with this work; if not, write to the Free Software Foundation,
4632N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
4632N/A *
4632N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
4632N/A * or visit www.oracle.com if you need additional information or have any
4632N/A * questions.
4632N/A */
4632N/A
4632N/A#import "QuartzSurfaceData.h"
4632N/A
4632N/A#import "java_awt_BasicStroke.h"
4632N/A#import "java_awt_AlphaComposite.h"
4632N/A#import "java_awt_geom_PathIterator.h"
4632N/A#import "java_awt_image_BufferedImage.h"
4632N/A#import "sun_awt_SunHints.h"
4632N/A#import "sun_java2d_CRenderer.h"
4632N/A#import "sun_java2d_OSXSurfaceData.h"
4632N/A#import "sun_lwawt_macosx_CPrinterSurfaceData.h"
4632N/A#import "ImageSurfaceData.h"
4632N/A
4632N/A#import <JavaNativeFoundation/JavaNativeFoundation.h>
4632N/A
4632N/A#import <AppKit/AppKit.h>
4632N/A#import "ThreadUtilities.h"
4632N/A
4632N/A//#define DEBUG
4632N/A#if defined DEBUG
4632N/A #define PRINT(msg) {fprintf(stderr, "%s\n", msg);}
4632N/A#else
4632N/A #define PRINT(msg) {}
4632N/A#endif
4632N/A
4632N/A#define kOffset (0.5f)
4632N/A
4632N/ABOOL gAdjustForJavaDrawing;
4632N/A
4632N/A#pragma mark
4632N/A#pragma mark --- Color Cache ---
4632N/A
4632N/A// Creating and deleting CGColorRefs can be expensive, therefore we have a color cache.
4632N/A// The color cache was first introduced with <rdar://problem/3923927>
4632N/A// With <rdar://problem/4280514>, the hashing function was improved
4632N/A// With <rdar://problem/4012223>, the color cache became global (per process) instead of per surface.
4632N/A
4632N/A// Must be power of 2. 1024 is the least power of 2 number that makes SwingSet2 run without any non-empty cache misses
4632N/A#define gColorCacheSize 1024
4632N/Astruct _ColorCacheInfo
4632N/A{
4632N/A UInt32 keys[gColorCacheSize];
4632N/A CGColorRef values[gColorCacheSize];
4632N/A};
4632N/Astatic struct _ColorCacheInfo colorCacheInfo;
4632N/A
4632N/Astatic pthread_mutex_t gColorCacheLock = PTHREAD_MUTEX_INITIALIZER;
4632N/A
4632N/A// given a UInt32 color, it tries to find that find the corresponding CGColorRef in the hash cache. If the CGColorRef
4632N/A// doesn't exist or there is a collision, it creates a new one CGColorRef and put's in the cache. Then,
4632N/A// it sets with current fill/stroke color for the the CGContext passed in (qsdo->cgRef).
4632N/Avoid setCachedColor(QuartzSDOps *qsdo, UInt32 color)
4632N/A{
4632N/A static const CGFloat kColorConversionMultiplier = 1.0f/255.0f;
4632N/A
4632N/A pthread_mutex_lock(&gColorCacheLock);
4632N/A
4632N/A static CGColorSpaceRef colorspace = NULL;
4632N/A if (colorspace == NULL)
4632N/A {
4632N/A colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
4632N/A }
4632N/A
4632N/A CGColorRef cgColor = NULL;
4632N/A
4632N/A // The colors passed have low randomness. That means we need to scramble the bits of the color
4632N/A // to produce a good hash key. After some analysis, it looks like Thomas's Wang integer hasing algorithm
4632N/A // seems a nice trade off between performance and effectivness.
4632N/A UInt32 index = color;
4632N/A index += ~(index << 15);
4632N/A index ^= (index >> 10);
4632N/A index += (index << 3);
4632N/A index ^= (index >> 6);
4632N/A index += ~(index << 11);
4632N/A index ^= (index >> 16);
4632N/A index = index & (gColorCacheSize - 1); // The bits are scrambled, we just need to make sure it fits inside our table
4632N/A
4632N/A UInt32 key = colorCacheInfo.keys[index];
4632N/A CGColorRef value = colorCacheInfo.values[index];
4632N/A if ((key == color) && (value != NULL))
4632N/A {
4632N/A //fprintf(stderr, "+");fflush(stderr);//hit
4632N/A cgColor = value;
4632N/A }
4632N/A else
4632N/A {
4632N/A if (value != NULL)
4632N/A {
4632N/A //fprintf(stderr, "!");fflush(stderr);//miss and replace - double ouch
4632N/A CGColorRelease(value);
4632N/A }
4632N/A //fprintf(stderr, "-");fflush(stderr);// miss
4632N/A
4632N/A CGFloat alpha = ((color>>24)&0xff)*kColorConversionMultiplier;
4632N/A CGFloat red = ((color>>16)&0xff)*kColorConversionMultiplier;
4632N/A CGFloat green = ((color>>8)&0xff)*kColorConversionMultiplier;
4632N/A CGFloat blue = ((color>>0)&0xff)*kColorConversionMultiplier;
4632N/A const CGFloat components[] = {red, green, blue, alpha, 1.0f};
4632N/A value = CGColorCreate(colorspace, components);
4632N/A
4632N/A colorCacheInfo.keys[index] = color;
4632N/A colorCacheInfo.values[index] = value;
4632N/A
4632N/A cgColor = value;
4632N/A }
4632N/A
4632N/A CGContextSetStrokeColorWithColor(qsdo->cgRef, cgColor);
4632N/A CGContextSetFillColorWithColor(qsdo->cgRef, cgColor);
4632N/A
4632N/A pthread_mutex_unlock(&gColorCacheLock);
4632N/A}
4632N/A
4632N/A#pragma mark
4632N/A#pragma mark --- Gradient ---
4632N/A
4632N/A// this function MUST NOT be inlined!
4632N/Avoid gradientLinearPaintEvaluateFunction(void *info, const CGFloat *in, CGFloat *out)
4632N/A{
4632N/A StateShadingInfo *shadingInfo = (StateShadingInfo *)info;
4632N/A CGFloat *colors = shadingInfo->colors;
4632N/A CGFloat range = *in;
4632N/A CGFloat c1, c2;
4632N/A jint k;
4632N/A
4632N/A//fprintf(stderr, "range=%f\n", range);
4632N/A for (k=0; k<4; k++)
4632N/A {
4632N/A c1 = colors[k];
4632N/A//fprintf(stderr, " c1=%f", c1);
4632N/A c2 = colors[k+4];
4632N/A//fprintf(stderr, ", c2=%f", c2);
4632N/A if (c1 == c2)
4632N/A {
4632N/A *out++ = c2;
4632N/A//fprintf(stderr, ", %f", *(out-1));
4632N/A }
4632N/A else if (c1 > c2)
4632N/A {
4632N/A *out++ = c1 - ((c1-c2)*range);
4632N/A//fprintf(stderr, ", %f", *(out-1));
4632N/A }
4632N/A else// if (c1 < c2)
4632N/A {
4632N/A *out++ = c1 + ((c2-c1)*range);
4632N/A//fprintf(stderr, ", %f", *(out-1));
4632N/A }
4632N/A//fprintf(stderr, "\n");
4632N/A }
4632N/A}
4632N/A
4632N/A// this function MUST NOT be inlined!
4632N/Avoid gradientCyclicPaintEvaluateFunction(void *info, const CGFloat *in, CGFloat *out)
4632N/A{
4632N/A StateShadingInfo *shadingInfo = (StateShadingInfo *)info;
4632N/A CGFloat length = shadingInfo->length ;
4632N/A CGFloat period = shadingInfo->period;
4632N/A CGFloat offset = shadingInfo->offset;
4632N/A CGFloat periodLeft = offset;
4632N/A CGFloat periodRight = periodLeft+period;
4632N/A CGFloat *colors = shadingInfo->colors;
4632N/A CGFloat range = *in;
4632N/A CGFloat c1, c2;
4632N/A jint k;
4632N/A jint count = 0;
4632N/A
4632N/A range *= length;
4632N/A
4632N/A // put the range within the period
4632N/A if (range < periodLeft)
4632N/A {
4632N/A while (range < periodLeft)
4632N/A {
4632N/A range += period;
4632N/A count++;
4632N/A }
4632N/A
4632N/A range = range-periodLeft;
4632N/A }
4632N/A else if (range > periodRight)
4632N/A {
4632N/A count = 1;
4632N/A
4632N/A while (range > periodRight)
4632N/A {
4632N/A range -= period;
4632N/A count++;
4632N/A }
4632N/A
4632N/A range = periodRight-range;
4632N/A }
4632N/A else
4632N/A {
4632N/A range = range - offset;
4632N/A }
4632N/A range = range/period;
4632N/A
4632N/A // cycle up or down
4632N/A if (count%2 == 0)
4632N/A {
4632N/A for (k=0; k<4; k++)
4632N/A {
4632N/A c1 = colors[k];
4632N/A c2 = colors[k+4];
4632N/A if (c1 == c2)
4632N/A {
4632N/A *out++ = c2;
4632N/A }
4632N/A else if (c1 > c2)
4632N/A {
4632N/A *out++ = c1 - ((c1-c2)*range);
4632N/A }
4632N/A else// if (c1 < c2)
4632N/A {
4632N/A *out++ = c1 + ((c2-c1)*range);
4632N/A }
4632N/A }
4632N/A }
4632N/A else
4632N/A {
4632N/A for (k=0; k<4; k++)
4632N/A {
4632N/A c1 = colors[k+4];
4632N/A c2 = colors[k];
4632N/A if (c1 == c2)
4632N/A {
4632N/A *out++ = c2;
4632N/A }
4632N/A else if (c1 > c2)
4632N/A {
4632N/A *out++ = c1 - ((c1-c2)*range);
4632N/A }
4632N/A else// if (c1 < c2)
4632N/A {
4632N/A *out++ = c1 + ((c2-c1)*range);
4632N/A }
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A// this function MUST NOT be inlined!
4632N/Avoid gradientPaintReleaseFunction(void *info)
4632N/A{
4632N/APRINT(" gradientPaintReleaseFunction")
4632N/A free(info);
4632N/A}
4632N/A
4632N/Astatic inline void contextGradientPath(QuartzSDOps* qsdo)
4632N/A{
4632N/APRINT(" ContextGradientPath")
4632N/A CGContextRef cgRef = qsdo->cgRef;
4632N/A StateShadingInfo* shadingInfo = qsdo->shadingInfo;
4632N/A
4632N/A CGRect bounds = CGContextGetClipBoundingBox(cgRef);
4632N/A
4632N/A static const CGFloat domain[2] = {0.0f, 1.0f};
4632N/A static const CGFloat range[8] = {0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f};
4632N/A CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
4632N/A CGFunctionRef shadingFunc = NULL;
4632N/A CGShadingRef shading = NULL;
4632N/A if (shadingInfo->cyclic == NO)
4632N/A {
4632N/A static const CGFunctionCallbacks callbacks = {0, &gradientLinearPaintEvaluateFunction, &gradientPaintReleaseFunction};
4632N/A shadingFunc = CGFunctionCreate((void *)shadingInfo, 1, domain, 4, range, &callbacks);
4632N/A shading = CGShadingCreateAxial(colorspace, shadingInfo->start, shadingInfo->end, shadingFunc, 1, 1);
4632N/A }
4632N/A else
4632N/A {
4632N/A//fprintf(stderr, "BOUNDING BOX x1=%f, y1=%f x2=%f, y2=%f\n", bounds.origin.x, bounds.origin.y, bounds.origin.x+bounds.size.width, bounds.origin.y+bounds.size.height);
4632N/A // need to extend the line start-end
4632N/A
4632N/A CGFloat x1 = shadingInfo->start.x;
4632N/A CGFloat y1 = shadingInfo->start.y;
4632N/A CGFloat x2 = shadingInfo->end.x;
4632N/A CGFloat y2 = shadingInfo->end.y;
4632N/A//fprintf(stderr, "GIVEN x1=%f, y1=%f x2=%f, y2=%f\n", x1, y1, x2, y2);
4632N/A
4632N/A if (x1 == x2)
4632N/A {
4632N/A y1 = bounds.origin.y;
4632N/A y2 = y1 + bounds.size.height;
4632N/A }
4632N/A else if (y1 == y2)
4632N/A {
4632N/A x1 = bounds.origin.x;
4632N/A x2 = x1 + bounds.size.width;
4632N/A }
4632N/A else
4632N/A {
4632N/A // find the original line function y = mx + c
4632N/A CGFloat m1 = (y2-y1)/(x2-x1);
4632N/A CGFloat c1 = y1 - m1*x1;
4632N/A//fprintf(stderr, " m1=%f, c1=%f\n", m1, c1);
4632N/A
4632N/A // a line perpendicular to the original one will have the slope
4632N/A CGFloat m2 = -(1/m1);
4632N/A//fprintf(stderr, " m2=%f\n", m2);
4632N/A
4632N/A // find the only 2 possible lines perpendicular to the original line, passing the two top corners of the bounding box
4632N/A CGFloat x1A = bounds.origin.x;
4632N/A CGFloat y1A = bounds.origin.y;
4632N/A CGFloat c1A = y1A - m2*x1A;
4632N/A//fprintf(stderr, " x1A=%f, y1A=%f, c1A=%f\n", x1A, y1A, c1A);
4632N/A CGFloat x1B = bounds.origin.x+bounds.size.width;
4632N/A CGFloat y1B = bounds.origin.y;
4632N/A CGFloat c1B = y1B - m2*x1B;
4632N/A//fprintf(stderr, " x1B=%f, y1B=%f, c1B=%f\n", x1B, y1B, c1B);
4632N/A
4632N/A // find the crossing points of the original line and the two lines we computed above to find the new possible starting points
4632N/A CGFloat x1Anew = (c1A-c1)/(m1-m2);
4632N/A CGFloat y1Anew = m2*x1Anew + c1A;
4632N/A CGFloat x1Bnew = (c1B-c1)/(m1-m2);
4632N/A CGFloat y1Bnew = m2*x1Bnew + c1B;
4632N/A//fprintf(stderr, "NEW x1Anew=%f, y1Anew=%f x1Bnew=%f, y1Bnew=%f\n", x1Anew, y1Anew, x1Bnew, y1Bnew);
4632N/A
4632N/A // select the new starting point
4632N/A if (y1Anew <= y1Bnew)
4632N/A {
4632N/A x1 = x1Anew;
4632N/A y1 = y1Anew;
4632N/A }
4632N/A else
4632N/A {
4632N/A x1 = x1Bnew;
4632N/A y1 = y1Bnew;
4632N/A }
4632N/A//fprintf(stderr, "--- NEW x1=%f, y1=%f\n", x1, y1);
4632N/A
4632N/A // find the only 2 possible lines perpendicular to the original line, passing the two bottom corners of the bounding box
4632N/A CGFloat x2A = bounds.origin.x;
4632N/A CGFloat y2A = bounds.origin.y+bounds.size.height;
4632N/A CGFloat c2A = y2A - m2*x2A;
4632N/A//fprintf(stderr, " x2A=%f, y2A=%f, c2A=%f\n", x2A, y2A, c2A);
4632N/A CGFloat x2B = bounds.origin.x+bounds.size.width;
4632N/A CGFloat y2B = bounds.origin.y+bounds.size.height;
4632N/A CGFloat c2B = y2B - m2*x2B;
4632N/A//fprintf(stderr, " x2B=%f, y2B=%f, c2B=%f\n", x2B, y2B, c2B);
4632N/A
4632N/A // find the crossing points of the original line and the two lines we computed above to find the new possible ending points
4632N/A CGFloat x2Anew = (c2A-c1)/(m1-m2);
4632N/A CGFloat y2Anew = m2*x2Anew + c2A;
4632N/A CGFloat x2Bnew = (c2B-c1)/(m1-m2);
4632N/A CGFloat y2Bnew = m2*x2Bnew + c2B;
4632N/A//fprintf(stderr, "NEW x2Anew=%f, y2Anew=%f x2Bnew=%f, y2Bnew=%f\n", x2Anew, y2Anew, x2Bnew, y2Bnew);
4632N/A
4632N/A // select the new ending point
4632N/A if (y2Anew >= y2Bnew)
4632N/A {
4632N/A x2 = x2Anew;
4632N/A y2 = y2Anew;
4632N/A }
4632N/A else
4632N/A {
4632N/A x2 = x2Bnew;
4632N/A y2 = y2Bnew;
4632N/A }
4632N/A//fprintf(stderr, "--- NEW x2=%f, y2=%f\n", x2, y2);
4632N/A }
4632N/A
4632N/A qsdo->shadingInfo->period = sqrt(pow(shadingInfo->end.x-shadingInfo->start.x, 2.0) + pow(shadingInfo->end.y-shadingInfo->start.y, 2.0));
4632N/A if ((qsdo->shadingInfo->period != 0))
4632N/A {
4632N/A // compute segment lengths that we will need for the gradient function
4632N/A qsdo->shadingInfo->length = sqrt(pow(x2-x1, 2.0) + pow(y2-y1, 2.0));
4632N/A qsdo->shadingInfo->offset = sqrt(pow(shadingInfo->start.x-x1, 2.0) + pow(shadingInfo->start.y-y1, 2.0));
4632N/A//fprintf(stderr, "length=%f, period=%f, offset=%f\n", qsdo->shadingInfo->length, qsdo->shadingInfo->period, qsdo->shadingInfo->offset);
4632N/A
4632N/A CGPoint newStart = {x1, y1};
4632N/A CGPoint newEnd = {x2, y2};
4632N/A
4632N/A static const CGFunctionCallbacks callbacks = {0, &gradientCyclicPaintEvaluateFunction, &gradientPaintReleaseFunction};
4632N/A shadingFunc = CGFunctionCreate((void *)shadingInfo, 1, domain, 4, range, &callbacks);
4632N/A shading = CGShadingCreateAxial(colorspace, newStart, newEnd, shadingFunc, 0, 0);
4632N/A }
4632N/A }
4632N/A CGColorSpaceRelease(colorspace);
4632N/A
4632N/A if (shadingFunc != NULL)
4632N/A {
4632N/A CGContextSaveGState(cgRef);
4632N/A
4632N/A // rdar://problem/5214320
4632N/A // Gradient fills of Java GeneralPath don't respect the even odd winding rule (quartz pipeline).
4632N/A if (qsdo->isEvenOddFill) {
4632N/A CGContextEOClip(cgRef);
4632N/A } else {
4632N/A CGContextClip(cgRef);
4632N/A }
4632N/A CGContextDrawShading(cgRef, shading);
4632N/A
4632N/A CGContextRestoreGState(cgRef);
4632N/A CGShadingRelease(shading);
4632N/A CGFunctionRelease(shadingFunc);
4632N/A qsdo->shadingInfo = NULL;
4632N/A }
4632N/A}
4632N/A
4632N/A#pragma mark
4632N/A#pragma mark --- Texture ---
4632N/A
4632N/A// this function MUST NOT be inlined!
4632N/Avoid texturePaintEvaluateFunction(void *info, CGContextRef cgRef)
4632N/A{
4632N/A JNIEnv* env = [ThreadUtilities getJNIEnvUncached];
4632N/A
4632N/A StatePatternInfo* patternInfo = (StatePatternInfo*)info;
4632N/A ImageSDOps* isdo = LockImage(env, patternInfo->sdata);
4632N/A
4632N/A makeSureImageIsCreated(isdo);
4632N/A CGContextDrawImage(cgRef, CGRectMake(0.0f, 0.0f, patternInfo->width, patternInfo->height), isdo->imgRef);
4632N/A
4632N/A UnlockImage(env, isdo);
4632N/A}
4632N/A
4632N/A// this function MUST NOT be inlined!
4632N/Avoid texturePaintReleaseFunction(void *info)
4632N/A{
4632N/A PRINT(" texturePaintReleaseFunction")
4632N/A JNIEnv* env = [ThreadUtilities getJNIEnvUncached];
4632N/A
4632N/A StatePatternInfo* patternInfo = (StatePatternInfo*)info;
4632N/A (*env)->DeleteGlobalRef(env, patternInfo->sdata);
4632N/A
4632N/A free(info);
4632N/A}
4632N/A
4632N/Astatic inline void contextTexturePath(JNIEnv* env, QuartzSDOps* qsdo)
4632N/A{
4632N/A PRINT(" ContextTexturePath")
4632N/A CGContextRef cgRef = qsdo->cgRef;
4632N/A StatePatternInfo* patternInfo = qsdo->patternInfo;
4632N/A
4632N/A CGAffineTransform ctm = CGContextGetCTM(cgRef);
4632N/A CGAffineTransform ptm = {patternInfo->sx, 0.0f, 0.0f, -patternInfo->sy, patternInfo->tx, patternInfo->ty};
4632N/A CGAffineTransform tm = CGAffineTransformConcat(ptm, ctm);
4632N/A CGFloat xStep = (CGFloat)qsdo->patternInfo->width;
4632N/A CGFloat yStep = (CGFloat)qsdo->patternInfo->height;
4632N/A CGPatternTiling tiling = kCGPatternTilingNoDistortion;
4632N/A BOOL isColored = YES;
4632N/A static const CGPatternCallbacks callbacks = {0, &texturePaintEvaluateFunction, &texturePaintReleaseFunction};
4632N/A CGPatternRef pattern = CGPatternCreate((void*)patternInfo, CGRectMake(0.0f, 0.0f, xStep, yStep), tm, xStep, yStep, tiling, isColored, &callbacks);
4632N/A
4632N/A CGColorSpaceRef colorspace = CGColorSpaceCreatePattern(NULL);
4632N/A static const CGFloat alpha = 1.0f;
4632N/A
4632N/A CGContextSaveGState(cgRef);
4632N/A
4632N/A CGContextSetFillColorSpace(cgRef, colorspace);
4632N/A CGContextSetFillPattern(cgRef, pattern, &alpha);
4632N/A CGContextSetRGBStrokeColor(cgRef, 0.0f, 0.0f, 0.0f, 1.0f);
4632N/A CGContextSetPatternPhase(cgRef, CGSizeMake(0.0f, 0.0f));
4632N/A // rdar://problem/5214320
4632N/A // Gradient fills of Java GeneralPath don't respect the even odd winding rule (quartz pipeline).
4632N/A if (qsdo->isEvenOddFill) {
4632N/A CGContextEOFillPath(cgRef);
4632N/A } else {
4632N/A CGContextFillPath(cgRef);
4632N/A }
4632N/A
4632N/A CGContextRestoreGState(cgRef);
4632N/A
4632N/A CGColorSpaceRelease(colorspace);
4632N/A CGPatternRelease(pattern);
4632N/A
4632N/A qsdo->patternInfo = NULL;
4632N/A}
4632N/A
4632N/A#pragma mark
4632N/A#pragma mark --- Context Setup ---
4632N/A
4632N/Astatic inline void setDefaultColorSpace(CGContextRef cgRef)
4632N/A{
4632N/A static CGColorSpaceRef colorspace = NULL;
4632N/A if (colorspace == NULL)
4632N/A {
4632N/A colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
4632N/A }
4632N/A CGContextSetStrokeColorSpace(cgRef, colorspace);
4632N/A CGContextSetFillColorSpace(cgRef, colorspace);
4632N/A}
4632N/A
4632N/Avoid SetUpCGContext(JNIEnv *env, QuartzSDOps *qsdo, SDRenderType renderType)
4632N/A{
4632N/APRINT(" SetUpCGContext")
4632N/A CGContextRef cgRef = qsdo->cgRef;
4632N/A//fprintf(stderr, "%p ", cgRef);
4632N/A jint *javaGraphicsStates = qsdo->javaGraphicsStates;
4632N/A jfloat *javaFloatGraphicsStates = (jfloat*)(qsdo->javaGraphicsStates);
4632N/A
4632N/A jint changeFlags = javaGraphicsStates[sun_java2d_OSXSurfaceData_kChangeFlagIndex];
4632N/A BOOL everyThingChanged = qsdo->newContext || (changeFlags == sun_java2d_OSXSurfaceData_kEverythingChangedFlag);
4632N/A BOOL clipChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kClipChangedBit) != 0);
4632N/A BOOL transformChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kCTMChangedBit) != 0);
4632N/A BOOL paintChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kColorChangedBit) != 0);
4632N/A BOOL compositeChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kCompositeChangedBit) != 0);
4632N/A BOOL strokeChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kStrokeChangedBit) != 0);
4632N/A// BOOL fontChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kFontChangedBit) != 0);
4632N/A BOOL renderingHintsChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kHintsChangedBit) != 0);
4632N/A
4632N/A//fprintf(stderr, "SetUpCGContext cgRef=%p new=%d changeFlags=%d, everyThingChanged=%d clipChanged=%d transformChanged=%d\n",
4632N/A// cgRef, qsdo->newContext, changeFlags, everyThingChanged, clipChanged, transformChanged);
4632N/A
4632N/A if ((everyThingChanged == YES) || (clipChanged == YES) || (transformChanged == YES))
4632N/A {
4632N/A everyThingChanged = YES; // in case clipChanged or transformChanged
4632N/A
4632N/A CGContextRestoreGState(cgRef); // restore to the original state
4632N/A
4632N/A CGContextSaveGState(cgRef); // make our local copy of the state
4632N/A
4632N/A setDefaultColorSpace(cgRef);
4632N/A }
4632N/A
4632N/A if ((everyThingChanged == YES) || (clipChanged == YES))
4632N/A {
4632N/A if (javaGraphicsStates[sun_java2d_OSXSurfaceData_kClipStateIndex] == sun_java2d_OSXSurfaceData_kClipRect)
4632N/A {
4632N/A CGFloat x = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kClipXIndex];
4632N/A CGFloat y = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kClipYIndex];
4632N/A CGFloat w = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kClipWidthIndex];
4632N/A CGFloat h = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kClipHeightIndex];
4632N/A CGContextClipToRect(cgRef, CGRectMake(x, y, w, h));
4632N/A }
4632N/A else
4632N/A {
4632N/A BOOL eoFill = (javaGraphicsStates[sun_java2d_OSXSurfaceData_kClipWindingRuleIndex] == java_awt_geom_PathIterator_WIND_EVEN_ODD);
4632N/A jint numtypes = javaGraphicsStates[sun_java2d_OSXSurfaceData_kClipNumTypesIndex];
4632N/A
4632N/A jobject coordsarray = (jobject)((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kClipCoordinatesIndex));
4632N/A jobject typesarray = (jobject)((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kClipTypesIndex));
4632N/A
4632N/A jfloat* coords = (jfloat*)(*env)->GetDirectBufferAddress(env, coordsarray);
4632N/A jint* types = (jint*)(*env)->GetDirectBufferAddress(env, typesarray);
4632N/A
4632N/A DoShapeUsingCG(cgRef, types, coords, numtypes, NO, qsdo->graphicsStateInfo.offsetX, qsdo->graphicsStateInfo.offsetY);
4632N/A
4632N/A if (CGContextIsPathEmpty(cgRef) == 0)
4632N/A {
4632N/A if (eoFill)
4632N/A {
4632N/A CGContextEOClip(cgRef);
4632N/A }
4632N/A else
4632N/A {
4632N/A CGContextClip(cgRef);
4632N/A }
4632N/A }
4632N/A else
4632N/A {
4632N/A CGContextClipToRect(cgRef, CGRectZero);
4632N/A }
4632N/A }
4632N/A }
4632N/A// for debugging
4632N/A//CGContextResetClip(cgRef);
4632N/A
4632N/A if ((everyThingChanged == YES) || (transformChanged == YES))
4632N/A {
4632N/A CGFloat a = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCTMaIndex];
4632N/A CGFloat b = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCTMbIndex];
4632N/A CGFloat c = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCTMcIndex];
4632N/A CGFloat d = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCTMdIndex];
4632N/A CGFloat tx = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCTMtxIndex];
4632N/A CGFloat ty = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCTMtyIndex];
4632N/A
4632N/A CGContextConcatCTM(cgRef, CGAffineTransformMake(a, b, c, d, tx, ty));
4632N/A
4632N/A if (gAdjustForJavaDrawing == YES)
4632N/A {
4632N/A // find the offsets in the device corrdinate system
4632N/A CGAffineTransform ctm = CGContextGetCTM(cgRef);
4632N/A if ((qsdo->graphicsStateInfo.ctm.a != ctm.a) ||
4632N/A (qsdo->graphicsStateInfo.ctm.b != ctm.b) ||
4632N/A (qsdo->graphicsStateInfo.ctm.c != ctm.c) ||
4632N/A (qsdo->graphicsStateInfo.ctm.d != ctm.d))
4632N/A {
4632N/A qsdo->graphicsStateInfo.ctm = ctm;
4632N/A // In CG affine xforms y' = bx+dy+ty
4632N/A // We need to flip both y coefficeints to flip the offset point into the java coordinate system.
4632N/A ctm.b = -ctm.b; ctm.d = -ctm.d; ctm.tx = 0.0f; ctm.ty = 0.0f;
4632N/A CGPoint offsets = {kOffset, kOffset};
5321N/A CGAffineTransform inverse = CGAffineTransformInvert(ctm);
5321N/A offsets = CGPointApplyAffineTransform(offsets, inverse);
4632N/A qsdo->graphicsStateInfo.offsetX = offsets.x;
4632N/A qsdo->graphicsStateInfo.offsetY = offsets.y;
4632N/A }
4632N/A }
4632N/A else
4632N/A {
4632N/A qsdo->graphicsStateInfo.offsetX = 0.0f;
4632N/A qsdo->graphicsStateInfo.offsetY = 0.0f;
4632N/A }
4632N/A }
4632N/A
4632N/A// for debugging
4632N/A//CGContextResetCTM(cgRef);
4632N/A
4632N/A if ((everyThingChanged == YES) || (compositeChanged == YES))
4632N/A {
4632N/A jint alphaCompositeRule = javaGraphicsStates[sun_java2d_OSXSurfaceData_kCompositeRuleIndex];
4632N/A CGFloat alphaCompositeValue = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCompositeValueIndex];
4632N/A
4632N/A NSCompositingOperation op;
4632N/A switch (alphaCompositeRule)
4632N/A {
4632N/A case java_awt_AlphaComposite_CLEAR:
4632N/A op = NSCompositeClear;
4632N/A break;
4632N/A case java_awt_AlphaComposite_SRC:
4632N/A op = NSCompositeCopy;
4632N/A break;
4632N/A case java_awt_AlphaComposite_SRC_OVER:
4632N/A op = NSCompositeSourceOver;
4632N/A break;
4632N/A case java_awt_AlphaComposite_DST_OVER:
4632N/A op = NSCompositeDestinationOver;
4632N/A break;
4632N/A case java_awt_AlphaComposite_SRC_IN:
4632N/A op = NSCompositeSourceIn;
4632N/A break;
4632N/A case java_awt_AlphaComposite_DST_IN:
4632N/A op = NSCompositeDestinationIn;
4632N/A break;
4632N/A case java_awt_AlphaComposite_SRC_OUT:
4632N/A op = NSCompositeSourceOut;
4632N/A break;
4632N/A case java_awt_AlphaComposite_DST_OUT:
4632N/A op = NSCompositeDestinationOut;
4632N/A break;
4632N/A case java_awt_AlphaComposite_DST:
4632N/A // Alpha must be set to 0 because we're using the kCGCompositeSover rule
4632N/A op = NSCompositeSourceOver;
4632N/A alphaCompositeValue = 0.0f;
4632N/A break;
4632N/A case java_awt_AlphaComposite_SRC_ATOP:
4632N/A op = NSCompositeSourceAtop;
4632N/A break;
4632N/A case java_awt_AlphaComposite_DST_ATOP:
4632N/A op = NSCompositeDestinationAtop;
4632N/A break;
4632N/A case java_awt_AlphaComposite_XOR:
4632N/A op = NSCompositeXOR;
4632N/A break;
4632N/A default:
4632N/A op = NSCompositeSourceOver;
4632N/A alphaCompositeValue = 1.0f;
4632N/A break;
4632N/A }
4632N/A
4632N/A NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithGraphicsPort:cgRef flipped:NO];
4632N/A //CGContextSetCompositeOperation(cgRef, op);
4632N/A [context setCompositingOperation:op];
4632N/A CGContextSetAlpha(cgRef, alphaCompositeValue);
4632N/A }
4632N/A
4632N/A if ((everyThingChanged == YES) || (renderingHintsChanged == YES))
4632N/A {
4632N/A jint antialiasHint = javaGraphicsStates[sun_java2d_OSXSurfaceData_kHintsAntialiasIndex];
4632N/A// jint textAntialiasHint = javaGraphicsStates[sun_java2d_OSXSurfaceData_kHintsTextAntialiasIndex];
4632N/A jint renderingHint = javaGraphicsStates[sun_java2d_OSXSurfaceData_kHintsRenderingIndex];
4632N/A jint interpolationHint = javaGraphicsStates[sun_java2d_OSXSurfaceData_kHintsInterpolationIndex];
4632N/A// jint textFractionalMetricsHint = javaGraphicsStates[sun_java2d_OSXSurfaceData_kHintsFractionalMetricsIndex];
4632N/A
4632N/A // 10-10-02 VL: since CoreGraphics supports only an interpolation quality attribute we have to map
4632N/A // both interpolationHint and renderingHint to an attribute value that best represents their combination.
4632N/A // (See Radar 3071704.) We'll go for the best quality. CG maps interpolation quality values as follows:
4632N/A // kCGInterpolationNone - nearest_neighbor
4632N/A // kCGInterpolationLow - bilinear
4632N/A // kCGInterpolationHigh - Lanczos (better than bicubic)
4632N/A CGInterpolationQuality interpolationQuality = kCGInterpolationDefault;
4632N/A // First check if the interpolation hint is suggesting to turn off interpolation:
4632N/A if (interpolationHint == sun_awt_SunHints_INTVAL_INTERPOLATION_NEAREST_NEIGHBOR)
4632N/A {
4632N/A interpolationQuality = kCGInterpolationNone;
4632N/A }
4632N/A else if ((interpolationHint >= sun_awt_SunHints_INTVAL_INTERPOLATION_BICUBIC) || (renderingHint >= sun_awt_SunHints_INTVAL_RENDER_QUALITY))
4632N/A {
4632N/A // Use >= just in case Sun adds some hint values in the future - this check wouldn't fall apart then:
4632N/A interpolationQuality = kCGInterpolationHigh;
4632N/A }
4632N/A else if (interpolationHint == sun_awt_SunHints_INTVAL_INTERPOLATION_BILINEAR)
4632N/A {
4632N/A interpolationQuality = kCGInterpolationLow;
4632N/A }
4632N/A else if (renderingHint == sun_awt_SunHints_INTVAL_RENDER_SPEED)
4632N/A {
4632N/A interpolationQuality = kCGInterpolationNone;
4632N/A }
4632N/A // else interpolationHint == -1 || renderingHint == sun_awt_SunHints_INTVAL_CSURFACE_DEFAULT --> kCGInterpolationDefault
4632N/A CGContextSetInterpolationQuality(cgRef, interpolationQuality);
4632N/A qsdo->graphicsStateInfo.interpolation = interpolationQuality;
4632N/A
4632N/A // antialiasing
4632N/A BOOL antialiased = (antialiasHint == sun_awt_SunHints_INTVAL_ANTIALIAS_ON);
4632N/A CGContextSetShouldAntialias(cgRef, antialiased);
4632N/A qsdo->graphicsStateInfo.antialiased = antialiased;
4632N/A }
4632N/A
4632N/A if ((everyThingChanged == YES) || (strokeChanged == YES))
4632N/A {
4632N/A qsdo->graphicsStateInfo.simpleStroke = YES;
4632N/A
4632N/A CGFloat linewidth = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kStrokeWidthIndex];
4632N/A jint linejoin = javaGraphicsStates[sun_java2d_OSXSurfaceData_kStrokeJoinIndex];
4632N/A jint linecap = javaGraphicsStates[sun_java2d_OSXSurfaceData_kStrokeCapIndex];
4632N/A CGFloat miterlimit = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kStrokeLimitIndex];
4632N/A jobject dasharray = ((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kStrokeDashArrayIndex));
4632N/A CGFloat dashphase = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kStrokeDashPhaseIndex];
4632N/A
4632N/A if (linewidth == 0.0f)
4632N/A {
4632N/A linewidth = (CGFloat)-109.05473e+14; // Don't ask !
4632N/A }
4632N/A CGContextSetLineWidth(cgRef, linewidth);
4632N/A
4632N/A CGLineCap cap;
4632N/A switch (linecap)
4632N/A {
4632N/A case java_awt_BasicStroke_CAP_BUTT:
4632N/A qsdo->graphicsStateInfo.simpleStroke = NO;
4632N/A cap = kCGLineCapButt;
4632N/A break;
4632N/A case java_awt_BasicStroke_CAP_ROUND:
4632N/A qsdo->graphicsStateInfo.simpleStroke = NO;
4632N/A cap = kCGLineCapRound;
4632N/A break;
4632N/A case java_awt_BasicStroke_CAP_SQUARE:
4632N/A default:
4632N/A cap = kCGLineCapSquare;
4632N/A break;
4632N/A }
4632N/A CGContextSetLineCap(cgRef, cap);
4632N/A
4632N/A CGLineJoin join;
4632N/A switch (linejoin)
4632N/A {
4632N/A case java_awt_BasicStroke_JOIN_ROUND:
4632N/A qsdo->graphicsStateInfo.simpleStroke = NO;
4632N/A join = kCGLineJoinRound;
4632N/A break;
4632N/A case java_awt_BasicStroke_JOIN_BEVEL:
4632N/A qsdo->graphicsStateInfo.simpleStroke = NO;
4632N/A join = kCGLineJoinBevel;
4632N/A break;
4632N/A case java_awt_BasicStroke_JOIN_MITER:
4632N/A default:
4632N/A join = kCGLineJoinMiter;
4632N/A break;
4632N/A }
4632N/A CGContextSetLineJoin(cgRef, join);
4632N/A CGContextSetMiterLimit(cgRef, miterlimit);
4632N/A
4632N/A if (dasharray != NULL)
4632N/A {
4632N/A qsdo->graphicsStateInfo.simpleStroke = NO;
4632N/A jint length = (*env)->GetArrayLength(env, dasharray);
4632N/A jfloat* jdashes = (jfloat*)(*env)->GetPrimitiveArrayCritical(env, dasharray, NULL);
4632N/A CGFloat* dashes = (CGFloat*)malloc(sizeof(CGFloat)*length);
4632N/A if (dashes != NULL)
4632N/A {
4632N/A jint i;
4632N/A for (i=0; i<length; i++)
4632N/A {
4632N/A dashes[i] = (CGFloat)jdashes[i];
4632N/A }
4632N/A }
4632N/A else
4632N/A {
4632N/A dashphase = 0;
4632N/A length = 0;
4632N/A }
4632N/A CGContextSetLineDash(cgRef, dashphase, dashes, length);
4632N/A if (dashes != NULL)
4632N/A {
4632N/A free(dashes);
4632N/A }
4632N/A (*env)->ReleasePrimitiveArrayCritical(env, dasharray, jdashes, 0);
4632N/A }
4632N/A else
4632N/A {
4632N/A CGContextSetLineDash(cgRef, 0, NULL, 0);
4632N/A }
4632N/A }
4632N/A
4632N/A BOOL cocoaPaint = (javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorStateIndex] == sun_java2d_OSXSurfaceData_kColorSystem);
4632N/A BOOL complexPaint = (javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorStateIndex] == sun_java2d_OSXSurfaceData_kColorGradient) ||
4632N/A (javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorStateIndex] == sun_java2d_OSXSurfaceData_kColorTexture);
4632N/A if ((everyThingChanged == YES) || (paintChanged == YES) || (cocoaPaint == YES) || (complexPaint == YES))
4632N/A {
4632N/A // rdar://problem/5214320
4632N/A // Gradient fills of Java GeneralPath don't respect the even odd winding rule (quartz pipeline).
4632N/A // Notice the side effect of the stmt after this if-block.
4632N/A if (renderType == SD_EOFill) {
4632N/A qsdo->isEvenOddFill = YES;
4632N/A }
4632N/A
4632N/A renderType = SetUpPaint(env, qsdo, renderType);
4632N/A }
4632N/A
4632N/A qsdo->renderType = renderType;
4632N/A}
4632N/A
4632N/ASDRenderType SetUpPaint(JNIEnv *env, QuartzSDOps *qsdo, SDRenderType renderType)
4632N/A{
4632N/A CGContextRef cgRef = qsdo->cgRef;
4632N/A
4632N/A jint *javaGraphicsStates = qsdo->javaGraphicsStates;
4632N/A jfloat *javaFloatGraphicsStates = (jfloat*)(qsdo->javaGraphicsStates);
4632N/A
4632N/A static const CGFloat kColorConversionMultiplier = 1.0f/255.0f;
4632N/A jint colorState = javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorStateIndex];
4632N/A
4632N/A switch (colorState)
4632N/A {
4632N/A case sun_java2d_OSXSurfaceData_kColorSimple:
4632N/A {
4632N/A if (qsdo->graphicsStateInfo.simpleColor == NO)
4632N/A {
4632N/A setDefaultColorSpace(cgRef);
4632N/A }
4632N/A qsdo->graphicsStateInfo.simpleColor = YES;
4632N/A
4632N/A // sets the color on the CGContextRef (CGContextSetStrokeColorWithColor/CGContextSetFillColorWithColor)
4632N/A setCachedColor(qsdo, javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorRGBValueIndex]);
4632N/A
4632N/A break;
4632N/A }
4632N/A case sun_java2d_OSXSurfaceData_kColorSystem:
4632N/A {
4632N/A qsdo->graphicsStateInfo.simpleStroke = NO;
4632N/A // All our custom Colors are NSPatternColorSpace so we are complex colors!
4632N/A qsdo->graphicsStateInfo.simpleColor = NO;
4632N/A
4632N/A NSColor *color = nil;
4632N/A /* TODO:BG
4632N/A {
4632N/A color = getColor(javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorIndexValueIndex]);
4632N/A }
4632N/A */
4632N/A [color set];
4632N/A break;
4632N/A }
4632N/A case sun_java2d_OSXSurfaceData_kColorGradient:
4632N/A {
4632N/A qsdo->shadingInfo = (StateShadingInfo*)malloc(sizeof(StateShadingInfo));
4632N/A if (qsdo->shadingInfo == NULL)
4632N/A {
4632N/A [JNFException raise:env as:kOutOfMemoryError reason:"Failed to malloc memory for gradient paint"];
4632N/A }
4632N/A
4632N/A qsdo->graphicsStateInfo.simpleStroke = NO;
4632N/A qsdo->graphicsStateInfo.simpleColor = NO;
4632N/A
4632N/A renderType = SD_Shade;
4632N/A
4632N/A qsdo->shadingInfo->start.x = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColorx1Index];
4632N/A qsdo->shadingInfo->start.y = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColory1Index];
4632N/A qsdo->shadingInfo->end.x = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColorx2Index];
4632N/A qsdo->shadingInfo->end.y = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColory2Index];
4632N/A jint c1 = javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorRGBValue1Index];
4632N/A qsdo->shadingInfo->colors[0] = ((c1>>16)&0xff)*kColorConversionMultiplier;
4632N/A qsdo->shadingInfo->colors[1] = ((c1>>8)&0xff)*kColorConversionMultiplier;
4632N/A qsdo->shadingInfo->colors[2] = ((c1>>0)&0xff)*kColorConversionMultiplier;
4632N/A qsdo->shadingInfo->colors[3] = ((c1>>24)&0xff)*kColorConversionMultiplier;
4632N/A jint c2 = javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorRGBValue2Index];
4632N/A qsdo->shadingInfo->colors[4] = ((c2>>16)&0xff)*kColorConversionMultiplier;
4632N/A qsdo->shadingInfo->colors[5] = ((c2>>8)&0xff)*kColorConversionMultiplier;
4632N/A qsdo->shadingInfo->colors[6] = ((c2>>0)&0xff)*kColorConversionMultiplier;
4632N/A qsdo->shadingInfo->colors[7] = ((c2>>24)&0xff)*kColorConversionMultiplier;
4632N/A qsdo->shadingInfo->cyclic = (javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorIsCyclicIndex] == sun_java2d_OSXSurfaceData_kColorCyclic);
4632N/A
4632N/A break;
4632N/A }
4632N/A case sun_java2d_OSXSurfaceData_kColorTexture:
4632N/A {
4632N/A qsdo->patternInfo = (StatePatternInfo*)malloc(sizeof(StatePatternInfo));
4632N/A if (qsdo->patternInfo == NULL)
4632N/A {
4632N/A [JNFException raise:env as:kOutOfMemoryError reason:"Failed to malloc memory for texture paint"];
4632N/A }
4632N/A
4632N/A qsdo->graphicsStateInfo.simpleStroke = NO;
4632N/A qsdo->graphicsStateInfo.simpleColor = NO;
4632N/A
4632N/A renderType = SD_Pattern;
4632N/A
4632N/A qsdo->patternInfo->tx = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColortxIndex];
4632N/A qsdo->patternInfo->ty = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColortyIndex];
4632N/A qsdo->patternInfo->sx = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColorsxIndex];
4632N/A if (qsdo->patternInfo->sx == 0.0f)
4632N/A {
4632N/A return SD_Fill; // 0 is an invalid value, fill argb rect
4632N/A }
4632N/A qsdo->patternInfo->sy = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColorsyIndex];
4632N/A if (qsdo->patternInfo->sy == 0.0f)
4632N/A {
4632N/A return SD_Fill; // 0 is an invalid value, fill argb rect
4632N/A }
4632N/A qsdo->patternInfo->width = javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorWidthIndex];
4632N/A qsdo->patternInfo->height = javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorHeightIndex];
4632N/A
4632N/A jobject sData = ((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kTextureImageIndex)); //deleted next time through SetUpPaint and not before ( radr://3913190 )
4632N/A if (sData != NULL)
4632N/A {
4632N/A qsdo->patternInfo->sdata = (*env)->NewGlobalRef(env, sData);
4632N/A if (qsdo->patternInfo->sdata == NULL)
4632N/A {
4632N/A renderType = SD_Fill;
4632N/A }
4632N/A }
4632N/A else
4632N/A {
4632N/A renderType = SD_Fill;
4632N/A }
4632N/A
4632N/A break;
4632N/A }
4632N/A }
4632N/A
4632N/A return renderType;
4632N/A}
4632N/A
4632N/A#pragma mark
4632N/A#pragma mark --- Shape Drawing Code ---
4632N/A
4632N/ASDRenderType DoShapeUsingCG(CGContextRef cgRef, jint *types, jfloat *coords, jint numtypes, BOOL fill, CGFloat offsetX, CGFloat offsetY)
4632N/A{
4632N/A//fprintf(stderr, "DoShapeUsingCG fill=%d\n", (jint)fill);
4632N/A SDRenderType renderType = SD_Nothing;
4632N/A
4632N/A if (gAdjustForJavaDrawing != YES)
4632N/A {
4632N/A offsetX = 0.0f;
4632N/A offsetY = 0.0f;
4632N/A }
4632N/A
4632N/A if (fill == YES)
4632N/A {
4632N/A renderType = SD_Fill;
4632N/A }
4632N/A else
4632N/A {
4632N/A renderType = SD_Stroke;
4632N/A }
4632N/A
4632N/A if (numtypes > 0)
4632N/A {
4632N/A BOOL needNewSubpath = NO;
4632N/A
4632N/A CGContextBeginPath(cgRef); // create new path
4632N/A//fprintf(stderr, " CGContextBeginPath\n");
4632N/A
4632N/A jint index = 0;
4632N/A CGFloat mx = 0.0f, my = 0.0f, x1 = 0.0f, y1 = 0.0f, cpx1 = 0.0f, cpy1 = 0.0f, cpx2 = 0.0f, cpy2 = 0.0f;
4632N/A jint i;
4632N/A
4632N/A mx = (CGFloat)coords[index++] + offsetX;
4632N/A my = (CGFloat)coords[index++] + offsetY;
4632N/A CGContextMoveToPoint(cgRef, mx, my);
4632N/A
4632N/A for (i=1; i<numtypes; i++)
4632N/A {
4632N/A jint pathType = types[i];
4632N/A
4632N/A if (needNewSubpath == YES)
4632N/A {
4632N/A needNewSubpath = NO;
4632N/A switch (pathType)
4632N/A {
4632N/A case java_awt_geom_PathIterator_SEG_LINETO:
4632N/A case java_awt_geom_PathIterator_SEG_QUADTO:
4632N/A case java_awt_geom_PathIterator_SEG_CUBICTO:
4632N/A//fprintf(stderr, " forced CGContextMoveToPoint (%f, %f)\n", mx, my);
4632N/A CGContextMoveToPoint(cgRef, mx, my); // force new subpath
4632N/A break;
4632N/A }
4632N/A }
4632N/A
4632N/A switch (pathType)
4632N/A {
4632N/A case java_awt_geom_PathIterator_SEG_MOVETO:
4632N/A mx = x1 = (CGFloat)coords[index++] + offsetX;
4632N/A my = y1 = (CGFloat)coords[index++] + offsetY;
4632N/A CGContextMoveToPoint(cgRef, x1, y1); // start new subpath
4632N/A//fprintf(stderr, " SEG_MOVETO CGContextMoveToPoint (%f, %f)\n", x1, y1);
4632N/A break;
4632N/A case java_awt_geom_PathIterator_SEG_LINETO:
4632N/A x1 = (CGFloat)coords[index++] + offsetX;
4632N/A y1 = (CGFloat)coords[index++] + offsetY;
4632N/A CGContextAddLineToPoint(cgRef, x1, y1);
4632N/A//fprintf(stderr, " SEG_LINETO CGContextAddLineToPoint (%f, %f)\n", x1, y1);
4632N/A break;
4632N/A case java_awt_geom_PathIterator_SEG_QUADTO:
4632N/A cpx1 = (CGFloat)coords[index++] + offsetX;
4632N/A cpy1 = (CGFloat)coords[index++] + offsetY;
4632N/A x1 = (CGFloat)coords[index++] + offsetX;
4632N/A y1 = (CGFloat)coords[index++]+ offsetY;
4632N/A CGContextAddQuadCurveToPoint(cgRef, cpx1, cpy1, x1, y1);
4632N/A//fprintf(stderr, " SEG_QUADTO CGContextAddQuadCurveToPoint (%f, %f), (%f, %f)\n", cpx1, cpy1, x1, y1);
4632N/A break;
4632N/A case java_awt_geom_PathIterator_SEG_CUBICTO:
4632N/A cpx1 = (CGFloat)coords[index++] + offsetX;
4632N/A cpy1 = (CGFloat)coords[index++] + offsetY;
4632N/A cpx2 = (CGFloat)coords[index++] + offsetX;
4632N/A cpy2 = (CGFloat)coords[index++] + offsetY;
4632N/A x1 = (CGFloat)coords[index++] + offsetX;
4632N/A y1 = (CGFloat)coords[index++] + offsetY;
4632N/A CGContextAddCurveToPoint(cgRef, cpx1, cpy1, cpx2, cpy2, x1, y1);
4632N/A//fprintf(stderr, " SEG_CUBICTO CGContextAddCurveToPoint (%f, %f), (%f, %f), (%f, %f)\n", cpx1, cpy1, cpx2, cpy2, x1, y1);
4632N/A break;
4632N/A case java_awt_geom_PathIterator_SEG_CLOSE:
4632N/A CGContextClosePath(cgRef); // close subpath
4632N/A needNewSubpath = YES;
4632N/A//fprintf(stderr, " SEG_CLOSE CGContextClosePath\n");
4632N/A break;
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A return renderType;
4632N/A}
4632N/A
4632N/Avoid CompleteCGContext(JNIEnv *env, QuartzSDOps *qsdo)
4632N/A{
4632N/APRINT(" CompleteCGContext")
4632N/A switch (qsdo->renderType)
4632N/A {
4632N/A case SD_Nothing:
4632N/A break;
4632N/A
4632N/A case SD_Stroke:
4632N/A if (CGContextIsPathEmpty(qsdo->cgRef) == 0)
4632N/A {
4632N/A CGContextStrokePath(qsdo->cgRef);
4632N/A }
4632N/A break;
4632N/A
4632N/A case SD_Fill:
4632N/A if (CGContextIsPathEmpty(qsdo->cgRef) == 0)
4632N/A {
4632N/A CGContextFillPath(qsdo->cgRef);
4632N/A }
4632N/A break;
4632N/A
4632N/A case SD_Shade:
4632N/A if (CGContextIsPathEmpty(qsdo->cgRef) == 0)
4632N/A {
4632N/A contextGradientPath(qsdo);
4632N/A }
4632N/A break;
4632N/A
4632N/A case SD_Pattern:
4632N/A if (CGContextIsPathEmpty(qsdo->cgRef) == 0)
4632N/A {
4632N/A //TODO:BG
4632N/A //contextTexturePath(env, qsdo);
4632N/A }
4632N/A break;
4632N/A
4632N/A case SD_EOFill:
4632N/A if (CGContextIsPathEmpty(qsdo->cgRef) == 0)
4632N/A {
4632N/A CGContextEOFillPath(qsdo->cgRef);
4632N/A }
4632N/A break;
4632N/A
4632N/A case SD_Image:
4632N/A break;
4632N/A
4632N/A case SD_Text:
4632N/A break;
4632N/A
4632N/A case SD_CopyArea:
4632N/A break;
4632N/A
4632N/A case SD_Queue:
4632N/A break;
4632N/A
4632N/A case SD_External:
4632N/A break;
4632N/A }
4632N/A
4632N/A if (qsdo->shadingInfo != NULL) {
4632N/A gradientPaintReleaseFunction(qsdo->shadingInfo);
4632N/A qsdo->shadingInfo = NULL;
4632N/A }
4632N/A}