Compare commits
21 Commits
client-are
...
moklev-ful
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0831a9d90 | ||
|
|
5f9b3a6dda | ||
|
|
cab6dd5087 | ||
|
|
e4b063cb1f | ||
|
|
bbd90315c9 | ||
|
|
c93b853a2b | ||
|
|
d65279cdc1 | ||
|
|
6c71f3a853 | ||
|
|
95a5c1661b | ||
|
|
153020320d | ||
|
|
23e2ac4c4e | ||
|
|
29ec6c2bce | ||
|
|
7997c7a5ee | ||
|
|
14659f0d30 | ||
|
|
a868128d2e | ||
|
|
1e1b932a4c | ||
|
|
bac12d4598 | ||
|
|
2bbfe3bf2f | ||
|
|
38abcae3e9 | ||
|
|
1746b04686 | ||
|
|
00d32e58dc |
2
.gitignore
vendored
@@ -3,3 +3,5 @@ JTreport
|
||||
*.class
|
||||
.idea/workspace.xml
|
||||
build/
|
||||
# Project exclude paths
|
||||
/jb/project/java-gradle/.gradle/
|
||||
@@ -10,11 +10,11 @@ def test_jvm = {
|
||||
file(jbsdkhome + (OperatingSystem.current().isWindows()?"/bin/java.exe" : "/bin/java")).absolutePath
|
||||
} else {
|
||||
if (OperatingSystem.current().isMacOsX()) {
|
||||
file('../../../build/macosx-x86_64-normal-server-release/images/jdk-bundle/jdk-11.jdk/Contents/Home/bin/java').absolutePath
|
||||
file('../../../build/macosx-x86_64-normal-server-release/images/jdk-bundle/jdk-11.0.3.jdk/Contents/Home/bin/java').absolutePath
|
||||
} else if (OperatingSystem.current().isLinux()) {
|
||||
file('../../../build/linux-x86_64-normal-server-release/images/jdk/bin/java').absolutePath
|
||||
} else {
|
||||
file('../../../build/windows-x86_64-normal-server-release/images/j2sdk-image/bin/java.exe').absolutePath
|
||||
file('../../../build/windows-x86_64-normal-server-release/images/jdk/bin/java.exe').absolutePath
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,15 +75,21 @@ test.dependsOn tasks.compileTestJava
|
||||
|
||||
test {
|
||||
systemProperty "jb.java2d.metal", "true"
|
||||
systemProperty "testdata", file('../../../jb/tests/testdata').absolutePath
|
||||
systemProperty "testdata", file('../../../test/jdk/jbu/testdata').absolutePath
|
||||
|
||||
// Generate golden images for DroidFontTest and MixedTextTest
|
||||
// systemProperty "gentestdata", ""
|
||||
|
||||
// Enable Java2D logging (https://confluence.jetbrains.com/display/JRE/Java2D+Rendering+Logging)
|
||||
// systemProperty "sun.java2d.trace", "log"
|
||||
// systemProperty "sun.java2d.trace", "log,pimpl"
|
||||
|
||||
outputs.upToDateWhen { false }
|
||||
executable = test_jvm()
|
||||
|
||||
// Enable J2D logging (only in debug build)
|
||||
// Enable async/dtrace profiler
|
||||
jvmArgs "-XX:+PreserveFramePointer"
|
||||
// Enable native J2D logging (only in debug build)
|
||||
// Can be turned on for J2D by adding "#define DEBUG 1" into jdk/src/share/native/sun/java2d/Trace.h
|
||||
|
||||
// environment 'J2D_TRACE_LEVEL', '4'
|
||||
@@ -96,24 +102,34 @@ if (OperatingSystem.current().isWindows()) {
|
||||
def cyg_make_cmd = new File("c:/cygwin64/bin/make.exe")
|
||||
if (cyg_make_cmd.exists()) make_cmd = cyg_make_cmd.absolutePath
|
||||
}
|
||||
|
||||
task make_images << {
|
||||
def pb = new ProcessBuilder().command(make_cmd.toString(), "-C", buildDir.absolutePath, "images")
|
||||
def proc = pb.redirectErrorStream(true).start()
|
||||
proc.inputStream.eachLine {println it}
|
||||
assert proc.waitFor() == 0
|
||||
def test_run = false
|
||||
task make_images {
|
||||
doLast {
|
||||
if (!test_run) {
|
||||
def pb = new ProcessBuilder().command(make_cmd.toString(), "-C", buildDir.absolutePath, "images")
|
||||
def proc = pb.redirectErrorStream(true).start()
|
||||
proc.inputStream.eachLine { println it }
|
||||
assert proc.waitFor() == 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task make_clean << {
|
||||
def pb = new ProcessBuilder().command(make_cmd.toString(), "-C", buildDir.absolutePath, "clean")
|
||||
def proc = pb.redirectErrorStream(true).start()
|
||||
proc.inputStream.eachLine {println it}
|
||||
assert proc.waitFor() == 0
|
||||
task make_clean {
|
||||
doLast {
|
||||
def pb = new ProcessBuilder().command(make_cmd.toString(), "-C", buildDir.absolutePath, "clean")
|
||||
def proc = pb.redirectErrorStream(true).start()
|
||||
proc.inputStream.eachLine { println it }
|
||||
assert proc.waitFor() == 0
|
||||
}
|
||||
}
|
||||
|
||||
task run_test {
|
||||
doLast {
|
||||
test_run = true
|
||||
}
|
||||
}
|
||||
|
||||
tasks.compileJava.enabled = false
|
||||
tasks.compileTestJava.dependsOn.clear()
|
||||
tasks.cleanTest.dependsOn tasks.run_test
|
||||
classes.dependsOn.clear()
|
||||
classes.dependsOn tasks.make_images
|
||||
tasks.cleanClasses.dependsOn tasks.make_clean
|
||||
|
||||
@@ -31,20 +31,12 @@ import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
// Right now this class is final to avoid a problem with native code.
|
||||
// For some reason the JNI IsInstanceOf was not working correctly
|
||||
// so we are checking the class specifically. If we subclass this
|
||||
// we need to modify the native code in CFontWrapper.m
|
||||
public final class CFont extends PhysicalFont implements FontSubstitution {
|
||||
private static final boolean useCoreTextLayout;
|
||||
|
||||
static {
|
||||
useCoreTextLayout = AccessController.doPrivileged((PrivilegedAction<Boolean>) () ->
|
||||
Boolean.getBoolean("sun.font.use.coretext.layout"));
|
||||
}
|
||||
|
||||
/* CFontStrike doesn't call these methods so they are unimplemented.
|
||||
* They are here to meet the requirements of PhysicalFont, needed
|
||||
@@ -84,18 +76,11 @@ public final class CFont extends PhysicalFont implements FontSubstitution {
|
||||
throw new InternalError("Not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getLayoutTableCache() {
|
||||
return getLayoutTableCacheNative(getNativeFontPtr());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] getTableBytes(int tag) {
|
||||
return getTableBytesNative(getNativeFontPtr(), tag);
|
||||
}
|
||||
|
||||
private native synchronized long getLayoutTableCacheNative(long nativeFontPtr);
|
||||
|
||||
private native byte[] getTableBytesNative(long nativeFontPtr, int tag);
|
||||
|
||||
private static native long createNativeFont(final String nativeFontName,
|
||||
@@ -254,13 +239,6 @@ public final class CFont extends PhysicalFont implements FontSubstitution {
|
||||
return nativeFontName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAAT() {
|
||||
// CoreText layout code ignores fractional metrics font attribute
|
||||
// also, using CoreText layout in Harfbuzz code leads to wrong advances for emoji glyphs
|
||||
return useCoreTextLayout && !"AppleColorEmoji".equals(nativeFontName) && super.isAAT();
|
||||
}
|
||||
|
||||
// <rdar://problem/5321707> sun.font.Font2D caches the last used strike,
|
||||
// but does not check if the properties of the strike match the properties
|
||||
// of the incoming java.awt.Font object (size, style, etc).
|
||||
|
||||
@@ -758,7 +758,7 @@ public class CInputMethod extends InputMethodAdapter {
|
||||
}
|
||||
}
|
||||
}}
|
||||
}, fAwtFocussedComponent);
|
||||
}, fAwtFocussedComponent, true); // [tav] avoid deadlock with javafx
|
||||
} catch (InvocationTargetException ite) { ite.printStackTrace(); }
|
||||
|
||||
synchronized(rect) { return rect; }
|
||||
@@ -779,7 +779,7 @@ public class CInputMethod extends InputMethodAdapter {
|
||||
offsetInfo[0] = fIMContext.getLocationOffset(screenX, screenY);
|
||||
insertPositionOffset[0] = fIMContext.getInsertPositionOffset();
|
||||
}}
|
||||
}, fAwtFocussedComponent);
|
||||
}, fAwtFocussedComponent, true); // [tav] avoid deadlock with javafx
|
||||
} catch (InvocationTargetException ite) { ite.printStackTrace(); }
|
||||
|
||||
// This bit of gymnastics ensures that the returned location is within the composed text.
|
||||
|
||||
@@ -361,11 +361,7 @@ final class CPlatformResponder {
|
||||
characterToSendWithTypedEvent = stringWithChar == null ? KeyEvent.CHAR_UNDEFINED : stringWithChar.charAt(0);
|
||||
}
|
||||
|
||||
boolean nonInputMethodsModifiersAreNotPressed = (jmodifiers &
|
||||
(InputEvent.META_DOWN_MASK | InputEvent.CTRL_DOWN_MASK)
|
||||
) == 0;
|
||||
|
||||
if (nonInputMethodsModifiersAreNotPressed) {
|
||||
if (!nsEvent.isHasDeadKey()) {
|
||||
eventNotifier.notifyKeyEvent(KeyEvent.KEY_TYPED, when, jmodifiers,
|
||||
jkeyCode, characterToSendWithTypedEvent,
|
||||
KeyEvent.KEY_LOCATION_UNKNOWN);
|
||||
|
||||
@@ -507,8 +507,7 @@ static BOOL shouldUsePressAndHold() {
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
|
||||
TISInputSourceRef sourceRef = TISCopyCurrentKeyboardLayoutInputSource();
|
||||
CFDataRef keyLayoutPtr = (CFDataRef)TISGetInputSourceProperty(
|
||||
sourceRef, kTISPropertyUnicodeKeyLayoutData);
|
||||
CFDataRef keyLayoutPtr = (CFDataRef)TISGetInputSourceProperty(sourceRef, kTISPropertyUnicodeKeyLayoutData);
|
||||
CFRelease( sourceRef);
|
||||
|
||||
const UCKeyboardLayout *keyboardLayout = (UCKeyboardLayout*)CFDataGetBytePtr(keyLayoutPtr);
|
||||
@@ -525,7 +524,6 @@ static BOOL shouldUsePressAndHold() {
|
||||
0,
|
||||
LMGetKbdType(),
|
||||
0,
|
||||
// ignore for now
|
||||
&isDeadKeyPressed,
|
||||
lengthOfBuffer,
|
||||
&actualLength,
|
||||
@@ -547,6 +545,8 @@ static BOOL shouldUsePressAndHold() {
|
||||
|
||||
if (status == noErr && isDeadKeyPressed != 0) {
|
||||
|
||||
UInt32 isDeadKeyPressedIgnore = 0;
|
||||
|
||||
status = UCKeyTranslate(
|
||||
keyboardLayout,
|
||||
kVK_Space,
|
||||
@@ -554,7 +554,7 @@ static BOOL shouldUsePressAndHold() {
|
||||
0,
|
||||
LMGetKbdType(),
|
||||
0,
|
||||
&isDeadKeyPressed,
|
||||
&isDeadKeyPressedIgnore,
|
||||
lengthOfBuffer,
|
||||
&actualLength,
|
||||
stringWithChars);
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <JavaRuntimeSupport/JavaRuntimeSupport.h>
|
||||
|
||||
#import "fontscalerdefs.h"
|
||||
|
||||
#define MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE 256
|
||||
|
||||
@interface AWTFont : NSObject {
|
||||
@@ -35,7 +33,6 @@
|
||||
NSFont *fFont;
|
||||
CGFontRef fNativeCGFont;
|
||||
BOOL fIsFakeItalic;
|
||||
TTLayoutTableCache* layoutTableCache;
|
||||
}
|
||||
|
||||
+ (AWTFont *) awtFontForName:(NSString *)name
|
||||
|
||||
@@ -43,33 +43,10 @@
|
||||
if (self) {
|
||||
fFont = [font retain];
|
||||
fNativeCGFont = CTFontCopyGraphicsFont((CTFontRef)font, NULL);
|
||||
layoutTableCache = NULL;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
static TTLayoutTableCache* newCFontLayoutTableCache() {
|
||||
TTLayoutTableCache* ltc = calloc(1, sizeof(TTLayoutTableCache));
|
||||
if (ltc) {
|
||||
int i;
|
||||
for(i=0;i<LAYOUTCACHE_ENTRIES;i++) {
|
||||
ltc->entries[i].len = -1;
|
||||
}
|
||||
}
|
||||
return ltc;
|
||||
}
|
||||
|
||||
static void freeCFontLayoutTableCache(TTLayoutTableCache* ltc) {
|
||||
if (ltc) {
|
||||
int i;
|
||||
for(i=0;i<LAYOUTCACHE_ENTRIES;i++) {
|
||||
if(ltc->entries[i].ptr) free (ltc->entries[i].ptr);
|
||||
}
|
||||
if (ltc->kernPairs) free(ltc->kernPairs);
|
||||
free(ltc);
|
||||
}
|
||||
}
|
||||
|
||||
- (void) dealloc {
|
||||
[fFont release];
|
||||
fFont = nil;
|
||||
@@ -77,10 +54,6 @@ static void freeCFontLayoutTableCache(TTLayoutTableCache* ltc) {
|
||||
if (fNativeCGFont) {
|
||||
CGFontRelease(fNativeCGFont);
|
||||
fNativeCGFont = NULL;
|
||||
if (layoutTableCache != NULL) {
|
||||
freeCFontLayoutTableCache(layoutTableCache);
|
||||
layoutTableCache = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
[super dealloc];
|
||||
@@ -91,10 +64,6 @@ static void freeCFontLayoutTableCache(TTLayoutTableCache* ltc) {
|
||||
CGFontRelease(fNativeCGFont);
|
||||
fNativeCGFont = NULL;
|
||||
}
|
||||
if (layoutTableCache != NULL) {
|
||||
freeCFontLayoutTableCache(layoutTableCache);
|
||||
layoutTableCache = NULL;
|
||||
}
|
||||
[super finalize];
|
||||
}
|
||||
|
||||
@@ -476,23 +445,6 @@ Java_sun_font_CFont_getCGFontPtrNative
|
||||
return (jlong)(awtFont->fNativeCGFont);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_font_CFont
|
||||
* Method: getLayoutTableCacheNative
|
||||
* Signature: (J)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_font_CFont_getLayoutTableCacheNative
|
||||
(JNIEnv *env, jclass clazz,
|
||||
jlong awtFontPtr)
|
||||
{
|
||||
AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr);
|
||||
if (awtFont->layoutTableCache == NULL) {
|
||||
awtFont->layoutTableCache = newCFontLayoutTableCache();
|
||||
}
|
||||
return (jlong)(awtFont->layoutTableCache);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_font_CFont
|
||||
* Method: getTableBytesNative
|
||||
|
||||
@@ -496,18 +496,21 @@ class BufferStrategyPaintManager extends RepaintManager.PaintManager {
|
||||
}
|
||||
}
|
||||
|
||||
if (isPaint && c == rootJ && x == 0 && y == 0 &&
|
||||
c.getWidth() == w && c.getHeight() == h) {
|
||||
|
||||
if (isPaint) {
|
||||
// Fallback to normal painting in undecorated non-opaque dialogs
|
||||
// and frames to resolve black background problem
|
||||
if ((root instanceof Dialog && ((Dialog)root).isUndecorated() ||
|
||||
root instanceof Frame && ((Frame)root).isUndecorated()) &&
|
||||
bsg != null && !c.isOpaque() &&
|
||||
Window window = SunToolkit.getContainingWindow(c);
|
||||
if ((window instanceof Dialog && ((Dialog)window).isUndecorated() ||
|
||||
window instanceof Frame && ((Frame)window).isUndecorated()) &&
|
||||
bsg != null && !window.isOpaque() &&
|
||||
((SunGraphics2D)bsg).getSurfaceData().getTransparency() ==
|
||||
Transparency.OPAQUE) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isPaint && c == rootJ && x == 0 && y == 0 &&
|
||||
c.getWidth() == w && c.getHeight() == h) {
|
||||
bufferInfo.setInSync(true);
|
||||
}
|
||||
else if (contentsLost) {
|
||||
|
||||
@@ -25,9 +25,6 @@
|
||||
|
||||
package sun.font;
|
||||
|
||||
import sun.java2d.Disposer;
|
||||
import sun.java2d.DisposerRecord;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.geom.AffineTransform;
|
||||
@@ -80,8 +77,6 @@ public abstract class Font2D {
|
||||
protected FontFamily family;
|
||||
protected int fontRank = DEFAULT_RANK;
|
||||
|
||||
private HarfbuzzFaceRef harfbuzzFaceRef;
|
||||
|
||||
/*
|
||||
* A mapper can be independent of the strike.
|
||||
* Perhaps the reference to the mapper ought to be held on the
|
||||
@@ -472,36 +467,12 @@ public abstract class Font2D {
|
||||
return null;
|
||||
}
|
||||
|
||||
/* implemented for fonts backed by an sfnt that has
|
||||
* OpenType or AAT layout tables.
|
||||
*/
|
||||
protected long getLayoutTableCache() {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
/* Used only on OS X.
|
||||
*/
|
||||
protected long getPlatformNativeFontPtr() {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
protected boolean isAAT() {
|
||||
return false;
|
||||
}
|
||||
|
||||
synchronized long getHarfbuzzFacePtr() {
|
||||
if (harfbuzzFaceRef == null) {
|
||||
long harfbuzzFaceNativePtr = createHarfbuzzFace(isAAT(), getPlatformNativeFontPtr());
|
||||
if (harfbuzzFaceNativePtr == 0) return 0;
|
||||
harfbuzzFaceRef = new HarfbuzzFaceRef(harfbuzzFaceNativePtr);
|
||||
Disposer.addObjectRecord(this, harfbuzzFaceRef);
|
||||
}
|
||||
return harfbuzzFaceRef.harfbuzzFaceNativePtr;
|
||||
}
|
||||
|
||||
private native long createHarfbuzzFace(boolean aat, long platformNativeFontPtr);
|
||||
private static native void disposeHarfbuzzFace(long harfbuzzFaceNativePtr);
|
||||
|
||||
/* for layout code */
|
||||
protected long getUnitsPerEm() {
|
||||
return 2048;
|
||||
@@ -587,17 +558,4 @@ public abstract class Font2D {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class HarfbuzzFaceRef implements DisposerRecord {
|
||||
private final long harfbuzzFaceNativePtr;
|
||||
|
||||
private HarfbuzzFaceRef(long harfbuzzFaceNativePtr) {
|
||||
this.harfbuzzFaceNativePtr = harfbuzzFaceNativePtr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
disposeHarfbuzzFace(harfbuzzFaceNativePtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,25 +181,6 @@ public abstract class FontScaler implements DisposerRecord {
|
||||
abstract int getMissingGlyphCode() throws FontScalerException;
|
||||
abstract int getGlyphCode(char charCode) throws FontScalerException;
|
||||
|
||||
/* This method returns table cache used by native layout engine.
|
||||
* This cache is essentially just small collection of
|
||||
* pointers to various truetype tables. See definition of TTLayoutTableCache
|
||||
* in the fontscalerdefs.h for more details.
|
||||
*
|
||||
* Note that tables themselves have same format as defined in the truetype
|
||||
* specification, i.e. font scaler do not need to perform any preprocessing.
|
||||
*
|
||||
* Probably it is better to have API to request pointers to each table
|
||||
* separately instead of requesting pointer to some native structure.
|
||||
* (then there is not need to share its definition by different
|
||||
* implementations of scaler).
|
||||
* However, this means multiple JNI calls and potential impact on performance.
|
||||
*
|
||||
* Note: return value 0 is legal.
|
||||
* This means tables are not available (e.g. type1 font).
|
||||
*/
|
||||
abstract long getLayoutTableCache() throws FontScalerException;
|
||||
|
||||
/* Used by the OpenType engine for mark positioning. */
|
||||
abstract Point2D.Float getGlyphPoint(long pScalerContext,
|
||||
int glyphCode, int ptNumber)
|
||||
|
||||
@@ -178,10 +178,6 @@ class FreetypeFontScaler extends FontScaler {
|
||||
.getNullScaler().getGlyphVectorOutline(0L, glyphs, numGlyphs, x, y);
|
||||
}
|
||||
|
||||
synchronized long getLayoutTableCache() throws FontScalerException {
|
||||
return getLayoutTableCacheNative(nativeScaler);
|
||||
}
|
||||
|
||||
public synchronized void dispose() {
|
||||
if (nativeScaler != 0L) {
|
||||
disposeNativeScaler(font.get(), nativeScaler);
|
||||
@@ -258,8 +254,6 @@ class FreetypeFontScaler extends FontScaler {
|
||||
native Point2D.Float getGlyphPointNative(Font2D font,
|
||||
long pScalerContext, long pScaler, int glyphCode, int ptNumber);
|
||||
|
||||
private native long getLayoutTableCacheNative(long pScaler);
|
||||
|
||||
private native void disposeNativeScaler(Font2D font2D, long pScaler);
|
||||
|
||||
private native int getGlyphCodeNative(Font2D font, long pScaler, char charCode);
|
||||
|
||||
@@ -64,8 +64,6 @@ class NullFontScaler extends FontScaler {
|
||||
return new GeneralPath();
|
||||
}
|
||||
|
||||
long getLayoutTableCache() {return 0L;}
|
||||
|
||||
long createScalerContext(double[] matrix, int aa,
|
||||
int fm, float boldness, float italic, boolean disableHinting) {
|
||||
return getNullScalerContext();
|
||||
|
||||
@@ -79,12 +79,6 @@ public abstract class PhysicalFont extends Font2D {
|
||||
return new Point2D.Float();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAAT() {
|
||||
return getTableBytes(TrueTypeFont.morxTag) != null ||
|
||||
getTableBytes(TrueTypeFont.mortTag) != null;
|
||||
}
|
||||
|
||||
/* These 3 metrics methods should be implemented to return
|
||||
* values in user space.
|
||||
*/
|
||||
|
||||
@@ -31,10 +31,13 @@
|
||||
package sun.font;
|
||||
|
||||
import sun.font.GlyphLayout.*;
|
||||
import sun.java2d.Disposer;
|
||||
import sun.java2d.DisposerRecord;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/*
|
||||
* different ways to do this
|
||||
@@ -143,28 +146,80 @@ public final class SunLayoutEngine implements LayoutEngine, LayoutEngineFactory
|
||||
}
|
||||
private SoftReference<ConcurrentHashMap<LayoutEngineKey, LayoutEngine>> cacheref =
|
||||
new SoftReference<>(null);
|
||||
private static final WeakHashMap<Font2D, FaceRef> facePtr =
|
||||
new WeakHashMap<>();
|
||||
|
||||
private static boolean isAAT(Font2D font) {
|
||||
// CoreText layout code ignores fractional metrics font attribute
|
||||
// also, using CoreText layout in Harfbuzz code leads to wrong advances for emoji glyphs
|
||||
return false;
|
||||
}
|
||||
|
||||
private SunLayoutEngine(LayoutEngineKey key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
private long getFacePtr(Font2D font2D) {
|
||||
FaceRef ref;
|
||||
synchronized (facePtr) {
|
||||
ref = facePtr.computeIfAbsent(font2D, FaceRef::new);
|
||||
}
|
||||
return ref.getNativePtr();
|
||||
}
|
||||
|
||||
public void layout(FontStrikeDesc desc, float[] mat, float ptSize, int gmask,
|
||||
int baseIndex, TextRecord tr, int typo_flags,
|
||||
Point2D.Float pt, GVData data) {
|
||||
Font2D font = key.font();
|
||||
FontStrike strike = font.getStrike(desc);
|
||||
shape(font, strike, ptSize, mat,
|
||||
font.getHarfbuzzFacePtr(), font.getPlatformNativeFontPtr(), font.isAAT(),
|
||||
tr.text, data, key.script(),
|
||||
tr.start, tr.limit, baseIndex, pt,
|
||||
typo_flags, gmask);
|
||||
long pNativeFont = font.getPlatformNativeFontPtr(); // used on OSX
|
||||
long pFace = getFacePtr(font);
|
||||
if (pFace != 0) {
|
||||
shape(font, strike, ptSize, mat, pNativeFont,
|
||||
pFace, isAAT(font),
|
||||
tr.text, data, key.script(),
|
||||
tr.start, tr.limit, baseIndex, pt,
|
||||
typo_flags, gmask);
|
||||
}
|
||||
}
|
||||
|
||||
/* Native method to invoke harfbuzz layout engine */
|
||||
private static native boolean
|
||||
shape(Font2D font, FontStrike strike, float ptSize, float[] mat,
|
||||
long pscaler, long pNativeFont, boolean aat,
|
||||
long pNativeFont, long pFace, boolean aat,
|
||||
char[] chars, GVData data,
|
||||
int script, int offset, int limit,
|
||||
int baseIndex, Point2D.Float pt, int typo_flags, int slot);
|
||||
|
||||
private static native long createFace(Font2D font,
|
||||
boolean aat,
|
||||
long platformNativeFontPtr);
|
||||
|
||||
private static native void disposeFace(long facePtr);
|
||||
|
||||
private static class FaceRef implements DisposerRecord {
|
||||
private Font2D font;
|
||||
private Long facePtr;
|
||||
|
||||
private FaceRef(Font2D font) {
|
||||
this.font = font;
|
||||
}
|
||||
|
||||
private synchronized long getNativePtr() {
|
||||
if (facePtr == null) {
|
||||
facePtr = createFace(font, isAAT(font),
|
||||
font.getPlatformNativeFontPtr());
|
||||
if (facePtr != 0) {
|
||||
Disposer.addObjectRecord(font, this);
|
||||
}
|
||||
font = null;
|
||||
}
|
||||
return facePtr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
disposeFace(facePtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -898,15 +898,6 @@ public class TrueTypeFont extends FileFont {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getLayoutTableCache() {
|
||||
try {
|
||||
return getScaler().getLayoutTableCache();
|
||||
} catch(FontScalerException fe) {
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] getTableBytes(int tag) {
|
||||
ByteBuffer buffer = getTableBuffer(tag);
|
||||
@@ -999,12 +990,6 @@ public class TrueTypeFont extends FileFont {
|
||||
return (fontWeight > 0) ? fontWeight : super.getWeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAAT() {
|
||||
return getDirectoryEntry(TrueTypeFont.morxTag) != null ||
|
||||
getDirectoryEntry(TrueTypeFont.mortTag) != null;
|
||||
}
|
||||
|
||||
/* TrueTypeFont can use the fsSelection fields of OS/2 table
|
||||
* to determine the style. In the unlikely case that doesn't exist,
|
||||
* can use macStyle in the 'head' table but simpler to
|
||||
|
||||
@@ -88,32 +88,8 @@ typedef struct GlyphInfo {
|
||||
*/
|
||||
#define INVISIBLE_GLYPHS 0xfffe
|
||||
|
||||
#define GSUB_TAG 0x47535542 /* 'GSUB' */
|
||||
#define GPOS_TAG 0x47504F53 /* 'GPOS' */
|
||||
#define GDEF_TAG 0x47444546 /* 'GDEF' */
|
||||
#define HEAD_TAG 0x68656164 /* 'head' */
|
||||
#define MORT_TAG 0x6D6F7274 /* 'mort' */
|
||||
#define MORX_TAG 0x6D6F7278 /* 'morx' */
|
||||
#define KERN_TAG 0x6B65726E /* 'kern' */
|
||||
|
||||
typedef struct TTLayoutTableCacheEntry {
|
||||
const void* ptr;
|
||||
int len;
|
||||
int tag;
|
||||
} TTLayoutTableCacheEntry;
|
||||
|
||||
#define LAYOUTCACHE_ENTRIES 7
|
||||
|
||||
typedef struct TTLayoutTableCache {
|
||||
TTLayoutTableCacheEntry entries[LAYOUTCACHE_ENTRIES];
|
||||
void* kernPairs;
|
||||
} TTLayoutTableCache;
|
||||
|
||||
#include "sunfontids.h"
|
||||
|
||||
JNIEXPORT extern TTLayoutTableCache* newLayoutTableCache();
|
||||
JNIEXPORT extern void freeLayoutTableCache(TTLayoutTableCache* ltc);
|
||||
|
||||
/* If font is malformed then scaler context created by particular scaler
|
||||
* will be replaced by null scaler context.
|
||||
* Note that this context is not compatible with structure of the context
|
||||
|
||||
@@ -131,6 +131,7 @@ typedef void (GLAPIENTRY *glViewportType)(GLint x, GLint y, GLsizei width, GLsiz
|
||||
* extensions, which is why they are called out separately here)
|
||||
*/
|
||||
typedef void (GLAPIENTRY *glActiveTextureARBType)(GLenum texture);
|
||||
typedef void (GLAPIENTRY *glClientActiveTextureType)(GLenum texture);
|
||||
typedef void (GLAPIENTRY *glMultiTexCoord2fARBType)(GLenum texture, GLfloat s, GLfloat t);
|
||||
typedef void (GLAPIENTRY *glTexImage3DType)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
|
||||
|
||||
@@ -290,6 +291,7 @@ typedef void (GLAPIENTRY *glTextureBarrierNVType) (void);
|
||||
|
||||
#define OGL_EXPRESS_EXT_FUNCS(action) \
|
||||
OGL_##action##_EXT_FUNC(glActiveTextureARB); \
|
||||
OGL_##action##_EXT_FUNC(glClientActiveTexture); \
|
||||
OGL_##action##_EXT_FUNC(glMultiTexCoord2fARB); \
|
||||
OGL_##action##_EXT_FUNC(glTexImage3D); \
|
||||
OGL_##action##_EXT_FUNC(glBindRenderbufferEXT); \
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "OGLTextRenderer.h"
|
||||
#include "OGLVertexCache.h"
|
||||
#include "AccelGlyphCache.h"
|
||||
#include "jni_util.h"
|
||||
|
||||
/**
|
||||
* The following constants define the inner and outer bounds of the
|
||||
@@ -712,21 +713,14 @@ OGLTR_UpdateCachedDestination(OGLSDOps *dstOps, GlyphInfo *ginfo,
|
||||
}
|
||||
|
||||
static jboolean
|
||||
OGLTR_DrawLCDGlyphViaCache(OGLContext *oglc, OGLSDOps *dstOps,
|
||||
GlyphInfo *ginfo, jint x, jint y,
|
||||
jint glyphIndex, jint totalGlyphs,
|
||||
jboolean rgbOrder, jint contrast,
|
||||
GLuint dstTextureID, jboolean * opened)
|
||||
OGLTR_DrawLCDGlyphViaCache(OGLContext *oglc, OGLSDOps *dstOps, GlyphInfo *ginfo, jint x, jint y, jint glyphIndex,
|
||||
jint totalGlyphs, jboolean rgbOrder, jint contrast, GLuint dstTextureID)
|
||||
{
|
||||
CacheCellInfo *cell;
|
||||
jint dx1, dy1, dx2, dy2;
|
||||
jfloat dtx1, dty1, dtx2, dty2;
|
||||
|
||||
if (glyphMode != MODE_USE_CACHE_LCD) {
|
||||
if (*opened) {
|
||||
*opened = JNI_FALSE;
|
||||
j2d_glEnd();
|
||||
}
|
||||
OGLTR_DisableGlyphModeState();
|
||||
CHECK_PREVIOUS_OP(GL_TEXTURE_2D);
|
||||
j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
@@ -758,10 +752,6 @@ OGLTR_DrawLCDGlyphViaCache(OGLContext *oglc, OGLSDOps *dstOps,
|
||||
}
|
||||
|
||||
if (ginfo->cellInfo == NULL) {
|
||||
if (*opened) {
|
||||
*opened = JNI_FALSE;
|
||||
j2d_glEnd();
|
||||
}
|
||||
// rowBytes will always be a multiple of 3, so the following is safe
|
||||
j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, ginfo->rowBytes / 3);
|
||||
|
||||
@@ -787,10 +777,6 @@ OGLTR_DrawLCDGlyphViaCache(OGLContext *oglc, OGLSDOps *dstOps,
|
||||
dy2 = dy1 + ginfo->height;
|
||||
|
||||
if (dstTextureID == 0) {
|
||||
if (*opened) {
|
||||
*opened = JNI_FALSE;
|
||||
j2d_glEnd();
|
||||
}
|
||||
// copy destination into second cached texture, if necessary
|
||||
OGLTR_UpdateCachedDestination(dstOps, ginfo,
|
||||
dx1, dy1, dx2, dy2,
|
||||
@@ -818,23 +804,12 @@ OGLTR_DrawLCDGlyphViaCache(OGLContext *oglc, OGLSDOps *dstOps,
|
||||
}
|
||||
|
||||
// render composed texture to the destination surface
|
||||
if (!*opened) {
|
||||
j2d_glBegin(GL_QUADS);
|
||||
*opened = JNI_TRUE;
|
||||
if (!OGLMTVertexCache_enable(oglc, dstTextureID != 0)) {
|
||||
J2dTracePrimitive("OGLMTVertexCache_enable_failed");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx1, cell->ty1);
|
||||
j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty1);
|
||||
j2d_glVertex2i(dx1, dy1);
|
||||
j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx2, cell->ty1);
|
||||
j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty1);
|
||||
j2d_glVertex2i(dx2, dy1);
|
||||
j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx2, cell->ty2);
|
||||
j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty2);
|
||||
j2d_glVertex2i(dx2, dy2);
|
||||
j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx1, cell->ty2);
|
||||
j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty2);
|
||||
j2d_glVertex2i(dx1, dy2);
|
||||
OGLMTVertexCache_addGlyphQuad(dx1, dy1, dx2, dy2, cell->tx1, cell->ty1,
|
||||
cell->tx2, cell->ty2, dtx1, dty1, dtx2, dty2);
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
@@ -1066,11 +1041,13 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
|
||||
{
|
||||
int glyphCounter;
|
||||
GLuint dstTextureID = 0;
|
||||
jboolean hasLCDGlyphs = JNI_FALSE;
|
||||
jboolean lcdOpened = JNI_FALSE;
|
||||
jint ox1 = INT_MIN;
|
||||
jlong time;
|
||||
|
||||
J2dTraceLn(J2D_TRACE_INFO, "OGLTR_DrawGlyphList");
|
||||
if (graphicsPrimitive_traceflags & J2D_PTRACE_TIME) {
|
||||
J2dTracePrimitive("OGLTR_DrawGlyphList");
|
||||
time = J2dTraceNanoTime();
|
||||
}
|
||||
|
||||
RETURN_IF_NULL(oglc);
|
||||
RETURN_IF_NULL(dstOps);
|
||||
@@ -1138,10 +1115,7 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
|
||||
}
|
||||
|
||||
if (ginfo->rowBytes == ginfo->width) {
|
||||
if (lcdOpened) {
|
||||
lcdOpened = JNI_FALSE;
|
||||
j2d_glEnd();
|
||||
}
|
||||
OGLMTVertexCache_disable();
|
||||
// grayscale or monochrome glyph data
|
||||
if (ginfo->width <= OGLTR_CACHE_CELL_WIDTH &&
|
||||
ginfo->height <= OGLTR_CACHE_CELL_HEIGHT)
|
||||
@@ -1151,18 +1125,12 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
|
||||
ok = OGLTR_DrawGrayscaleGlyphNoCache(oglc, ginfo, x, y);
|
||||
}
|
||||
} else if (ginfo->rowBytes == ginfo->width * 4) {
|
||||
OGLMTVertexCache_disable();
|
||||
// color glyph data
|
||||
ok = OGLTR_DrawColorGlyphNoCache(oglc, ginfo, x, y);
|
||||
} else {
|
||||
// LCD-optimized glyph data
|
||||
jint rowBytesOffset = 0;
|
||||
if (!hasLCDGlyphs) {
|
||||
// Flush GPU buffers before processing first LCD glyph
|
||||
hasLCDGlyphs = JNI_TRUE;
|
||||
if (dstTextureID != 0) {
|
||||
j2d_glTextureBarrierNV();
|
||||
}
|
||||
}
|
||||
|
||||
if (subPixPos) {
|
||||
jint frac = (jint)((glyphx - x) * 3);
|
||||
@@ -1172,29 +1140,16 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
|
||||
}
|
||||
}
|
||||
|
||||
// Flush GPU buffers before processing overlapping LCD glyphs on OSX
|
||||
if (dstTextureID != 0 && ox1 > x) {
|
||||
if (lcdOpened) {
|
||||
lcdOpened = JNI_FALSE;
|
||||
j2d_glEnd();
|
||||
}
|
||||
j2d_glTextureBarrierNV();
|
||||
}
|
||||
|
||||
if (rowBytesOffset == 0 &&
|
||||
ginfo->width <= OGLTR_CACHE_CELL_WIDTH &&
|
||||
ginfo->height <= OGLTR_CACHE_CELL_HEIGHT)
|
||||
{
|
||||
ok = OGLTR_DrawLCDGlyphViaCache(oglc, dstOps,
|
||||
ginfo, x, y,
|
||||
ok = OGLTR_DrawLCDGlyphViaCache(oglc, dstOps, ginfo, x, y,
|
||||
glyphCounter, totalGlyphs,
|
||||
rgbOrder, lcdContrast,
|
||||
dstTextureID, &lcdOpened);
|
||||
dstTextureID);
|
||||
} else {
|
||||
if (lcdOpened) {
|
||||
lcdOpened = JNI_FALSE;
|
||||
j2d_glEnd();
|
||||
}
|
||||
OGLMTVertexCache_disable();
|
||||
ok = OGLTR_DrawLCDGlyphNoCache(oglc, dstOps,
|
||||
ginfo, x, y,
|
||||
rowBytesOffset,
|
||||
@@ -1202,15 +1157,12 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
|
||||
dstTextureID);
|
||||
}
|
||||
}
|
||||
|
||||
ox1 = x + ginfo->width;
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lcdOpened) {
|
||||
j2d_glEnd();
|
||||
}
|
||||
OGLMTVertexCache_disable();
|
||||
J2dTracePrimitiveTime("OGLTR_DrawGlyphList", time);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
|
||||
@@ -27,9 +27,11 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <float.h>
|
||||
|
||||
#include "sun_java2d_SunGraphics2D.h"
|
||||
|
||||
#include "jni_util.h"
|
||||
#include "OGLPaints.h"
|
||||
#include "OGLVertexCache.h"
|
||||
|
||||
@@ -39,11 +41,28 @@ typedef struct _J2DVertex {
|
||||
jfloat dx, dy;
|
||||
} J2DVertex;
|
||||
|
||||
// Multitexture vertex
|
||||
typedef struct _J2DMTVertex {
|
||||
jfloat dx, dy;
|
||||
jfloat tx0, ty0;
|
||||
jfloat tx1, ty1;
|
||||
} J2DMTVertex;
|
||||
|
||||
static J2DVertex *vertexCache = NULL;
|
||||
static jint vertexCacheIndex = 0;
|
||||
|
||||
static J2DMTVertex *mtVertexCache = NULL;
|
||||
static jboolean mtVertexCacheEnabled = JNI_FALSE;
|
||||
static jboolean mtUseTxtBarrier = JNI_FALSE;
|
||||
static jint evenLCDGlyphInd = 0;
|
||||
static jint oddLCDGlyphInd = ODD_LCD_GLYPHS_OFFSET;
|
||||
static jint lcdGlyphInd = 0;
|
||||
static jfloat evenOx2 = FLT_MIN;
|
||||
static jfloat oddOx2 = FLT_MIN;
|
||||
|
||||
static GLuint maskCacheTexID = 0;
|
||||
static jint maskCacheIndex = 0;
|
||||
static void OGLMTVertexCache_flush(jint mask);
|
||||
|
||||
#define OGLVC_ADD_VERTEX(TX, TY, R, G, B, A, DX, DY) \
|
||||
do { \
|
||||
@@ -66,6 +85,25 @@ static jint maskCacheIndex = 0;
|
||||
OGLVC_ADD_VERTEX(TX1, TY2, R, G, B, A, DX1, DY2); \
|
||||
} while (0)
|
||||
|
||||
#define OGLMTVC_ADD_VERTEX(IND, DX, DY, TX0, TY0, TX1, TY1) \
|
||||
do { \
|
||||
J2DMTVertex *v = &mtVertexCache[IND++]; \
|
||||
v->dx = DX; \
|
||||
v->dy = DY; \
|
||||
v->tx0 = TX0; \
|
||||
v->ty0 = TY0; \
|
||||
v->tx1 = TX1; \
|
||||
v->ty1 = TY1; \
|
||||
} while (0)
|
||||
|
||||
#define OGLMTVC_ADD_QUAD(IND, DX1, DY1, DX2, DY2, TX1, TY1, TX2, TY2, DTX1, DTY1, DTX2, DTY2) \
|
||||
do { \
|
||||
OGLMTVC_ADD_VERTEX((IND), DX1, DY1, TX1, TY1, DTX1, DTY1); \
|
||||
OGLMTVC_ADD_VERTEX((IND), DX2, DY1, TX2, TY1, DTX2, DTY1); \
|
||||
OGLMTVC_ADD_VERTEX((IND), DX2, DY2, TX2, TY2, DTX2, DTY2); \
|
||||
OGLMTVC_ADD_VERTEX((IND), DX1, DY2, TX1, TY2, DTX1, DTY2); \
|
||||
} while (0)
|
||||
|
||||
jboolean
|
||||
OGLVertexCache_InitVertexCache(OGLContext *oglc)
|
||||
{
|
||||
@@ -287,4 +325,97 @@ OGLVertexCache_AddGlyphQuad(OGLContext *oglc,
|
||||
oglc->r, oglc->g, oglc->b, oglc->a);
|
||||
}
|
||||
|
||||
jboolean OGLMTVertexCache_enable(OGLContext *oglc, jboolean useTxtBarrier) {
|
||||
mtUseTxtBarrier = useTxtBarrier;
|
||||
if (mtVertexCache == NULL) {
|
||||
mtVertexCache = (J2DMTVertex *)malloc(OGLMTVC_MAX_INDEX * sizeof(J2DMTVertex));
|
||||
if (mtVertexCache == NULL) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mtVertexCacheEnabled) {
|
||||
oglc->vertexCacheEnabled = JNI_FALSE;
|
||||
|
||||
j2d_glVertexPointer(2, GL_FLOAT, sizeof(J2DMTVertex), &mtVertexCache[0].dx);
|
||||
j2d_glEnableClientState(GL_VERTEX_ARRAY);
|
||||
j2d_glClientActiveTexture(GL_TEXTURE1_ARB);
|
||||
j2d_glTexCoordPointer(2, GL_FLOAT, sizeof(J2DMTVertex), &mtVertexCache[0].tx1);
|
||||
j2d_glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
j2d_glClientActiveTexture(GL_TEXTURE0_ARB);
|
||||
j2d_glTexCoordPointer(2, GL_FLOAT, sizeof(J2DMTVertex), &mtVertexCache[0].tx0);
|
||||
j2d_glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
mtVertexCacheEnabled = JNI_TRUE;
|
||||
evenLCDGlyphInd = 0;
|
||||
oddLCDGlyphInd = ODD_LCD_GLYPHS_OFFSET;
|
||||
lcdGlyphInd = 0;
|
||||
}
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
void OGLMTVertexCache_disable() {
|
||||
if (mtVertexCacheEnabled) {
|
||||
OGLMTVertexCache_flush(OGLMTVC_FLUSH_ALL);
|
||||
mtVertexCacheEnabled = JNI_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void OGLMTVertexCache_flush(jint mask) {
|
||||
if (mtVertexCacheEnabled) {
|
||||
if ((mask & OGLMTVC_FLUSH_EVEN) && evenLCDGlyphInd > 0) {
|
||||
if (mtUseTxtBarrier) {
|
||||
// TextureBarrierNV() will guarantee that writes have completed
|
||||
// and caches have been invalidated before subsequent Draws are
|
||||
// executed
|
||||
j2d_glTextureBarrierNV();
|
||||
evenOx2 = FLT_MIN;
|
||||
}
|
||||
j2d_glDrawArrays(GL_QUADS, 0, evenLCDGlyphInd);
|
||||
evenLCDGlyphInd = 0;
|
||||
}
|
||||
|
||||
if ((mask & OGLMTVC_FLUSH_ODD) && oddLCDGlyphInd > ODD_LCD_GLYPHS_OFFSET) {
|
||||
if (mtUseTxtBarrier) {
|
||||
// See the comment above
|
||||
j2d_glTextureBarrierNV();
|
||||
oddOx2 = FLT_MIN;
|
||||
}
|
||||
j2d_glDrawArrays(GL_QUADS, ODD_LCD_GLYPHS_OFFSET,
|
||||
oddLCDGlyphInd - ODD_LCD_GLYPHS_OFFSET);
|
||||
oddLCDGlyphInd = ODD_LCD_GLYPHS_OFFSET;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OGLMTVertexCache_addGlyphQuad(jfloat dx1, jfloat dy1,
|
||||
jfloat dx2, jfloat dy2,
|
||||
jfloat tx1, jfloat ty1,
|
||||
jfloat tx2, jfloat ty2,
|
||||
jfloat dtx1, jfloat dty1,
|
||||
jfloat dtx2, jfloat dty2)
|
||||
{
|
||||
jint* ind;
|
||||
if (lcdGlyphInd & 0x1) {
|
||||
if (oddLCDGlyphInd >= OGLMTVC_MAX_INDEX ||
|
||||
(mtUseTxtBarrier && oddOx2 >= dx1))
|
||||
{
|
||||
OGLMTVertexCache_flush(OGLMTVC_FLUSH_ODD);
|
||||
} else if (mtUseTxtBarrier) {
|
||||
oddOx2 = dx2;
|
||||
}
|
||||
ind = &oddLCDGlyphInd;
|
||||
} else {
|
||||
if (evenLCDGlyphInd >= ODD_LCD_GLYPHS_OFFSET ||
|
||||
(mtUseTxtBarrier && evenOx2 >= dx1))
|
||||
{
|
||||
OGLMTVertexCache_flush(OGLMTVC_FLUSH_EVEN);
|
||||
} else if (mtUseTxtBarrier) {
|
||||
evenOx2 = dx2;
|
||||
}
|
||||
ind = &evenLCDGlyphInd;
|
||||
}
|
||||
lcdGlyphInd++;
|
||||
OGLMTVC_ADD_QUAD(*ind, dx1, dy1, dx2, dy2, tx1, ty1, tx2, ty2, dtx1, dty1, dtx2, dty2);
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
|
||||
@@ -30,9 +30,14 @@
|
||||
#include "OGLContext.h"
|
||||
|
||||
/**
|
||||
* Constants that control the size of the vertex cache.
|
||||
* Constants that control the size of the vertex caches.
|
||||
*/
|
||||
#define OGLVC_MAX_INDEX 1024
|
||||
#define OGLMTVC_MAX_INDEX 2048
|
||||
#define ODD_LCD_GLYPHS_OFFSET (OGLMTVC_MAX_INDEX >> 1)
|
||||
#define OGLMTVC_FLUSH_EVEN 1
|
||||
#define OGLMTVC_FLUSH_ODD 2
|
||||
#define OGLMTVC_FLUSH_ALL 3
|
||||
|
||||
/**
|
||||
* Constants that control the size of the texture tile cache used for
|
||||
@@ -83,4 +88,14 @@ void OGLVertexCache_AddGlyphQuad(OGLContext *oglc,
|
||||
jfloat dx1, jfloat dy1,
|
||||
jfloat dx2, jfloat dy2);
|
||||
|
||||
jboolean OGLMTVertexCache_enable(OGLContext *oglc, jboolean useTxtBarrier);
|
||||
void OGLMTVertexCache_addGlyphQuad(jfloat dx1, jfloat dy1,
|
||||
jfloat dx2, jfloat dy2,
|
||||
jfloat tx1, jfloat ty1,
|
||||
jfloat tx2, jfloat ty2,
|
||||
jfloat dtx1, jfloat dty1,
|
||||
jfloat dtx2, jfloat dty2);
|
||||
void OGLMTVertexCache_disable();
|
||||
|
||||
|
||||
#endif /* OGLVertexCache_h_Included */
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
#include <jni.h>
|
||||
#include "debug_trace.h"
|
||||
#include "jni_util.h"
|
||||
#ifdef __MACH__
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -53,6 +56,8 @@ JNIEXPORT extern jint graphicsPrimitive_traceflags;
|
||||
#define J2D_TRACE_VERBOSE2 5
|
||||
#define J2D_TRACE_MAX (J2D_TRACE_VERBOSE2+1)
|
||||
|
||||
#define J2D_PTRACE_TIME 8
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
J2dTraceImpl(int level, jboolean cr, const char *string, ...);
|
||||
JNIEXPORT void JNICALL
|
||||
@@ -182,13 +187,41 @@ J2dTraceInit();
|
||||
if (graphicsPrimitive_traceflags && jvm) { \
|
||||
void *env; \
|
||||
jstring jstr; \
|
||||
(*jvm)->AttachCurrentThreadAsDaemon(jvm, &env, NULL); \
|
||||
(*jvm)->AttachCurrentThreadAsDaemon(jvm, (void**)&env, NULL); \
|
||||
jstr = (*(JNIEnv*)env)->NewStringUTF(env, string); \
|
||||
JNU_CallStaticMethodByName(env, NULL, "sun/java2d/loops/GraphicsPrimitive", \
|
||||
"tracePrimitive", "(Ljava/lang/Object;)V", jstr); \
|
||||
JNU_CallStaticMethodByName( \
|
||||
env, NULL, "sun/java2d/loops/GraphicsPrimitive", \
|
||||
"tracePrimitive", "(Ljava/lang/Object;)V", jstr); \
|
||||
(*(JNIEnv*)env)->DeleteLocalRef(env, jstr); \
|
||||
} \
|
||||
}
|
||||
|
||||
#ifdef __MACH__
|
||||
#define J2dTraceNanoTime() (mach_absolute_time())
|
||||
|
||||
#define J2dTracePrimitiveTime(string,t0) { \
|
||||
if ((graphicsPrimitive_traceflags & J2D_PTRACE_TIME) && jvm) { \
|
||||
JNIEnv *env; \
|
||||
jstring jstr; \
|
||||
static mach_timebase_info_data_t ti; \
|
||||
jlong t1; \
|
||||
t1 = mach_absolute_time(); \
|
||||
if (ti.denom == 0) { \
|
||||
(void) mach_timebase_info(&ti); \
|
||||
} \
|
||||
(*jvm)->AttachCurrentThreadAsDaemon(jvm, &env, NULL); \
|
||||
jstr = (*env)->NewStringUTF(env, string); \
|
||||
JNU_CallStaticMethodByName(env, NULL, "sun/java2d/loops/GraphicsPrimitive", \
|
||||
"tracePrimitiveTime", "(Ljava/lang/Object;J)V", jstr,\
|
||||
(((t1-t0)*ti.numer)/ti.denom)); \
|
||||
(*env)->DeleteLocalRef(env, jstr); \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define J2dTracePrimitiveTime(string,t)
|
||||
#define J2dTraceNanoTime() (0)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@@ -238,8 +238,8 @@ JNIEXPORT jboolean JNICALL Java_sun_font_SunLayoutEngine_shape
|
||||
jobject fontStrike,
|
||||
jfloat ptSize,
|
||||
jfloatArray matrix,
|
||||
jlong pFace,
|
||||
jlong pNativeFont,
|
||||
jlong pFace,
|
||||
jboolean aat,
|
||||
jcharArray text,
|
||||
jobject gvdata,
|
||||
|
||||
@@ -111,7 +111,6 @@ typedef struct {
|
||||
unsigned fontDataOffset;
|
||||
unsigned fontDataLength;
|
||||
unsigned fileSize;
|
||||
TTLayoutTableCache* layoutTables;
|
||||
} FTScalerInfo;
|
||||
|
||||
typedef struct FTScalerContext {
|
||||
@@ -494,7 +493,6 @@ Java_sun_font_FreetypeFontScaler_initNativeScaler(
|
||||
if (type == TYPE1_FROM_JAVA) { /* TYPE1 */
|
||||
scalerInfo->fontData = (unsigned char*) malloc(filesize);
|
||||
scalerInfo->directBuffer = NULL;
|
||||
scalerInfo->layoutTables = NULL;
|
||||
scalerInfo->fontDataLength = filesize;
|
||||
|
||||
if (scalerInfo->fontData != NULL) {
|
||||
@@ -1343,32 +1341,6 @@ Java_sun_font_FreetypeFontScaler_getGlyphImageNative(
|
||||
return ptr_to_jlong(glyphInfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Class: sun_font_FreetypeFontScaler
|
||||
* Method: getLayoutTableCacheNative
|
||||
* Signature: (J)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_font_FreetypeFontScaler_getLayoutTableCacheNative(
|
||||
JNIEnv *env, jobject scaler, jlong pScaler) {
|
||||
FTScalerInfo *scalerInfo = (FTScalerInfo*) jlong_to_ptr(pScaler);
|
||||
|
||||
if (scalerInfo == NULL) {
|
||||
invalidateJavaScaler(env, scaler, scalerInfo);
|
||||
return 0L;
|
||||
}
|
||||
|
||||
// init layout table cache in font
|
||||
// we're assuming the font is a file font and moreover it is Truetype font
|
||||
// otherwise we shouldn't be able to get here...
|
||||
if (scalerInfo->layoutTables == NULL) {
|
||||
scalerInfo->layoutTables = newLayoutTableCache();
|
||||
}
|
||||
|
||||
return ptr_to_jlong(scalerInfo->layoutTables);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_font_FreetypeFontScaler
|
||||
* Method: disposeNativeScaler
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
*/
|
||||
|
||||
#include "jlong.h"
|
||||
#include "sun_font_Font2D.h"
|
||||
#include "sun_font_SunLayoutEngine.h"
|
||||
|
||||
#include "hb.h"
|
||||
#include "hb-jdk.h"
|
||||
#ifdef MACOSX
|
||||
@@ -283,6 +284,9 @@ _hb_jdk_get_font_funcs (void)
|
||||
static void _do_nothing(void) {
|
||||
}
|
||||
|
||||
static void _free_nothing(void*) {
|
||||
}
|
||||
|
||||
struct Font2DPtr {
|
||||
JavaVM* vmPtr;
|
||||
jweak font2DRef;
|
||||
@@ -295,7 +299,7 @@ static void cleanupFontInfo(void* data) {
|
||||
fontInfo = (Font2DPtr*) data;
|
||||
fontInfo->vmPtr->GetEnv((void**)&env, JNI_VERSION_1_1);
|
||||
env->DeleteWeakGlobalRef(fontInfo->font2DRef);
|
||||
free((void*)data);
|
||||
free(data);
|
||||
}
|
||||
|
||||
static hb_blob_t *
|
||||
@@ -305,7 +309,13 @@ reference_table(hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) {
|
||||
JNIEnv* env;
|
||||
jobject font2D;
|
||||
jsize length;
|
||||
jbyte* buffer;
|
||||
void* buffer;
|
||||
|
||||
// HB_TAG_NONE is 0 and is used to get the whole font file.
|
||||
// It is not expected to be needed for JDK.
|
||||
if (tag == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fontInfo = (Font2DPtr*)user_data;
|
||||
fontInfo->vmPtr->GetEnv((void**)&env, JNI_VERSION_1_1);
|
||||
@@ -314,31 +324,32 @@ reference_table(hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) {
|
||||
}
|
||||
font2D = fontInfo->font2DRef;
|
||||
|
||||
// HB_TAG_NONE is 0 and is used to get the whole font file.
|
||||
// It is not expected not be needed for JDK.
|
||||
if (tag == 0) {
|
||||
return NULL;
|
||||
}
|
||||
jbyteArray tableBytes = (jbyteArray)
|
||||
env->CallObjectMethod(font2D, sunFontIDs.getTableBytesMID, tag);
|
||||
if (tableBytes == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
length = env->GetArrayLength(tableBytes);
|
||||
buffer = (jbyte *)calloc(length, sizeof(jbyte));
|
||||
env->GetByteArrayRegion(tableBytes, 0, length, buffer);
|
||||
buffer = calloc(length, sizeof(jbyte));
|
||||
env->GetByteArrayRegion(tableBytes, 0, length, (jbyte*)buffer);
|
||||
|
||||
return hb_blob_create((const char *)buffer, length,
|
||||
HB_MEMORY_MODE_WRITABLE,
|
||||
buffer, free);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
/*
|
||||
* Class: sun_font_Font2D
|
||||
* Method: createHarfbuzzFace
|
||||
* Signature: (ZJ)J
|
||||
* Class: sun_font_SunLayoutEngine
|
||||
* Method: createFace
|
||||
* Signature: (Lsun/font/Font2D;ZJJ)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_sun_font_Font2D_createHarfbuzzFace(JNIEnv *env, jobject font2D, jboolean aat, jlong platformFontPtr) {
|
||||
JNIEXPORT jlong JNICALL Java_sun_font_SunLayoutEngine_createFace(JNIEnv *env,
|
||||
jclass cls,
|
||||
jobject font2D,
|
||||
jboolean aat,
|
||||
jlong platformFontPtr) {
|
||||
#ifdef MACOSX
|
||||
if (aat && platformFontPtr) {
|
||||
hb_face_t *face = hb_coretext_face_create((CGFontRef)platformFontPtr);
|
||||
@@ -353,20 +364,29 @@ JNIEXPORT jlong JNICALL Java_sun_font_Font2D_createHarfbuzzFace(JNIEnv *env, job
|
||||
env->GetJavaVM(&vmPtr);
|
||||
fi->vmPtr = vmPtr;
|
||||
fi->font2DRef = env->NewWeakGlobalRef(font2D);
|
||||
hb_face_t *face = hb_face_create_for_tables(reference_table, fi, cleanupFontInfo);
|
||||
if (!fi->font2DRef) {
|
||||
free(fi);
|
||||
return 0;
|
||||
}
|
||||
hb_face_t *face = hb_face_create_for_tables(reference_table, fi,
|
||||
cleanupFontInfo);
|
||||
return ptr_to_jlong(face);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_font_Font2D
|
||||
* Method: disposeHarfbuzzFace
|
||||
* Class: sun_font_SunLayoutEngine
|
||||
* Method: disposeFace
|
||||
* Signature: (J)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_font_Font2D_disposeHarfbuzzFace(JNIEnv *env, jclass cls, jlong ptr) {
|
||||
JNIEXPORT void JNICALL Java_sun_font_SunLayoutEngine_disposeFace(JNIEnv *env,
|
||||
jclass cls,
|
||||
jlong ptr) {
|
||||
hb_face_t* face = (hb_face_t*) jlong_to_ptr(ptr);
|
||||
hb_face_destroy(face);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
static hb_font_t* _hb_jdk_font_create(hb_face_t* face,
|
||||
JDKFontInfo *jdkFontInfo,
|
||||
hb_destroy_func_t destroy) {
|
||||
@@ -384,7 +404,8 @@ static hb_font_t* _hb_jdk_font_create(hb_face_t* face,
|
||||
}
|
||||
|
||||
#ifdef MACOSX
|
||||
static hb_font_t* _hb_jdk_ct_font_create(hb_face_t* face, JDKFontInfo *jdkFontInfo) {
|
||||
static hb_font_t* _hb_jdk_ct_font_create(hb_face_t* face,
|
||||
JDKFontInfo *jdkFontInfo) {
|
||||
|
||||
hb_font_t *font = NULL;
|
||||
font = hb_font_create(face);
|
||||
@@ -395,19 +416,13 @@ static hb_font_t* _hb_jdk_ct_font_create(hb_face_t* face, JDKFontInfo *jdkFontIn
|
||||
}
|
||||
#endif
|
||||
|
||||
hb_font_t* hb_jdk_font_create(hb_face_t* hbface,
|
||||
JDKFontInfo *jdkFontInfo,
|
||||
hb_font_t* hb_jdk_font_create(hb_face_t* hbFace,
|
||||
JDKFontInfo *jdkFontInfo,
|
||||
hb_destroy_func_t destroy) {
|
||||
|
||||
hb_font_t* font = NULL;
|
||||
|
||||
#ifdef MACOSX
|
||||
if (jdkFontInfo->aat && jdkFontInfo->nativeFont) {
|
||||
font = _hb_jdk_ct_font_create(hbface, jdkFontInfo);
|
||||
return _hb_jdk_ct_font_create(hbFace, jdkFontInfo);
|
||||
}
|
||||
#endif
|
||||
if (font == NULL) {
|
||||
font = _hb_jdk_font_create(hbface, jdkFontInfo, destroy);
|
||||
}
|
||||
return font;
|
||||
return _hb_jdk_font_create(hbFace, jdkFontInfo, destroy);
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ hb_face_t *
|
||||
hb_jdk_face_create(JDKFontInfo* jdkFontInfo,
|
||||
hb_destroy_func_t destroy);
|
||||
hb_font_t *
|
||||
hb_jdk_font_create(hb_face_t* hbface,
|
||||
hb_jdk_font_create(hb_face_t* hbFace,
|
||||
JDKFontInfo* jdkFontInfo,
|
||||
hb_destroy_func_t destroy);
|
||||
|
||||
|
||||
@@ -344,32 +344,3 @@ Java_sun_font_StrikeCache_getGlyphCacheDescription
|
||||
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, results, nresults, 0);
|
||||
}
|
||||
|
||||
JNIEXPORT TTLayoutTableCache* newLayoutTableCache() {
|
||||
TTLayoutTableCache* ltc = calloc(1, sizeof(TTLayoutTableCache));
|
||||
if (ltc) {
|
||||
int i;
|
||||
for(i=0;i<LAYOUTCACHE_ENTRIES;i++) {
|
||||
ltc->entries[i].len = -1;
|
||||
}
|
||||
ltc->entries[0].tag = GDEF_TAG;
|
||||
ltc->entries[1].tag = GPOS_TAG;
|
||||
ltc->entries[2].tag = GSUB_TAG;
|
||||
ltc->entries[3].tag = HEAD_TAG;
|
||||
ltc->entries[4].tag = KERN_TAG;
|
||||
ltc->entries[5].tag = MORT_TAG;
|
||||
ltc->entries[6].tag = MORX_TAG;
|
||||
}
|
||||
return ltc;
|
||||
}
|
||||
|
||||
JNIEXPORT void freeLayoutTableCache(TTLayoutTableCache* ltc) {
|
||||
if (ltc) {
|
||||
int i;
|
||||
for(i=0;i<LAYOUTCACHE_ENTRIES;i++) {
|
||||
if(ltc->entries[i].ptr) free (ltc->entries[i].ptr);
|
||||
}
|
||||
if (ltc->kernPairs) free(ltc->kernPairs);
|
||||
free(ltc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1794,8 +1794,10 @@ MsgRouting AwtFrame::WmNcCalcSize(BOOL wParam, LPNCCALCSIZE_PARAMS lpncsp, LRESU
|
||||
if (::IsZoomed(GetHWnd())) {
|
||||
rect->top += insets.bottom;
|
||||
// [moklev] Workaround for RIDER-27069, IDEA-211327
|
||||
rect->right += this->ScaleUpX(1);
|
||||
rect->bottom -= 1;
|
||||
if (!this->IsUndecorated()) {
|
||||
rect->right += this->ScaleUpX(1);
|
||||
rect->bottom -= 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// this makes the native caption go uncovered
|
||||
|
||||
81
test/jdk/java/awt/font/TextLayout/FontLayoutStressTest.java
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2000-2019 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8220231
|
||||
* @summary Cache HarfBuzz face object for same font's text layout calls
|
||||
* @comment Test layout operations for the same font performed simultaneously
|
||||
* from multiple threads
|
||||
*/
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.GlyphVector;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class FontLayoutStressTest {
|
||||
private static final int NUMBER_OF_THREADS =
|
||||
Runtime.getRuntime().availableProcessors() * 2;
|
||||
private static final long TIME_TO_RUN_NS = 1_000_000_000; // 1 second
|
||||
private static final Font FONT = new Font(Font.SERIF, Font.PLAIN, 12);
|
||||
private static final FontRenderContext FRC = new FontRenderContext(null,
|
||||
false, false);
|
||||
private static final char[] TEXT = "Lorem ipsum dolor sit amet, ..."
|
||||
.toCharArray();
|
||||
|
||||
private static double doLayout() {
|
||||
GlyphVector gv = FONT.layoutGlyphVector(FRC, TEXT, 0, TEXT.length,
|
||||
Font.LAYOUT_LEFT_TO_RIGHT);
|
||||
return gv.getGlyphPosition(gv.getNumGlyphs()).getX();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
double expectedWidth = doLayout();
|
||||
AtomicReference<Throwable> throwableRef = new AtomicReference<>();
|
||||
CyclicBarrier barrier = new CyclicBarrier(NUMBER_OF_THREADS);
|
||||
List<Thread> threads = new ArrayList<>();
|
||||
for (int i = 0; i < NUMBER_OF_THREADS; i++) {
|
||||
Thread thread = new Thread(() -> {
|
||||
try {
|
||||
barrier.await();
|
||||
long timeToStop = System.nanoTime() + TIME_TO_RUN_NS;
|
||||
while (System.nanoTime() < timeToStop) {
|
||||
double width = doLayout();
|
||||
if (width != expectedWidth) {
|
||||
throw new RuntimeException(
|
||||
"Unexpected layout result");
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throwableRef.set(e);
|
||||
}
|
||||
});
|
||||
threads.add(thread);
|
||||
thread.start();
|
||||
}
|
||||
for (Thread thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
Throwable throwable = throwableRef.get();
|
||||
if (throwable != null) {
|
||||
throw throwable;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -599,7 +599,7 @@ java/awt/Window/AlwaysOnTop/AutoTestOnTop.java
|
||||
java/awt/Window/AlwaysOnTop/TestAlwaysOnTopBeforeShow.java 8169530 macosx-all,windows-all
|
||||
java/awt/Window/GrabSequence/GrabSequence.java 6848409 macosx-all,windows-all,linux-all
|
||||
java/awt/Window/LocationAtScreenCorner/LocationAtScreenCorner.java 8203371 linux-all,solaris-all
|
||||
java/awt/Window/setLocRelativeTo/SetLocationRelativeToTest.java JRE-1173 windows-all
|
||||
java/awt/Window/setLocRelativeTo/SetLocationRelativeToTest.java JRE-1173 windows-all,linux-all
|
||||
java/awt/datatransfer/ConstructFlavoredObjectTest/ConstructFlavoredObjectTest.java 8202860 linux-all
|
||||
java/awt/datatransfer/DataFlavor/DataFlavorRemoteTest.java JRE-898 macosx-all
|
||||
java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java 8080982 generic-all
|
||||
@@ -984,7 +984,7 @@ javax/swing/JPopupMenu/6515446/bug6515446.java
|
||||
javax/swing/JPopupMenu/6580930/bug6580930.java 8196096 windows-all,linux-all,macosx-all
|
||||
javax/swing/JPopupMenu/6583251/bug6583251.java 8213564 linux-all
|
||||
javax/swing/JPopupMenu/6675802/bug6675802.java 8196097 windows-all
|
||||
javax/swing/JPopupMenu/6800513/bug6800513.java 7184956,8080868 macosx-all,windows-all
|
||||
javax/swing/JPopupMenu/6800513/bug6800513.java 7184956,8080868 macosx-all,windows-all,linux-all
|
||||
javax/swing/JPopupMenu/6987844/bug6987844.java 8169956 macosx-all,windows-all
|
||||
javax/swing/JPopupMenu/7156657/bug7156657.java 8171381 macosx-all,windows-all
|
||||
javax/swing/JPopupMenu/8075063/ContextMenuScrollTest.java 8202880 linux-all,windows-all,macosx-all
|
||||
|
||||
@@ -3,6 +3,7 @@ java/awt/Choice/DragMouseOutAndRelease/DragMouseOutAndRelease.java
|
||||
java/awt/Choice/GetSizeTest/GetSizeTest.java nobug macosx-all,windows-all
|
||||
java/awt/Choice/ResizeAutoClosesChoice/ResizeAutoClosesChoice.java nobug windows-all,linux-all
|
||||
java/awt/Component/F10TopToplevel/F10TopToplevel.html nobug linux-all
|
||||
java/awt/Component/PaintAll/PaintAll.java nobug linux-all
|
||||
java/awt/Container/isRemoveNotifyNeeded/JInternalFrameTest.java nobug generic-all
|
||||
java/awt/Dialog/MakeWindowAlwaysOnTop/MakeWindowAlwaysOnTop.java nobug macosx-all,windows-all
|
||||
java/awt/Dialog/NestedDialogs/Modal/NestedModalDialogTest.java nobug macosx-all,windows-all
|
||||
@@ -14,6 +15,8 @@ java/awt/EventDispatchThread/PreserveDispathThread/PreserveDispatchThread.java
|
||||
java/awt/FileDialog/FileDialogMemoryLeak/FileDialogLeakTest.java nobug windows-all
|
||||
java/awt/FileDialog/FilenameFilterTest/FilenameFilterTest.html nobug macosx-all
|
||||
java/awt/FileDialog/MoveToTrashTest.java nobug windows-all
|
||||
java/awt/FileDialog/ModalFocus/FileDialogModalFocusTest.java nobug linux-all,windows-all
|
||||
java/awt/Focus/6981400/Test2.java nobug linux-all
|
||||
java/awt/Focus/AppletInitialFocusTest/AppletInitialFocusTest1.html nobug linux-all,windows-all
|
||||
java/awt/FileDialog/ModalFocus/FileDialogModalFocusTest.java nobug linux-all,windows-all
|
||||
java/awt/Focus/ConsumeNextKeyTypedOnModalShowTest/ConsumeNextKeyTypedOnModalShowTest.java nobug macosx-all,linux-all,windows-all
|
||||
@@ -28,7 +31,9 @@ java/awt/Focus/RemoveAfterRequest/RemoveAfterRequest.java
|
||||
java/awt/Focus/RequestFocusAndHideTest/RequestFocusAndHideTest.java nobug macosx-all
|
||||
java/awt/Focus/RequestFocusByCause/RequestFocusByCauseTest.java nobug linux-all,windows-all reproduced with Adopt, OpenJDK
|
||||
java/awt/Focus/WindowIsFocusableAccessByThreadsTest/WindowIsFocusableAccessByThreadsTest.java nobug macosx-all,windows-all
|
||||
java/awt/Frame/8158918/SetExtendedState.java nobug linux-all
|
||||
java/awt/Frame/FrameLocation/FrameLocation.java nobug linux-all
|
||||
java/awt/Frame/FrameSize/TestFrameSize.java nobug linux-all,mac-osx
|
||||
java/awt/Frame/MaximizedToIconified/MaximizedToIconified.java nobug linux-all,windows-all
|
||||
java/awt/Frame/MiscUndecorated/ActiveAWTWindowTest.java nobug macosx-all,windows-all
|
||||
java/awt/Frame/MiscUndecorated/ActiveSwingWindowTest.java nobug macosx-all,windows-all
|
||||
@@ -71,6 +76,7 @@ java/awt/Mouse/MouseWheelAbsXY/MouseWheelAbsXY.java
|
||||
java/awt/MouseAdapter/MouseAdapterUnitTest/MouseAdapterUnitTest.java nobug macosx-all,windows-all
|
||||
java/awt/MouseInfo/ComponentMousePositionTest.java nobug macosx-all,windows-all
|
||||
java/awt/MouseInfo/JContainerMousePositionTest.java nobug macosx-all,windows-all
|
||||
java/awt/Paint/ComponentIsNotDrawnAfterRemoveAddTest/ComponentIsNotDrawnAfterRemoveAddTest.java nobug linux-all,macosx-all,windows-all
|
||||
java/awt/Paint/ExposeOnEDT.java nobug windows-all
|
||||
java/awt/Paint/ListRepaint.java nobug linux-all (java.lang.NullPointerException reproduced with Adopt)
|
||||
java/awt/PopupMenu/PopupMenuLocation.java nobug macosx-all,linux-all,windows-all
|
||||
|
||||
826
test/jdk/jbu/performance/rendering/RenderPerfTest.java
Normal file
@@ -0,0 +1,826 @@
|
||||
/*
|
||||
* Copyright 2019 JetBrains s.r.o.
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package performance.rendering;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.QuadCurve2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class RenderPerfTest {
|
||||
private final static int N = 1000;
|
||||
private final static float WIDTH = 800;
|
||||
private final static float HEIGHT = 800;
|
||||
private final static float R = 25;
|
||||
private final static int BW = 50;
|
||||
private final static int BH = 50;
|
||||
private final static int COUNT = 300;
|
||||
private final static int DELAY = 10;
|
||||
private final static int RESOLUTION = 5;
|
||||
private final static int COLOR_TOLERANCE = 10;
|
||||
|
||||
|
||||
interface Renderable {
|
||||
void render(Graphics2D g2d);
|
||||
void update();
|
||||
}
|
||||
|
||||
static class Particles {
|
||||
private float[] bx;
|
||||
private float[] by;
|
||||
private float[] vx;
|
||||
private float[] vy;
|
||||
private float r;
|
||||
private int n;
|
||||
|
||||
private float x0;
|
||||
private float y0;
|
||||
private float width;
|
||||
private float height;
|
||||
|
||||
Particles(int n, float r, float x0, float y0, float width, float height) {
|
||||
bx = new float[n];
|
||||
by = new float[n];
|
||||
vx = new float[n];
|
||||
vy = new float[n];
|
||||
this.n = n;
|
||||
this.r = r;
|
||||
this.x0 = x0;
|
||||
this.y0 = y0;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
for (int i = 0; i < n; i++) {
|
||||
bx[i] = (float) (x0 + r + 0.1 + Math.random() * (width - 2 * r - 0.2 - x0));
|
||||
by[i] = (float) (y0 + r + 0.1 + Math.random() * (height - 2 * r - 0.2 - y0));
|
||||
vx[i] = 0.1f * (float) (Math.random() * 2 * r - r);
|
||||
vy[i] = 0.1f * (float) (Math.random() * 2 * r - r);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void render(Graphics2D g2d, ParticleRenderer renderer) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
renderer.render(g2d, i, bx, by, vx, vy);
|
||||
}
|
||||
}
|
||||
|
||||
void update() {
|
||||
for (int i = 0; i < n; i++) {
|
||||
bx[i] += vx[i];
|
||||
if (bx[i] + r > width || bx[i] - r < x0) vx[i] = -vx[i];
|
||||
by[i] += vy[i];
|
||||
if (by[i] + r > height || by[i] - r < y0) vy[i] = -vy[i];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
interface ParticleRenderer {
|
||||
void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy);
|
||||
|
||||
}
|
||||
|
||||
private static void report(String name, double value) {
|
||||
System.err.println("##teamcity[buildStatisticValue key='" + name + "' value='" + value +"']");
|
||||
}
|
||||
|
||||
static class FlatParticleRenderer implements ParticleRenderer {
|
||||
Color[] colors;
|
||||
float r;
|
||||
|
||||
FlatParticleRenderer(int n, float r) {
|
||||
colors = new Color[n];
|
||||
this.r = r;
|
||||
for (int i = 0; i < n; i++) {
|
||||
colors[i] = new Color((float) Math.random(),
|
||||
(float) Math.random(), (float) Math.random());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||
g2d.setColor(colors[id % colors.length]);
|
||||
g2d.fillOval((int)(x[id] - r), (int)(y[id] - r), (int)(2*r), (int)(2*r));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class WhiteTextParticleRenderer implements ParticleRenderer {
|
||||
float r;
|
||||
Object hint;
|
||||
|
||||
WhiteTextParticleRenderer(float r, Object hint) {
|
||||
this.r = r;
|
||||
this.hint = hint;
|
||||
}
|
||||
|
||||
void setPaint(Graphics2D g2d, int id) {
|
||||
g2d.setColor(Color.WHITE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, hint);
|
||||
|
||||
setPaint(g2d, id);
|
||||
g2d.drawString("The quick brown fox jumps over the lazy dog",
|
||||
(int)(x[id] - r), (int)(y[id] - r));
|
||||
g2d.drawString("The quick brown fox jumps over the lazy dog",
|
||||
(int)(x[id] - r), (int)y[id]);
|
||||
g2d.drawString("The quick brown fox jumps over the lazy dog",
|
||||
(int)(x[id] - r), (int)(y[id] + r));
|
||||
}
|
||||
}
|
||||
|
||||
static class TextParticleRenderer extends WhiteTextParticleRenderer {
|
||||
Color[] colors;
|
||||
|
||||
float r;
|
||||
|
||||
TextParticleRenderer(int n, float r, Object hint) {
|
||||
super(r, hint);
|
||||
colors = new Color[n];
|
||||
this.r = r;
|
||||
for (int i = 0; i < n; i++) {
|
||||
colors[i] = new Color((float) Math.random(),
|
||||
(float) Math.random(), (float) Math.random());
|
||||
}
|
||||
}
|
||||
|
||||
void setPaint(Graphics2D g2d, int id) {
|
||||
g2d.setColor(colors[id % colors.length]);
|
||||
}
|
||||
}
|
||||
|
||||
static class FlatOvalRotParticleRenderer extends FlatParticleRenderer {
|
||||
|
||||
|
||||
FlatOvalRotParticleRenderer(int n, float r) {
|
||||
super(n, r);
|
||||
}
|
||||
|
||||
void setPaint(Graphics2D g2d, int id) {
|
||||
g2d.setColor(colors[id % colors.length]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||
setPaint(g2d, id);
|
||||
if (Math.abs(vx[id] + vy[id]) > 0.001) {
|
||||
AffineTransform t = (AffineTransform) g2d.getTransform().clone();
|
||||
double l = vx[id] / Math.sqrt(vx[id] * vx[id] + vy[id] * vy[id]);
|
||||
if (vy[id] < 0) {
|
||||
l = -l;
|
||||
}
|
||||
g2d.translate(x[id], y[id]);
|
||||
g2d.rotate(Math.acos(l));
|
||||
g2d.fillOval(-(int)r, (int)(-0.5*r), (int) (2 * r), (int)r);
|
||||
g2d.setTransform(t);
|
||||
} else {
|
||||
g2d.fillOval((int)(x[id] - r), (int)(y[id] - 0.5*r),
|
||||
(int) (2 * r), (int) r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class LinGradOvalRotParticleRenderer extends FlatOvalRotParticleRenderer {
|
||||
|
||||
|
||||
LinGradOvalRotParticleRenderer(int n, float r) {
|
||||
super(n, r);
|
||||
}
|
||||
|
||||
@Override
|
||||
void setPaint(Graphics2D g2d, int id) {
|
||||
Point2D start = new Point2D.Double(- r, - 0.5*r);
|
||||
Point2D end = new Point2D.Double( 2 * r, r);
|
||||
float[] dist = {0.0f, 1.0f};
|
||||
Color[] cls = {colors[id %colors.length], colors[(colors.length - id) %colors.length]};
|
||||
LinearGradientPaint p =
|
||||
new LinearGradientPaint(start, end, dist, cls);
|
||||
g2d.setPaint(p);
|
||||
}
|
||||
}
|
||||
|
||||
static class FlatBoxParticleRenderer extends FlatParticleRenderer {
|
||||
|
||||
|
||||
FlatBoxParticleRenderer(int n, float r) {
|
||||
super(n, r);
|
||||
}
|
||||
@Override
|
||||
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||
g2d.setColor(colors[id % colors.length]);
|
||||
g2d.fillRect((int)(x[id] - r), (int)(y[id] - r), (int)(2*r), (int)(2*r));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class ImgParticleRenderer extends FlatParticleRenderer {
|
||||
BufferedImage dukeImg;
|
||||
|
||||
ImgParticleRenderer(int n, float r) {
|
||||
super(n, r);
|
||||
String testDataStr = System.getProperty("testdata");
|
||||
assertNotNull("testdata property is not set", testDataStr);
|
||||
|
||||
File testData = new File(testDataStr, "performance" + File.separator + "rendering");
|
||||
assertTrue("Test data dir does not exist", testData.exists());
|
||||
File dukeFile = new File(testData, "duke.png");
|
||||
|
||||
if (!dukeFile.exists()) throw new RuntimeException(dukeFile.toString() + " not found");
|
||||
|
||||
try {
|
||||
dukeImg = ImageIO.read(dukeFile);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||
g2d.setColor(colors[id % colors.length]);
|
||||
g2d.drawImage(dukeImg, (int)(x[id] - r), (int)(y[id] - r), (int)(2*r), (int)(2*r), null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class FlatBoxRotParticleRenderer extends FlatParticleRenderer {
|
||||
|
||||
|
||||
FlatBoxRotParticleRenderer(int n, float r) {
|
||||
super(n, r);
|
||||
}
|
||||
@Override
|
||||
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||
g2d.setColor(colors[id % colors.length]);
|
||||
if (Math.abs(vx[id] + vy[id]) > 0.001) {
|
||||
AffineTransform t = (AffineTransform) g2d.getTransform().clone();
|
||||
double l = vx[id] / Math.sqrt(vx[id] * vx[id] + vy[id] * vy[id]);
|
||||
if (vy[id] < 0) {
|
||||
l = -l;
|
||||
}
|
||||
g2d.translate(x[id], y[id]);
|
||||
g2d.rotate(Math.acos(l));
|
||||
g2d.fillRect(-(int)r, -(int)r, (int) (2 * r), (int) (2 * r));
|
||||
g2d.setTransform(t);
|
||||
} else {
|
||||
g2d.fillRect((int)(x[id] - r), (int)(y[id] - r),
|
||||
(int) (2 * r), (int) (2 * r));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class WiredParticleRenderer extends FlatParticleRenderer {
|
||||
|
||||
|
||||
WiredParticleRenderer(int n, float r) {
|
||||
super(n, r);
|
||||
}
|
||||
@Override
|
||||
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||
g2d.setColor(colors[id % colors.length]);
|
||||
g2d.drawOval((int)(x[id] - r), (int)(y[id] - r), (int)(2*r), (int)(2*r));
|
||||
}
|
||||
|
||||
}
|
||||
static class WiredBoxParticleRenderer extends FlatParticleRenderer {
|
||||
|
||||
WiredBoxParticleRenderer(int n, float r) {
|
||||
super(n, r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||
g2d.setColor(colors[id % colors.length]);
|
||||
g2d.drawRect((int)(x[id] - r), (int)(y[id] - r), (int)(2*r), (int)(2*r));
|
||||
}
|
||||
|
||||
}
|
||||
static class SegParticleRenderer extends FlatParticleRenderer {
|
||||
|
||||
SegParticleRenderer(int n, float r) {
|
||||
super(n, r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||
double v = Math.sqrt(vx[id]*vx[id]+vy[id]*vy[id]);
|
||||
float nvx = (float) (vx[id]/v);
|
||||
float nvy = (float) (vy[id]/v);
|
||||
g2d.setColor(colors[id % colors.length]);
|
||||
g2d.drawLine((int)(x[id] - r*nvx), (int)(y[id] - r*nvy),
|
||||
(int)(x[id] + 2*r*nvx), (int)(y[id] + 2*r*nvy));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static class WiredQuadParticleRenderer extends FlatParticleRenderer {
|
||||
|
||||
WiredQuadParticleRenderer(int n, float r) {
|
||||
super(n, r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||
if (id > 2 && (id % 3) == 0) {
|
||||
g2d.setColor(colors[id % colors.length]);
|
||||
g2d.draw(new QuadCurve2D.Float(x[id-3], y[id-3], x[id-2], y[id-2], x[id-1], y[id-1]));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static class FlatQuadParticleRenderer extends FlatParticleRenderer {
|
||||
|
||||
FlatQuadParticleRenderer(int n, float r) {
|
||||
super(n, r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||
if (id > 2 && (id % 3) == 0) {
|
||||
g2d.setColor(colors[id % colors.length]);
|
||||
g2d.fill(new QuadCurve2D.Float(x[id-3], y[id-3], x[id-2], y[id-2], x[id-1], y[id-1]));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class PerfMeter {
|
||||
|
||||
private int frame = 0;
|
||||
|
||||
private JPanel panel;
|
||||
|
||||
private long time;
|
||||
private double execTime = 0;
|
||||
private Color expColor = Color.RED;
|
||||
AtomicBoolean waiting = new AtomicBoolean(false);
|
||||
|
||||
double exec(final Renderable renderable) throws Exception {
|
||||
final CountDownLatch latch = new CountDownLatch(COUNT);
|
||||
final CountDownLatch latchFrame = new CountDownLatch(1);
|
||||
|
||||
final JFrame f = new JFrame();
|
||||
f.addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosed(WindowEvent e) {
|
||||
latchFrame.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
SwingUtilities.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
panel = new JPanel()
|
||||
{
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
|
||||
super.paintComponent(g);
|
||||
time = System.nanoTime();
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
renderable.render(g2d);
|
||||
g2d.setColor(expColor);
|
||||
g.fillRect(0, 0, BW, BH);
|
||||
}
|
||||
};
|
||||
|
||||
panel.setPreferredSize(new Dimension((int)(WIDTH + BW), (int)(HEIGHT + BH)));
|
||||
panel.setBackground(Color.BLACK);
|
||||
f.add(panel);
|
||||
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
||||
f.pack();
|
||||
f.setVisible(true);
|
||||
}
|
||||
});
|
||||
Robot robot = new Robot();
|
||||
|
||||
Timer timer = new Timer(DELAY, e -> {
|
||||
|
||||
if (waiting.compareAndSet(false, true)) {
|
||||
Color c = robot.getPixelColor(panel.getTopLevelAncestor().getX() + 25,
|
||||
panel.getTopLevelAncestor().getY() + 25);
|
||||
if (isAlmostEqual(c, Color.BLUE)) {
|
||||
expColor = Color.RED;
|
||||
} else {
|
||||
expColor = Color.BLUE;
|
||||
}
|
||||
renderable.update();
|
||||
panel.getParent().repaint();
|
||||
|
||||
} else {
|
||||
while (!isAlmostEqual(
|
||||
robot.getPixelColor(
|
||||
panel.getTopLevelAncestor().getX() + BW / 2,
|
||||
panel.getTopLevelAncestor().getY() + BH / 2),
|
||||
expColor))
|
||||
{
|
||||
try {
|
||||
Thread.sleep(RESOLUTION);
|
||||
} catch (InterruptedException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
time = System.nanoTime() - time;
|
||||
execTime += time;
|
||||
frame++;
|
||||
waiting.set(false);
|
||||
}
|
||||
|
||||
latch.countDown();
|
||||
});
|
||||
timer.start();
|
||||
latch.await();
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
timer.stop();
|
||||
f.setVisible(false);
|
||||
f.dispose();
|
||||
});
|
||||
|
||||
latchFrame.await();
|
||||
return 1e9/(execTime / frame);
|
||||
}
|
||||
|
||||
private boolean isAlmostEqual(Color c1, Color c2) {
|
||||
return Math.abs(c1.getRed() - c2.getRed()) < COLOR_TOLERANCE ||
|
||||
Math.abs(c1.getGreen() - c2.getGreen()) < COLOR_TOLERANCE ||
|
||||
Math.abs(c1.getBlue() - c2.getBlue()) < COLOR_TOLERANCE;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static final Particles balls = new Particles(N, R, BW, BH, WIDTH, HEIGHT);
|
||||
private static final ParticleRenderer flatRenderer = new FlatParticleRenderer(N, R);
|
||||
private static final ParticleRenderer flatOvalRotRenderer = new FlatOvalRotParticleRenderer(N, R);
|
||||
private static final ParticleRenderer flatBoxRenderer = new FlatBoxParticleRenderer(N, R);
|
||||
private static final ParticleRenderer flatBoxRotRenderer = new FlatBoxRotParticleRenderer(N, R);
|
||||
private static final ParticleRenderer linGradOvalRotRenderer = new LinGradOvalRotParticleRenderer(N, R);
|
||||
private static final ParticleRenderer wiredRenderer = new WiredParticleRenderer(N, R);
|
||||
private static final ParticleRenderer wiredBoxRenderer = new WiredBoxParticleRenderer(N, R);
|
||||
private static final ParticleRenderer segRenderer = new SegParticleRenderer(N, R);
|
||||
private static final ParticleRenderer flatQuadRenderer = new FlatQuadParticleRenderer(N, R);
|
||||
private static final ParticleRenderer wiredQuadRenderer = new WiredQuadParticleRenderer(N, R);
|
||||
private static final ParticleRenderer imgRenderer = new ImgParticleRenderer(N, R);
|
||||
private static final ParticleRenderer textRendererNoAA =
|
||||
new TextParticleRenderer(N, R, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
|
||||
private static final ParticleRenderer textRendererLCD =
|
||||
new TextParticleRenderer(N, R, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
|
||||
private static final ParticleRenderer textRendererGray =
|
||||
new TextParticleRenderer(N, R, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
|
||||
private static final ParticleRenderer whiteTextRendererNoAA =
|
||||
new WhiteTextParticleRenderer(R, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
|
||||
private static final ParticleRenderer whiteTextRendererLCD =
|
||||
new WhiteTextParticleRenderer(R, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
|
||||
private static final ParticleRenderer whiteTextRendererGray =
|
||||
new WhiteTextParticleRenderer(R, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
|
||||
|
||||
@Test
|
||||
public void testFlatBubbles() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, flatRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
report("FlatOval", fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlatBoxBubbles() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, flatBoxRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
report("FlatBox", fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImgBubbles() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, imgRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
report("Image", fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlatBoxRotBubbles() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, flatBoxRotRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
report("RotatedBox", fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlatOvalRotBubbles() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, flatOvalRotRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
report("RotatedOval", fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLinGradOvalRotBubbles() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, linGradOvalRotRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
report("LinGradRotatedOval", fps);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testWiredBubbles() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, wiredRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
report("WiredOval", fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWiredBoxBubbles() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, wiredBoxRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
report("WiredBox", fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLines() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, segRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
report("Lines", fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlatQuad() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, flatQuadRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
report("FlatQuad", fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWiredQuad() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, wiredQuadRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
report("WiredQuad", fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTextBubblesNoAA() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, textRendererNoAA);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
report("TextNoAA", fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTextBubblesLCD() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, textRendererLCD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
report("TextLCD", fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTextBubblesGray() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, textRendererGray);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
report("TextGray", fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWhiteTextBubblesNoAA() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, whiteTextRendererNoAA);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
report("WhiteTextNoAA", fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWhiteTextBubblesLCD() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, whiteTextRendererLCD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
report("WhiteTextLCD", fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWhiteTextBubblesGray() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, whiteTextRendererGray);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
report("WhiteTextGray", fps);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
package quality.text;
|
||||
|
||||
import org.junit.Test;
|
||||
import quality.util.RenderUtil;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.Raster;
|
||||
import java.io.File;
|
||||
|
||||
@@ -40,7 +38,7 @@ public class DroidFontTest {
|
||||
|
||||
String[] testDataVariant = {
|
||||
"osx_hardware_rendering", "osx_software_rendering", "osx_sierra_rendering",
|
||||
"linux_rendering"};
|
||||
"osx_mojave_rendering", "linux_rendering"};
|
||||
|
||||
String testDataStr = System.getProperty("testdata");
|
||||
assertNotNull("testdata property is not set", testDataStr);
|
||||
@@ -70,7 +68,7 @@ public class DroidFontTest {
|
||||
(int) bnd.getWidth(), (int) bnd.getHeight());
|
||||
|
||||
String gfName = name.toLowerCase().replace(" ", "") +
|
||||
Integer.toString(style) + "_" + Integer.toString(size) + ".png";
|
||||
style + "_" + size + ".png";
|
||||
|
||||
if (System.getProperty("gentestdata") == null) {
|
||||
boolean failed = true;
|
||||
@@ -98,7 +96,7 @@ public class DroidFontTest {
|
||||
for (int j = 0; j < gRaster.getHeight(); j++) {
|
||||
gRaster.getPixel(i, j, gArr);
|
||||
rRaster.getPixel(i, j, rArr);
|
||||
assertTrue(gArr.length == rArr.length);
|
||||
assertEquals(gArr.length, rArr.length);
|
||||
for (int k = 0; k < gArr.length; k++) {
|
||||
if (gArr[k] != rArr[k]) {
|
||||
failureReason.append(variant).append(" : Different pixels found ").append("at (").append(i).append(",").append(j).append(")");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017 JetBrains s.r.o.
|
||||
* Copyright 2019 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,81 +16,25 @@
|
||||
|
||||
package quality.util;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import quality.util.osx.Foundation;
|
||||
import quality.util.osx.FoundationLibrary;
|
||||
import quality.util.osx.ID;
|
||||
import quality.util.osx.MacUtil;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorConvertOp;
|
||||
import java.awt.image.Raster;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class RenderUtil {
|
||||
|
||||
private static BufferedImage captureScreen(Window belowWindow, Rectangle rect) {
|
||||
ID pool = Foundation.invoke("NSAutoreleasePool", "new");
|
||||
try {
|
||||
ID windowId = belowWindow != null ? MacUtil.findWindowFromJavaWindow(belowWindow) : null;
|
||||
Foundation.NSRect nsRect = new Foundation.NSRect(rect.x, rect.y, rect.width, rect.height);
|
||||
ID cgWindowId = windowId != null ? Foundation.invoke(windowId, "windowNumber") : ID.NIL;
|
||||
int windowListOptions = cgWindowId != null
|
||||
? FoundationLibrary.kCGWindowListOptionIncludingWindow
|
||||
: FoundationLibrary.kCGWindowListOptionAll;
|
||||
int windowImageOptions = FoundationLibrary.kCGWindowImageBestResolution |
|
||||
FoundationLibrary.kCGWindowImageShouldBeOpaque;
|
||||
ID cgImageRef = Foundation.cgWindowListCreateImage(
|
||||
nsRect, windowListOptions, cgWindowId, windowImageOptions);
|
||||
|
||||
ID bitmapRep = Foundation.invoke(
|
||||
Foundation.invoke("NSBitmapImageRep", "alloc"),
|
||||
"initWithCGImage:", cgImageRef);
|
||||
ID nsImage = Foundation.invoke(
|
||||
Foundation.invoke("NSImage", "alloc"),
|
||||
"init");
|
||||
Foundation.invoke(nsImage, "addRepresentation:", bitmapRep);
|
||||
ID data = Foundation.invoke(nsImage, "TIFFRepresentation");
|
||||
ID bytes = Foundation.invoke(data, "bytes");
|
||||
ID length = Foundation.invoke(data, "length");
|
||||
Pointer ptr = new Pointer(bytes.longValue());
|
||||
ByteBuffer byteBuffer = ptr.getByteBuffer(0, length.longValue());
|
||||
Foundation.invoke(nsImage, "release");
|
||||
byte[] b = new byte[byteBuffer.remaining()];
|
||||
byteBuffer.get(b);
|
||||
|
||||
BufferedImage result = ImageIO.read(new ByteArrayInputStream(b));
|
||||
if (result != null) {
|
||||
ColorSpace ics = ColorSpace.getInstance(ColorSpace.CS_sRGB);
|
||||
ColorConvertOp cco = new ColorConvertOp(ics, null);
|
||||
return cco.filter(result, null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
return null;
|
||||
}
|
||||
finally {
|
||||
Foundation.invoke(pool, "release");
|
||||
}
|
||||
}
|
||||
private final static int TOLERANCE = 1;
|
||||
|
||||
public static BufferedImage capture(int width, int height, Consumer<Graphics2D> painter)
|
||||
throws Exception
|
||||
{
|
||||
JFrame[] f = new JFrame[1];
|
||||
Point[] p = new Point[1];
|
||||
double[] scale = new double[2];
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
f[0] = new JFrame();
|
||||
|
||||
@@ -99,22 +43,26 @@ public class RenderUtil {
|
||||
f[0].add(c);
|
||||
c.setSize(width + 10, height + 10);
|
||||
f[0].setSize(width + 100, height + 100); // giving some space
|
||||
// for frame border effects,
|
||||
// e.g. rounded frame
|
||||
// for frame border effects,
|
||||
// e.g. rounded frame
|
||||
c.setLocation(50, 50);
|
||||
f[0].setVisible(true);
|
||||
p[0]= c.getLocationOnScreen();
|
||||
scale[0] = f[0].getGraphicsConfiguration().getDefaultTransform().getScaleX();
|
||||
scale[1] = f[0].getGraphicsConfiguration().getDefaultTransform().getScaleY();
|
||||
});
|
||||
|
||||
Rectangle screenRect;
|
||||
Robot r = new Robot();
|
||||
while (!Color.black.equals(r.getPixelColor(p[0].x, p[0].y))) {
|
||||
while (!Color.black.equals(r.getPixelColor(p[0].x+1, p[0].y))) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
screenRect = new Rectangle(p[0].x + 5, p[0].y + 5, width, height);
|
||||
screenRect = new Rectangle(
|
||||
p[0].x + 5,
|
||||
p[0].y + 5,
|
||||
(int)((width - 20) * scale[0]), (int)((height - 30) * scale[1]));
|
||||
|
||||
BufferedImage result = SystemUtils.IS_OS_MAC ?
|
||||
captureScreen(f[0], screenRect) : r.createScreenCapture(screenRect);
|
||||
BufferedImage result = r.createScreenCapture(screenRect);
|
||||
SwingUtilities.invokeAndWait(f[0]::dispose);
|
||||
return result;
|
||||
}
|
||||
@@ -129,14 +77,16 @@ public class RenderUtil {
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
g.translate(5, 5);
|
||||
Shape savedClip = g.getClip();
|
||||
g.clipRect(0, 0, getWidth() - 20, getHeight() - 20);
|
||||
g.translate(5, 5);
|
||||
painter.accept((Graphics2D)g);
|
||||
g.translate(-5, -5);
|
||||
g.setClip(savedClip);
|
||||
g.setColor(Color.black);
|
||||
((Graphics2D) g).setStroke(new BasicStroke(10));
|
||||
g.drawRect(-5, -5, getWidth() - 5, getHeight() - 5);
|
||||
g.fillRect(0, 0, getWidth() + 10, 5);
|
||||
g.fillRect(0, getHeight()-5, getWidth() + 10, 5);
|
||||
g.fillRect(getWidth() - 10, -10, getWidth() + 5, getHeight() + 5);
|
||||
g.fillRect(-5, -10, 10, getHeight() + 5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +95,7 @@ public class RenderUtil {
|
||||
|
||||
String[] testDataVariant = {
|
||||
"osx_hardware_rendering", "osx_software_rendering",
|
||||
"osx_sierra_rendering", "osx_lowres_rendering",
|
||||
"osx_sierra_rendering", "osx_mojave_rendering", "osx_lowres_rendering",
|
||||
"linux_rendering", "windows_rendering"};
|
||||
|
||||
String testDataStr = System.getProperty("testdata");
|
||||
@@ -181,11 +131,12 @@ public class RenderUtil {
|
||||
for (int j = 0; j < gRaster.getHeight(); j++) {
|
||||
gRaster.getPixel(i, j, gArr);
|
||||
rRaster.getPixel(i, j, rArr);
|
||||
assertTrue(gArr.length == rArr.length);
|
||||
for (int k = 0; k < gArr.length; k++) {
|
||||
if (gArr[k] != rArr[k]) {
|
||||
failureReason.append(variant).append(" : Different pixels found ").
|
||||
append("at (").append(i).append(",").append(j).append(")");
|
||||
int diff = Math.abs(gArr[k] - rArr[k]);
|
||||
if (diff > TOLERANCE) {
|
||||
failureReason.append(variant).append(" : Different pixels found (").
|
||||
append("c[").append(k).append("]=").append(diff).
|
||||
append(") at (").append(i).append(",").append(j).append(")");
|
||||
failed = true;
|
||||
break scan;
|
||||
}
|
||||
|
||||
BIN
test/jdk/jbu/testdata/performance/rendering/duke.png
vendored
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 3.3 KiB |
BIN
test/jdk/jbu/testdata/quality/text/osx_mojave_rendering/bndtext.png
vendored
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
test/jdk/jbu/testdata/quality/text/osx_mojave_rendering/cnclcd.png
vendored
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
test/jdk/jbu/testdata/quality/text/osx_mojave_rendering/droidsans0_20.png
vendored
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
test/jdk/jbu/testdata/quality/text/osx_mojave_rendering/droidsans1_20.png
vendored
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
test/jdk/jbu/testdata/quality/text/osx_mojave_rendering/droidsansmono0_20.png
vendored
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
test/jdk/jbu/testdata/quality/text/osx_mojave_rendering/droidsansmonodotted0_20.png
vendored
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
test/jdk/jbu/testdata/quality/text/osx_mojave_rendering/droidsansmonoslashed0_20.png
vendored
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
test/jdk/jbu/testdata/quality/text/osx_mojave_rendering/droidserif0_20.png
vendored
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
test/jdk/jbu/testdata/quality/text/osx_mojave_rendering/droidserif1_20.png
vendored
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
test/jdk/jbu/testdata/quality/text/osx_mojave_rendering/droidserif2_20.png
vendored
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
test/jdk/jbu/testdata/quality/text/osx_mojave_rendering/droidserif3_20.png
vendored
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
test/jdk/jbu/testdata/quality/text/osx_mojave_rendering/lcdgray.png
vendored
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
test/jdk/jbu/testdata/quality/text/windows_rendering/droidsans0_20.png
vendored
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
test/jdk/jbu/testdata/quality/text/windows_rendering/droidsans1_20.png
vendored
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
test/jdk/jbu/testdata/quality/text/windows_rendering/droidsansmono0_20.png
vendored
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
test/jdk/jbu/testdata/quality/text/windows_rendering/droidsansmonodotted0_20.png
vendored
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
test/jdk/jbu/testdata/quality/text/windows_rendering/droidsansmonoslashed0_20.png
vendored
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
test/jdk/jbu/testdata/quality/text/windows_rendering/droidserif0_20.png
vendored
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
test/jdk/jbu/testdata/quality/text/windows_rendering/droidserif1_20.png
vendored
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
test/jdk/jbu/testdata/quality/text/windows_rendering/droidserif2_20.png
vendored
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
test/jdk/jbu/testdata/quality/text/windows_rendering/droidserif3_20.png
vendored
Normal file
|
After Width: | Height: | Size: 3.3 KiB |