JDK-7187834 : [macosx] Usage of private API in macosx 2d implementation causes Apple Store rejection
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 7
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: os_x
  • CPU: x86
  • Submitted: 2012-07-30
  • Updated: 2013-09-06
  • Resolved: 2012-09-11
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7 JDK 8
7u10Fixed 8 b56Fixed
Description
FULL PRODUCT VERSION :
openjdk version "1.7.0"
OpenJDK Runtime Environment (build 1.7.0-2012_06_18_15_16-b00)
OpenJDK 64-Bit Server VM (build 23.2-b05, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
OSX 10.7

A DESCRIPTION OF THE PROBLEM :
Our application has been rejected on the Apple Store because some native awt files in jdk/src/macosx/native/sun/awt/  use private calls like CGPointApplyInverseAffineTransform from the framework '/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices'.

Other private calls I found are CGContextSetCTM and the usage of a constant called CTIntegerMetrics in CoreTextSupport.m and CTextPipe.m.




REPRODUCIBILITY :
This bug can be reproduced always.

CUSTOMER SUBMITTED WORKAROUND :
The following patch against OpenJDK 7u rev 243717d7fe95 attempts to replace the private calls  CGPointApplyInverseAffineTransform and CGContextSetCTM with public ones.

# HG changeset patch
# User Marco Dinacci <###@###.###>
# Date 1343648968 -3600
# Node ID d873b027d78564ad237f98a0cb5a327c5c740354
# Parent  2ebb564fd0a1267491b6a13bf7ff35b9894ebdba
Replaced CGContextSetCTM and CGPointApplyInverseAffineTransform with public API calls.

diff -r 2ebb564fd0a1 -r d873b027d785 src/macosx/native/sun/awt/ImageSurfaceData.m
--- a/src/macosx/native/sun/awt/ImageSurfaceData.m	Thu Jun 28 10:13:16 2012 +0100
+++ b/src/macosx/native/sun/awt/ImageSurfaceData.m	Mon Jul 30 12:49:28 2012 +0100
@@ -48,20 +48,16 @@
 #endif
 
 // same value as defined in Sun's own code
 #define XOR_ALPHA_CUTOFF 128
 
 // for vImage framework headers
 #include <Accelerate/Accelerate.h>
 
-
-// private Quartz routines needed here
-CG_EXTERN void CGContextSetCTM(CGContextRef ref, CGAffineTransform tx);
-
 static ContextInfo sDefaultContextInfo[sun_java2d_OSXOffScreenSurfaceData_TYPE_3BYTE_RGB+1] =
 {
     {YES,    YES,    8,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_CUSTOM            // special case
     {YES,    YES,    8,        4,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,        NULL},    // TYPE_INT_RGB
     {YES,    YES,    8,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_INT_ARGB
     {YES,    YES,    8,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_INT_ARGB_PRE
     {YES,    YES,    8,        4,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,        NULL},    // TYPE_INT_BGR
     {YES,    NO,        8,        4,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,        NULL},    // TYPE_3BYTE_BGR        // use the default ARGB_PRE context synce we have to sync by hand anyway
@@ -937,17 +933,16 @@ PRINT("createContext")
     if (qsdo->cgRef == NULL)
     {
         fprintf(stderr, "ERROR: (qsdo->cgRef == NULL) in createContext!\n");
     }
 
     // intitalize the context to match the Java coordinate system
 
     // BG, since the context is created above, we can just concat
-    //CGContextSetCTM(qsdo->cgRef, CGAffineTransformMake(1, 0, 0, -1, 0, isdo->height));
     CGContextConcatCTM(qsdo->cgRef, CGAffineTransformMake(1, 0, 0, -1, 0, isdo->height));
 
     CGContextSaveGState(qsdo->cgRef); // this will make sure we don't go pass device context settings
     CGContextSaveGState(qsdo->cgRef); // this will put user settings on top, used by LazyStateManagement code
     qsdo->newContext = YES;
 }
 
 IMAGE_SURFACE_INLINE void holdJavaPixels(JNIEnv* env, ImageSDOps* isdo)
@@ -1109,17 +1104,17 @@ PRINT("syncFromJavaPixels")
                 if (qsdo->cgRef == NULL)
                 {
                     createContext(env, isdo);
                 }
 
                 if (qsdo->cgRef != NULL)
                 {
                     CGContextSaveGState(qsdo->cgRef);
-                    CGContextSetCTM(qsdo->cgRef, CGAffineTransformMake(1, 0, 0, 1, 0, 0));
+                    CGContextConcatCTM(qsdo->cgRef, CGAffineTransformMake(1, 0, 0, 1, 0, 0));
                     CGContextSetBlendMode(qsdo->cgRef, kCGBlendModeCopy);
                     CGContextSetAlpha(qsdo->cgRef, 1.0f);
                     CGContextDrawImage(qsdo->cgRef, CGRectMake(0, 0, width, height), javaImg);
                     CGContextFlush(qsdo->cgRef);
                     CGContextRestoreGState(qsdo->cgRef);
                     CGImageRelease(javaImg);
                 }
                 else
diff -r 2ebb564fd0a1 -r d873b027d785 src/macosx/native/sun/awt/QuartzRenderer.m
--- a/src/macosx/native/sun/awt/QuartzRenderer.m	Thu Jun 28 10:13:16 2012 +0100
+++ b/src/macosx/native/sun/awt/QuartzRenderer.m	Mon Jul 30 12:49:28 2012 +0100
@@ -45,19 +45,16 @@
 // Copied the following from Math.java
 #define PI 3.14159265358979323846f
 
 #define BATCHED_POINTS_SIZE 1024
 
 // same value as defined in Sun's own code
 #define XOR_ALPHA_CUTOFF 128
 
-// private Quartz routines needed here
-CG_EXTERN void CGContextSetCTM(CGContextRef ref, CGAffineTransform tx);
-
 
 static CGFloat gRoundRectCtrlpts[10][12] =
 {
     {0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
     {0.0f, 0.0f, 1.0f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
     {0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 1.0f, 0.0f},
     {1.0f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
     {1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, -0.5f},
@@ -532,31 +529,33 @@ QUARTZ_RENDERER_INLINE void doImageCG(JN
     {
         a = -1.0f;
         tx += dw;
     }
 
     makeSureImageIsCreated(isdo);
 
     CGAffineTransform ctm = CGContextGetCTM(cgRef);
-    CGContextConcatCTM(cgRef, CGAffineTransformMake(a, b, c, d, tx, ty));
+    CGAffineTransform newTm = CGAffineTransformMake(a, b, c, d, tx, ty);
+    CGContextConcatCTM(cgRef, newTm);
     jint alphaInfo = isdo->contextInfo.alphaInfo & kCGBitmapAlphaInfoMask;
 
     if ((sx == 0) && (sy == 0) && (sw == w) && (sh == h)) // no subimages allowed here
     {
         CGContextDrawImage(cgRef, CGRectMake(0, 0, dw, dh), isdo->imgRef);
     }
     else // handle subimages
     {
         CGImageRef subImg = CGImageCreateWithImageInRect(isdo->imgRef, CGRectMake(sx, sy, sw, sh));
         CGContextDrawImage(cgRef, CGRectMake(0.0f, 0.0f, dw, dh), subImg);
         CGImageRelease(subImg);
     }
 
-    CGContextSetCTM(cgRef, ctm);
+    CGAffineTransform inverse = CGAffineTransformInvert(newRef);
+    CGContextConcatCTM(cgRef, inverse);
     UnlockImage(env, isdo);
 }
 
 QUARTZ_RENDERER_INLINE void doImage(JNIEnv *env, QuartzSDOps *qsdo, jobject imageSurfaceData,
                                 jboolean fliph, jboolean flipv, jint w, jint h, jint sx, jint sy, jint sw, jint sh, jint dx, jint dy, jint dw, jint dh)
 {
     if ((w > 0) && (h > 0) && (sw > 0) && (sh > 0) && (dw > 0) && (dh > 0))
     {
diff -r 2ebb564fd0a1 -r d873b027d785 src/macosx/native/sun/awt/QuartzSurfaceData.m
--- a/src/macosx/native/sun/awt/QuartzSurfaceData.m	Thu Jun 28 10:13:16 2012 +0100
+++ b/src/macosx/native/sun/awt/QuartzSurfaceData.m	Mon Jul 30 12:49:28 2012 +0100
@@ -35,29 +35,23 @@
 #import "sun_lwawt_macosx_CPrinterSurfaceData.h"
 #import "ImageSurfaceData.h"
 
 #import <JavaNativeFoundation/JavaNativeFoundation.h>
 
 #import <AppKit/AppKit.h>
 #import "ThreadUtilities.h"
 
-// private Quartz routines needed here
-CG_EXTERN void CGContextSetCTM(CGContextRef ref, CGAffineTransform tx);
-
 //#define DEBUG
 #if defined DEBUG
     #define PRINT(msg) {fprintf(stderr, "%s\n", msg);}
 #else
     #define PRINT(msg) {}
 #endif
 
-// from CGAffineTransformPrivate.h
-extern CGPoint CGPointApplyInverseAffineTransform(CGPoint point, CGAffineTransform t);
-
 #define kOffset (0.5f)
 
 BOOL gAdjustForJavaDrawing;
 
 #pragma mark
 #pragma mark --- Color Cache ---
 
 // Creating and deleting CGColorRefs can be expensive, therefore we have a color cache.
@@ -603,17 +597,21 @@ PRINT(" SetUpCGContext")
                         (qsdo->graphicsStateInfo.ctm.c != ctm.c) ||
                             (qsdo->graphicsStateInfo.ctm.d != ctm.d))
             {
                 qsdo->graphicsStateInfo.ctm = ctm;
                 // In CG affine xforms y' = bx+dy+ty
                 // We need to flip both y coefficeints to flip the offset point into the java coordinate system.
                 ctm.b = -ctm.b; ctm.d = -ctm.d; ctm.tx = 0.0f; ctm.ty = 0.0f;
                 CGPoint offsets = {kOffset, kOffset};
-                offsets = CGPointApplyInverseAffineTransform(offsets, ctm);
+
+                
+                CGAffineTransform inverse = CGAffineTransformInvert(ctm);
+                offsets = CGPointApplyAffineTransform(offsets, inverse);
+                //offsets = CGPointApplyInverseAffineTransform(offsets, ctm);
                 qsdo->graphicsStateInfo.offsetX = offsets.x;
                 qsdo->graphicsStateInfo.offsetY = offsets.y;
             }
         }
         else
         {
             qsdo->graphicsStateInfo.offsetX = 0.0f;
             qsdo->graphicsStateInfo.offsetY = 0.0f;
exporting patch:
<fdopen>

Comments
SQE has no suitable instrument to verify success of App Store admission and/or even ensure proper usage of Apple private API. Closing unverified.
13-06-2013

EVALUATION fixed here : http://hg.openjdk.java.net/jdk8/2d/jdk/rev/b4f7ef73dfe8
05-09-2012