diff --git a/.hgtags b/.hgtags index e12216bcd6b75ac0a18a78869c93a165927f6d69..90b30b8f1df3ee985d0820096b5c19c42d77b918 100644 --- a/.hgtags +++ b/.hgtags @@ -98,3 +98,5 @@ ecab7eefb8f2326fd90fb632f47f1b6f81e928f8 jdk7-b119 a661d8587b5d8986aacae086f5df66af9e1a96b1 jdk7-b121 ac311eb325bfc763698219252bf3cee9e091f3af jdk7-b122 869190935eedee7750d955019ab2a1b80f0a13a8 jdk7-b123 +1c72adc9d5f331cb882cf5354ba0dcb118a60b23 jdk7-b124 +0a56bdd709d01c1663047e55201d19152ffd3d69 jdk7-b125 diff --git a/make/sun/Makefile b/make/sun/Makefile index be97a77510593e1d24fee776199904f1682d5a0b..0e8bb3e4220b96707920f4fcca3b33cfba39cbea 100644 --- a/make/sun/Makefile +++ b/make/sun/Makefile @@ -42,7 +42,15 @@ ifneq ($(PLATFORM), windows) ifndef OPENJDK ifeq ($(PLATFORM), solaris) ifneq ($(ARCH), amd64) - DGA_SUBDIR = jdga + # Solaris 11 does not have support for new compilation of DGA code. + OS_VERSION = $(shell uname -r) + OS_MAJOR_VERSION := $(call MajorVersion,$(OS_VERSION)) + OS_MINOR_VERSION := $(call MinorVersion,$(OS_VERSION)) + ifeq ($(shell $(EXPR) $(OS_MAJOR_VERSION) == 5), 1) + ifeq ($(shell $(EXPR) $(OS_MINOR_VERSION) \<= 10), 1) + DGA_SUBDIR = jdga + endif + endif endif endif endif diff --git a/make/sun/awt/Makefile b/make/sun/awt/Makefile index c7961dc556a19e8fe2e5e74891ea60a6eb7a08b0..87fd56b6dad73a6ff853031bf4f9da94a3fcfb59 100644 --- a/make/sun/awt/Makefile +++ b/make/sun/awt/Makefile @@ -175,6 +175,10 @@ endif include $(BUILDDIR)/common/Mapfile-vers.gmk include $(BUILDDIR)/common/Library.gmk +COMPILEFONTCONFIG_FLAGS = +ifdef ALT_COMPILEFONTCONFIG_FLAGS + COMPILEFONTCONFIG_FLAGS += $(ALT_COMPILEFONTCONFIG_FLAGS) +endif build: fontconfigs @@ -406,7 +410,7 @@ COMPILEFONTCONFIG_JARFILE = $(BUILDTOOLJARDIR)/compilefontconfig.jar $(LIBDIR)/%.bfc: $(FONTCONFIGS_SRC)/$(FONTCONFIGS_SRC_PREFIX)%.properties \ $(COMPILEFONTCONFIG_JARFILE) $(prep-target) - $(BOOT_JAVA_CMD) -jar $(COMPILEFONTCONFIG_JARFILE) $< $@ + $(BOOT_JAVA_CMD) -jar $(COMPILEFONTCONFIG_JARFILE) $(COMPILEFONTCONFIG_FLAGS) $< $@ $(install-module-file) $(call chmod-file, 444) @$(java-vm-cleanup) diff --git a/make/sun/awt/make.depend b/make/sun/awt/make.depend index 6a6186585c685f10b8be39018a0cff3f84908850..02b3b1672d176c5536f615a766cd759a260c31ba 100644 --- a/make/sun/awt/make.depend +++ b/make/sun/awt/make.depend @@ -224,7 +224,7 @@ $(OBJDIR)/DllUtil.obj:: ../../../src/windows/native/sun/windows/DllUtil.h $(OBJDIR)/DrawLine.obj:: $(CLASSHDRDIR)/java_awt_AlphaComposite.h $(CLASSHDRDIR)/sun_java2d_loops_DrawLine.h ../../../src/share/javavm/export/jni.h ../../../src/share/native/common/gdefs.h ../../../src/share/native/sun/java2d/loops/AlphaMath.h ../../../src/share/native/sun/java2d/loops/GlyphImageRef.h ../../../src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h ../../../src/share/native/sun/java2d/loops/LineUtils.h ../../../src/share/native/sun/java2d/pipe/SpanIterator.h ../../../src/share/native/sun/java2d/SurfaceData.h ../../../src/windows/javavm/export/jni_md.h ../../../src/windows/native/common/gdefs_md.h ../../../src/windows/native/sun/java2d/j2d_md.h -$(OBJDIR)/DrawParallelogram.obj:: $(CLASSHDRDIR)/java_awt_AlphaComposite.h $(CLASSHDRDIR)/sun_java2d_loops_DrawParallelogram.h $(CLASSHDRDIR)/sun_java2d_loops_FillParallelogram.h ../../../src/share/javavm/export/classfile_constants.h ../../../src/share/javavm/export/jni.h ../../../src/share/javavm/export/jvm.h ../../../src/share/native/common/gdefs.h ../../../src/share/native/common/jlong.h ../../../src/share/native/common/jni_util.h ../../../src/share/native/sun/awt/debug/debug_assert.h ../../../src/share/native/sun/awt/debug/debug_mem.h ../../../src/share/native/sun/awt/debug/debug_trace.h ../../../src/share/native/sun/awt/debug/debug_util.h ../../../src/share/native/sun/java2d/loops/AlphaMath.h ../../../src/share/native/sun/java2d/loops/GlyphImageRef.h ../../../src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h ../../../src/share/native/sun/java2d/loops/LineUtils.h ../../../src/share/native/sun/java2d/loops/LoopMacros.h ../../../src/share/native/sun/java2d/pipe/SpanIterator.h ../../../src/share/native/sun/java2d/SurfaceData.h ../../../src/share/native/sun/java2d/Trace.h ../../../src/windows/javavm/export/jni_md.h ../../../src/windows/javavm/export/jvm_md.h ../../../src/windows/native/common/gdefs_md.h ../../../src/windows/native/common/jlong_md.h ../../../src/windows/native/sun/java2d/j2d_md.h +$(OBJDIR)/DrawParallelogram.obj:: $(CLASSHDRDIR)/java_awt_AlphaComposite.h $(CLASSHDRDIR)/sun_java2d_loops_DrawParallelogram.h ../../../src/share/javavm/export/classfile_constants.h ../../../src/share/javavm/export/jni.h ../../../src/share/javavm/export/jvm.h ../../../src/share/native/common/gdefs.h ../../../src/share/native/common/jlong.h ../../../src/share/native/common/jni_util.h ../../../src/share/native/sun/awt/debug/debug_assert.h ../../../src/share/native/sun/awt/debug/debug_mem.h ../../../src/share/native/sun/awt/debug/debug_trace.h ../../../src/share/native/sun/awt/debug/debug_util.h ../../../src/share/native/sun/java2d/loops/AlphaMath.h ../../../src/share/native/sun/java2d/loops/GlyphImageRef.h ../../../src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h ../../../src/share/native/sun/java2d/loops/LineUtils.h ../../../src/share/native/sun/java2d/loops/ParallelogramUtils.h ../../../src/share/native/sun/java2d/pipe/SpanIterator.h ../../../src/share/native/sun/java2d/SurfaceData.h ../../../src/share/native/sun/java2d/Trace.h ../../../src/windows/javavm/export/jni_md.h ../../../src/windows/javavm/export/jvm_md.h ../../../src/windows/native/common/gdefs_md.h ../../../src/windows/native/common/jlong_md.h ../../../src/windows/native/sun/java2d/j2d_md.h $(OBJDIR)/DrawPath.obj:: $(CLASSHDRDIR)/java_awt_AlphaComposite.h $(CLASSHDRDIR)/sun_java2d_loops_DrawPath.h ../../../src/share/javavm/export/jni.h ../../../src/share/native/common/gdefs.h ../../../src/share/native/common/jlong.h ../../../src/share/native/common/jni_util.h ../../../src/share/native/sun/java2d/loops/AlphaMath.h ../../../src/share/native/sun/java2d/loops/DrawPath.h ../../../src/share/native/sun/java2d/loops/GlyphImageRef.h ../../../src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h ../../../src/share/native/sun/java2d/loops/LineUtils.h ../../../src/share/native/sun/java2d/loops/ProcessPath.h ../../../src/share/native/sun/java2d/pipe/SpanIterator.h ../../../src/share/native/sun/java2d/SurfaceData.h ../../../src/windows/javavm/export/jni_md.h ../../../src/windows/native/common/gdefs_md.h ../../../src/windows/native/common/jlong_md.h ../../../src/windows/native/sun/java2d/j2d_md.h @@ -232,7 +232,7 @@ $(OBJDIR)/DrawPolygons.obj:: $(CLASSHDRDIR)/java_awt_AlphaComposite.h $(CLASSHDR $(OBJDIR)/DrawRect.obj:: $(CLASSHDRDIR)/java_awt_AlphaComposite.h $(CLASSHDRDIR)/sun_java2d_loops_DrawRect.h ../../../src/share/javavm/export/jni.h ../../../src/share/native/common/gdefs.h ../../../src/share/native/sun/java2d/loops/AlphaMath.h ../../../src/share/native/sun/java2d/loops/GlyphImageRef.h ../../../src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h ../../../src/share/native/sun/java2d/loops/LineUtils.h ../../../src/share/native/sun/java2d/pipe/SpanIterator.h ../../../src/share/native/sun/java2d/SurfaceData.h ../../../src/windows/javavm/export/jni_md.h ../../../src/windows/native/common/gdefs_md.h ../../../src/windows/native/sun/java2d/j2d_md.h -$(OBJDIR)/FillParallelogram.obj:: $(CLASSHDRDIR)/java_awt_AlphaComposite.h $(CLASSHDRDIR)/sun_java2d_loops_FillParallelogram.h ../../../src/share/javavm/export/jni.h ../../../src/share/native/common/gdefs.h ../../../src/share/native/sun/java2d/loops/AlphaMath.h ../../../src/share/native/sun/java2d/loops/GlyphImageRef.h ../../../src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h ../../../src/share/native/sun/java2d/pipe/SpanIterator.h ../../../src/share/native/sun/java2d/SurfaceData.h ../../../src/windows/javavm/export/jni_md.h ../../../src/windows/native/common/gdefs_md.h ../../../src/windows/native/sun/java2d/j2d_md.h +$(OBJDIR)/FillParallelogram.obj:: $(CLASSHDRDIR)/java_awt_AlphaComposite.h $(CLASSHDRDIR)/sun_java2d_loops_FillParallelogram.h ../../../src/share/javavm/export/jni.h ../../../src/share/native/common/gdefs.h ../../../src/share/native/sun/java2d/loops/AlphaMath.h ../../../src/share/native/sun/java2d/loops/GlyphImageRef.h ../../../src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h ../../../src/share/native/sun/java2d/loops/ParallelogramUtils.h ../../../src/share/native/sun/java2d/pipe/SpanIterator.h ../../../src/share/native/sun/java2d/SurfaceData.h ../../../src/windows/javavm/export/jni_md.h ../../../src/windows/native/common/gdefs_md.h ../../../src/windows/native/sun/java2d/j2d_md.h $(OBJDIR)/FillPath.obj:: $(CLASSHDRDIR)/java_awt_AlphaComposite.h $(CLASSHDRDIR)/sun_java2d_loops_FillPath.h ../../../src/share/javavm/export/jni.h ../../../src/share/native/common/gdefs.h ../../../src/share/native/common/jlong.h ../../../src/share/native/common/jni_util.h ../../../src/share/native/sun/java2d/loops/AlphaMath.h ../../../src/share/native/sun/java2d/loops/DrawPath.h ../../../src/share/native/sun/java2d/loops/GlyphImageRef.h ../../../src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h ../../../src/share/native/sun/java2d/loops/LineUtils.h ../../../src/share/native/sun/java2d/loops/ProcessPath.h ../../../src/share/native/sun/java2d/pipe/SpanIterator.h ../../../src/share/native/sun/java2d/SurfaceData.h ../../../src/windows/javavm/export/jni_md.h ../../../src/windows/native/common/gdefs_md.h ../../../src/windows/native/common/jlong_md.h ../../../src/windows/native/sun/java2d/j2d_md.h @@ -284,7 +284,7 @@ $(OBJDIR)/IntRgbx.obj:: $(CLASSHDRDIR)/java_awt_AlphaComposite.h ../../../src/sh $(OBJDIR)/MaskBlit.obj:: $(CLASSHDRDIR)/java_awt_AlphaComposite.h $(CLASSHDRDIR)/sun_java2d_loops_MaskBlit.h ../../../src/share/javavm/export/jni.h ../../../src/share/native/common/gdefs.h ../../../src/share/native/sun/java2d/loops/AlphaMath.h ../../../src/share/native/sun/java2d/loops/GlyphImageRef.h ../../../src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h ../../../src/share/native/sun/java2d/pipe/Region.h ../../../src/share/native/sun/java2d/pipe/SpanIterator.h ../../../src/share/native/sun/java2d/SurfaceData.h ../../../src/windows/javavm/export/jni_md.h ../../../src/windows/native/common/gdefs_md.h ../../../src/windows/native/sun/awt/utility/rect.h ../../../src/windows/native/sun/java2d/j2d_md.h -$(OBJDIR)/MaskFill.obj:: $(CLASSHDRDIR)/java_awt_AlphaComposite.h $(CLASSHDRDIR)/sun_java2d_loops_MaskFill.h ../../../src/share/javavm/export/jni.h ../../../src/share/native/common/gdefs.h ../../../src/share/native/sun/java2d/loops/AlphaMath.h ../../../src/share/native/sun/java2d/loops/GlyphImageRef.h ../../../src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h ../../../src/share/native/sun/java2d/pipe/SpanIterator.h ../../../src/share/native/sun/java2d/SurfaceData.h ../../../src/windows/javavm/export/jni_md.h ../../../src/windows/native/common/gdefs_md.h ../../../src/windows/native/sun/java2d/j2d_md.h +$(OBJDIR)/MaskFill.obj:: $(CLASSHDRDIR)/java_awt_AlphaComposite.h $(CLASSHDRDIR)/sun_java2d_loops_MaskFill.h ../../../src/share/javavm/export/jni.h ../../../src/share/native/common/gdefs.h ../../../src/share/native/sun/java2d/loops/AlphaMath.h ../../../src/share/native/sun/java2d/loops/GlyphImageRef.h ../../../src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h ../../../src/share/native/sun/java2d/loops/ParallelogramUtils.h ../../../src/share/native/sun/java2d/pipe/SpanIterator.h ../../../src/share/native/sun/java2d/SurfaceData.h ../../../src/windows/javavm/export/jni_md.h ../../../src/windows/native/common/gdefs_md.h ../../../src/windows/native/sun/java2d/j2d_md.h $(OBJDIR)/MouseInfo.obj:: $(CLASSHDRDIR)/java_awt_AWTEvent.h $(CLASSHDRDIR)/java_awt_Component.h $(CLASSHDRDIR)/java_awt_Dimension.h $(CLASSHDRDIR)/java_awt_Event.h $(CLASSHDRDIR)/java_awt_event_FocusEvent.h $(CLASSHDRDIR)/java_awt_event_KeyEvent.h $(CLASSHDRDIR)/java_awt_event_MouseEvent.h $(CLASSHDRDIR)/java_awt_event_WindowEvent.h $(CLASSHDRDIR)/java_awt_Font.h $(CLASSHDRDIR)/sun_awt_FontDescriptor.h $(CLASSHDRDIR)/sun_awt_PlatformFont.h $(CLASSHDRDIR)/sun_awt_windows_WComponentPeer.h $(CLASSHDRDIR)/sun_awt_windows_WFontMetrics.h $(CLASSHDRDIR)/sun_awt_windows_WObjectPeer.h $(CLASSHDRDIR)/sun_awt_windows_WToolkit.h ../../../src/share/javavm/export/classfile_constants.h ../../../src/share/javavm/export/jni.h ../../../src/share/javavm/export/jvm.h ../../../src/share/native/common/jlong.h ../../../src/share/native/common/jni_util.h ../../../src/share/native/sun/awt/debug/debug_assert.h ../../../src/share/native/sun/awt/debug/debug_mem.h ../../../src/share/native/sun/awt/debug/debug_trace.h ../../../src/share/native/sun/awt/debug/debug_util.h ../../../src/share/native/sun/awt/image/cvutils/img_globals.h ../../../src/share/native/sun/java2d/SurfaceData.h ../../../src/share/native/sun/java2d/Trace.h ../../../src/windows/javavm/export/jni_md.h ../../../src/windows/javavm/export/jvm_md.h ../../../src/windows/native/common/jlong_md.h ../../../src/windows/native/sun/java2d/windows/GDIWindowSurfaceData.h ../../../src/windows/native/sun/windows/alloc.h ../../../src/windows/native/sun/windows/awt.h ../../../src/windows/native/sun/windows/awtmsg.h ../../../src/windows/native/sun/windows/awt_Brush.h ../../../src/windows/native/sun/windows/awt_Component.h ../../../src/windows/native/sun/windows/awt_Debug.h ../../../src/windows/native/sun/windows/awt_Font.h ../../../src/windows/native/sun/windows/awt_GDIObject.h ../../../src/windows/native/sun/windows/awt_Object.h ../../../src/windows/native/sun/windows/awt_Palette.h ../../../src/windows/native/sun/windows/awt_Pen.h ../../../src/windows/native/sun/windows/awt_Toolkit.h ../../../src/windows/native/sun/windows/awt_Win32GraphicsDevice.h ../../../src/windows/native/sun/windows/colordata.h ../../../src/windows/native/sun/windows/Devices.h ../../../src/windows/native/sun/windows/GDIHashtable.h ../../../src/windows/native/sun/windows/Hashtable.h ../../../src/windows/native/sun/windows/ObjectList.h ../../../src/windows/native/sun/windows/stdhdrs.h diff --git a/make/sun/awt/mapfile-vers b/make/sun/awt/mapfile-vers index f967ecc8aeb559f2c295271db4d89faaf855a0a2..5c6cfea808bb560247ecb0239c772bfa2e307573 100644 --- a/make/sun/awt/mapfile-vers +++ b/make/sun/awt/mapfile-vers @@ -118,6 +118,8 @@ SUNWprivate_1.1 { Java_sun_java2d_loops_GraphicsPrimitiveMgr_registerNativeLoops; Java_sun_java2d_loops_MaskBlit_MaskBlit; Java_sun_java2d_loops_MaskFill_MaskFill; + Java_sun_java2d_loops_MaskFill_FillAAPgram; + Java_sun_java2d_loops_MaskFill_DrawAAPgram; Java_sun_java2d_loops_TransformHelper_Transform; Java_sun_java2d_pipe_Region_initIDs; Java_sun_java2d_pipe_SpanClipRenderer_initIDs; diff --git a/make/sun/awt/mapfile-vers-linux b/make/sun/awt/mapfile-vers-linux index 3ea914a2124ed728d65411a4c53d9d7225cec45f..60fa9ccef69a93df3149ea090bff17586ec7d851 100644 --- a/make/sun/awt/mapfile-vers-linux +++ b/make/sun/awt/mapfile-vers-linux @@ -115,6 +115,8 @@ SUNWprivate_1.1 { Java_sun_java2d_loops_GraphicsPrimitiveMgr_registerNativeLoops; Java_sun_java2d_loops_MaskBlit_MaskBlit; Java_sun_java2d_loops_MaskFill_MaskFill; + Java_sun_java2d_loops_MaskFill_FillAAPgram; + Java_sun_java2d_loops_MaskFill_DrawAAPgram; Java_sun_java2d_pipe_BufferedRenderPipe_fillSpans; Java_sun_java2d_pipe_SpanClipRenderer_initIDs; sun_awt_image_GifImageDecoder_initIDs; diff --git a/make/tools/src/build/tools/javazic/Zoneinfo.java b/make/tools/src/build/tools/javazic/Zoneinfo.java index 143c687d51b9357faf0a95419b6790f7578c686a..872cc1144c8568239e8f195dc9d24a70cef5060b 100644 --- a/make/tools/src/build/tools/javazic/Zoneinfo.java +++ b/make/tools/src/build/tools/javazic/Zoneinfo.java @@ -222,6 +222,7 @@ class Zoneinfo { boolean continued = false; Zone zone = null; String l; + lineNum = 0; try { while ((line = in.readLine()) != null) { diff --git a/src/share/classes/java/awt/SplashScreen.java b/src/share/classes/java/awt/SplashScreen.java index e236f0770f10cc4828613b1ec99124746c4a50e6..867ecb330c5ac4cc39fd8ed4cbea09b499ae7a0a 100644 --- a/src/share/classes/java/awt/SplashScreen.java +++ b/src/share/classes/java/awt/SplashScreen.java @@ -33,27 +33,17 @@ import sun.util.logging.PlatformLogger; import sun.awt.image.SunWritableRaster; /** - * The splash screen can be created at application startup, before the + * The splash screen can be displayed at application startup, before the * Java Virtual Machine (JVM) starts. The splash screen is displayed as an - * undecorated window containing an image. You can use GIF, JPEG, and PNG files - * for the image. Animation (for GIF) and transparency (for GIF, PNG) are - * supported. The window is positioned at the center of the screen (the - * position on multi-monitor systems is not specified - it is platform and - * implementation dependent). - * The window is closed automatically as soon as the first window is displayed by - * Swing/AWT (may be also closed manually using the Java API, see below). + * undecorated window containing an image. You can use GIF, JPEG, or PNG files + * for the image. Animation is supported for the GIF format, while transparency + * is supported both for GIF and PNG. The window is positioned at the center + * of the screen. The position on multi-monitor systems is not specified. It is + * platform and implementation dependent. The splash screen window is closed + * automatically as soon as the first window is displayed by Swing/AWT (may be + * also closed manually using the Java API, see below). *

- * There are two ways to show the native splash screen: - *

- *

+ *

+ * The splash screen will be displayed as faithfully as possible to present the + * whole splash screen image given the limitations of the target platform and + * display. + *

+ * It is implied that the specified image is presented on the screen "as is", + * i.e. preserving the exact color values as specified in the image file. Under + * certain circumstances, though, the presented image may differ, e.g. when + * applying color dithering to present a 32 bits per pixel (bpp) image on a 16 + * or 8 bpp screen. The native platform display configuration may also affect + * the colors of the displayed image (e.g. color profiles, etc.) *

* The {@code SplashScreen} class provides the API for controlling the splash * screen. This class may be used to close the splash screen, change the splash - * screen image, get the image position/size and paint in the splash screen. It - * cannot be used to create the splash screen; you should use the command line or manifest - * file option for that. + * screen image, get the splash screen native window position/size, and paint + * in the splash screen. It cannot be used to create the splash screen. You + * should use the options provided by the Java implementation for that. *

* This class cannot be instantiated. Only a single instance of this class - * can exist, and it may be obtained using the {@link #getSplashScreen()} + * can exist, and it may be obtained by using the {@link #getSplashScreen()} * static method. In case the splash screen has not been created at * application startup via the command line or manifest file option, * the getSplashScreen method returns null. @@ -91,7 +102,7 @@ public final class SplashScreen { /** * Returns the {@code SplashScreen} object used for - * Java startup splash screen control. + * Java startup splash screen control on systems that support display. * * @throws UnsupportedOperationException if the splash screen feature is not * supported by the current toolkit @@ -219,6 +230,9 @@ public final class SplashScreen { *

* You cannot control the size or position of the splash screen. * The splash screen size is adjusted automatically when the image changes. + *

+ * The image may contain transparent areas, and thus the reported bounds may + * be larger than the visible splash screen image on the screen. * * @return a {@code Rectangle} containing the splash screen bounds * @throws IllegalStateException if the splash screen has already been closed @@ -237,6 +251,9 @@ public final class SplashScreen { *

* You cannot control the size or position of the splash screen. * The splash screen size is adjusted automatically when the image changes. + *

+ * The image may contain transparent areas, and thus the reported size may + * be larger than the visible splash screen image on the screen. * * @return a {@link Dimension} object indicating the splash screen size * @throws IllegalStateException if the splash screen has already been closed @@ -254,6 +271,10 @@ public final class SplashScreen { * screen window. You should call {@code update()} on the * SplashScreen when you want the splash screen to be * updated immediately. + *

+ * The pixel (0, 0) in the coordinate space of the graphics context + * corresponds to the origin of the splash screen native window bounds (see + * {@link #getBounds()}). * * @return graphics context for the splash screen overlay surface * @throws IllegalStateException if the splash screen has already been closed @@ -334,6 +355,11 @@ public final class SplashScreen { * Determines whether the splash screen is visible. The splash screen may * be hidden using {@link #close()}, it is also hidden automatically when * the first AWT/Swing window is made visible. + *

+ * Note that the native platform may delay presenting the splash screen + * native window on the screen. The return value of {@code true} for this + * method only guarantees that the conditions to hide the splash screen + * window have not occurred yet. * * @return true if the splash screen is visible (has not been closed yet), * false otherwise diff --git a/src/share/classes/java/awt/font/NumericShaper.java b/src/share/classes/java/awt/font/NumericShaper.java index 0c57c299fb61ca770ce039cdd0ad00597ab153f9..c8100bfb0dea20c53dcce409127cca63ca884bf8 100644 --- a/src/share/classes/java/awt/font/NumericShaper.java +++ b/src/share/classes/java/awt/font/NumericShaper.java @@ -58,20 +58,20 @@ import java.util.Set; * It is also possible to perform numeric shaping explicitly using instances * of NumericShaper, as this code snippet demonstrates:
*

- *   char[] text = ...;
- *   // shape all EUROPEAN digits (except zero) to ARABIC digits
- *   NumericShaper shaper = NumericShaper.getShaper(NumericShaper.ARABIC);
- *   shaper.shape(text, start, count);
+ * char[] text = ...;
+ * // shape all EUROPEAN digits (except zero) to ARABIC digits
+ * NumericShaper shaper = NumericShaper.getShaper(NumericShaper.ARABIC);
+ * shaper.shape(text, start, count);
  *
- *   // shape European digits to ARABIC digits if preceding text is Arabic, or
- *   // shape European digits to TAMIL digits if preceding text is Tamil, or
- *   // leave European digits alone if there is no preceding text, or
- *   // preceding text is neither Arabic nor Tamil
- *   NumericShaper shaper =
- *      NumericShaper.getContextualShaper(NumericShaper.ARABIC |
- *                                              NumericShaper.TAMIL,
- *                                              NumericShaper.EUROPEAN);
- *   shaper.shape(text, start, count);
+ * // shape European digits to ARABIC digits if preceding text is Arabic, or
+ * // shape European digits to TAMIL digits if preceding text is Tamil, or
+ * // leave European digits alone if there is no preceding text, or
+ * // preceding text is neither Arabic nor Tamil
+ * NumericShaper shaper =
+ *     NumericShaper.getContextualShaper(NumericShaper.ARABIC |
+ *                                         NumericShaper.TAMIL,
+ *                                       NumericShaper.EUROPEAN);
+ * shaper.shape(text, start, count);
  * 
* *

Bit mask- and enum-based Unicode ranges

@@ -99,6 +99,37 @@ import java.util.Set; * values are specified, such as {@code NumericShaper.Range.BALINESE}, * those ranges are ignored. * + *

Decimal Digits Precedence

+ * + *

A Unicode range may have more than one set of decimal digits. If + * multiple decimal digits sets are specified for the same Unicode + * range, one of the sets will take precedence as follows. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Unicode RangeNumericShaper ConstantsPrecedence
Arabic{@link NumericShaper#ARABIC NumericShaper.ARABIC}
+ * {@link NumericShaper#EASTERN_ARABIC NumericShaper.EASTERN_ARABIC}
{@link NumericShaper#EASTERN_ARABIC NumericShaper.EASTERN_ARABIC}
{@link NumericShaper.Range#ARABIC}
+ * {@link NumericShaper.Range#EASTERN_ARABIC}
{@link NumericShaper.Range#EASTERN_ARABIC}
Tai Tham{@link NumericShaper.Range#TAI_THAM_HORA}
+ * {@link NumericShaper.Range#TAI_THAM_THAM}
{@link NumericShaper.Range#TAI_THAM_THAM}
+ * * @since 1.4 */ diff --git a/src/share/classes/java/awt/image/IndexColorModel.java b/src/share/classes/java/awt/image/IndexColorModel.java index 373a7e89061a6e5bd06df8b7b81dcf32fb94399b..fabe8d20432cfe19face31984e8eb6c053354030 100644 --- a/src/share/classes/java/awt/image/IndexColorModel.java +++ b/src/share/classes/java/awt/image/IndexColorModel.java @@ -625,7 +625,7 @@ public class IndexColorModel extends ColorModel { } nBits[0] = nBits[1] = nBits[2] = 8; } - return nBits; + return nBits.clone(); } /** diff --git a/src/share/classes/java/awt/image/SampleModel.java b/src/share/classes/java/awt/image/SampleModel.java index 5e7a0458ce4097d22349c2ba2e1c6f41e889e198..2412da2db949e5000fa6694ee12fa78dcadae8b1 100644 --- a/src/share/classes/java/awt/image/SampleModel.java +++ b/src/share/classes/java/awt/image/SampleModel.java @@ -121,7 +121,7 @@ public abstract class SampleModel */ public SampleModel(int dataType, int w, int h, int numBands) { - float size = (float)w*h; + long size = (long)w * h; if (w <= 0 || h <= 0) { throw new IllegalArgumentException("Width ("+w+") and height ("+ h+") must be > 0"); diff --git a/src/share/classes/java/awt/image/SinglePixelPackedSampleModel.java b/src/share/classes/java/awt/image/SinglePixelPackedSampleModel.java index e7a0f44e7871c5675021a703ec8945f6c1ae49ba..7ad012706504d22b1eeef31eeb4c65506fd514c2 100644 --- a/src/share/classes/java/awt/image/SinglePixelPackedSampleModel.java +++ b/src/share/classes/java/awt/image/SinglePixelPackedSampleModel.java @@ -92,7 +92,8 @@ public class SinglePixelPackedSampleModel extends SampleModel * Constructs a SinglePixelPackedSampleModel with bitMasks.length bands. * Each sample is stored in a data array element in the position of * its corresponding bit mask. Each bit mask must be contiguous and - * masks must not overlap. + * masks must not overlap. Bit masks exceeding data type capacity are + * truncated. * @param dataType The data type for storing samples. * @param w The width (in pixels) of the region of the * image data described. @@ -120,7 +121,8 @@ public class SinglePixelPackedSampleModel extends SampleModel * and a scanline stride equal to scanlineStride data array elements. * Each sample is stored in a data array element in the position of * its corresponding bit mask. Each bit mask must be contiguous and - * masks must not overlap. + * masks must not overlap. Bit masks exceeding data type capacity are + * truncated. * @param dataType The data type for storing samples. * @param w The width (in pixels) of the region of * image data described. @@ -153,11 +155,13 @@ public class SinglePixelPackedSampleModel extends SampleModel this.bitOffsets = new int[numBands]; this.bitSizes = new int[numBands]; + int maxMask = (int)((1L << DataBuffer.getDataTypeSize(dataType)) - 1); + this.maxBitSize = 0; for (int i=0; i>> 1; @@ -243,30 +247,12 @@ public class SinglePixelPackedSampleModel extends SampleModel /** Returns the number of bits per sample for all bands. */ public int[] getSampleSize() { - int mask; - int sampleSize[] = new int [numBands]; - for (int i=0; i>> bitOffsets[i]; - while ((mask & 1) != 0) { - sampleSize[i] ++; - mask = mask >>> 1; - } - } - - return sampleSize; + return bitSizes.clone(); } /** Returns the number of bits per sample for the specified band. */ public int getSampleSize(int band) { - int sampleSize = 0; - int mask = bitMasks[band] >>> bitOffsets[band]; - while ((mask & 1) != 0) { - sampleSize ++; - mask = mask >>> 1; - } - - return sampleSize; + return bitSizes[band]; } /** Returns the offset (in data array elements) of pixel (x,y). diff --git a/src/share/classes/java/text/MessageFormat.java b/src/share/classes/java/text/MessageFormat.java index ed155e9b2f7329781e7a6b0b2316886b7b6a96bb..6590e7677952f3dd347e00186d0b4db65789e640 100644 --- a/src/share/classes/java/text/MessageFormat.java +++ b/src/share/classes/java/text/MessageFormat.java @@ -93,73 +93,65 @@ import java.util.Locale; * currency * percent * SubformatPattern + * * - * String: - * StringPartopt - * String StringPart + *

Within a String, a pair of single quotes can be used to + * quote any arbitrary characters except single quotes. For example, + * pattern string "'{0}'" represents string + * "{0}", not a FormatElement. A single quote itself + * must be represented by doubled single quotes {@code ''} throughout a + * String. For example, pattern string "'{''}'" is + * interpreted as a sequence of '{ (start of quoting and a + * left curly brace), '' (a single quote), and + * }' (a right curly brace and end of quoting), + * not '{' and '}' (quoted left and + * right curly braces): representing string "{'}", + * not "{}". * - * StringPart: - * '' - * ' QuotedString ' - * UnquotedString + *

A SubformatPattern is interpreted by its corresponding + * subformat, and subformat-dependent pattern rules apply. For example, + * pattern string "{1,number,$'#',##}" + * (SubformatPattern with underline) will produce a number format + * with the pound-sign quoted, with a result such as: {@code + * "$#31,45"}. Refer to each {@code Format} subclass documentation for + * details. * - * SubformatPattern: - * SubformatPatternPartopt - * SubformatPattern SubformatPatternPart + *

Any unmatched quote is treated as closed at the end of the given + * pattern. For example, pattern string {@code "'{0}"} is treated as + * pattern {@code "'{0}'"}. * - * SubFormatPatternPart: - * ' QuotedPattern ' - * UnquotedPattern - * + *

Any curly braces within an unquoted pattern must be balanced. For + * example, "ab {0} de" and "ab '}' de" are + * valid patterns, but "ab {0'}' de", "ab } de" + * and "''{''" are not. * *

- * Within a String, "''" represents a single - * quote. A QuotedString can contain arbitrary characters - * except single quotes; the surrounding single quotes are removed. - * An UnquotedString can contain arbitrary characters - * except single quotes and left curly brackets. Thus, a string that - * should result in the formatted message "'{0}'" can be written as - * "'''{'0}''" or "'''{0}'''". - *

- * Within a SubformatPattern, different rules apply. - * A QuotedPattern can contain arbitrary characters - * except single quotes; but the surrounding single quotes are - * not removed, so they may be interpreted by the - * subformat. For example, "{1,number,$'#',##}" will - * produce a number format with the pound-sign quoted, with a result - * such as: "$#31,45". - * An UnquotedPattern can contain arbitrary characters - * except single quotes, but curly braces within it must be balanced. - * For example, "ab {0} de" and "ab '}' de" - * are valid subformat patterns, but "ab {0'}' de" and - * "ab } de" are not. - *

*

Warning:
The rules for using quotes within message * format patterns unfortunately have shown to be somewhat confusing. * In particular, it isn't always obvious to localizers whether single * quotes need to be doubled or not. Make sure to inform localizers about * the rules, and tell them (for example, by using comments in resource - * bundle source files) which strings will be processed by MessageFormat. + * bundle source files) which strings will be processed by {@code MessageFormat}. * Note that localizers may need to use single quotes in translated * strings where the original version doesn't have them. *
*

* The ArgumentIndex value is a non-negative integer written - * using the digits '0' through '9', and represents an index into the - * arguments array passed to the format methods - * or the result array returned by the parse methods. + * using the digits {@code '0'} through {@code '9'}, and represents an index into the + * {@code arguments} array passed to the {@code format} methods + * or the result array returned by the {@code parse} methods. *

* The FormatType and FormatStyle values are used to create - * a Format instance for the format element. The following - * table shows how the values map to Format instances. Combinations not + * a {@code Format} instance for the format element. The following + * table shows how the values map to {@code Format} instances. Combinations not * shown in the table are illegal. A SubformatPattern must - * be a valid pattern string for the Format subclass used. + * be a valid pattern string for the {@code Format} subclass used. *

* * - * * * * * * * * * * * * * * * * * * * *
Format Type - * Format Style - * Subformat Created + * FormatType + * FormatStyle + * Subformat Created *
(none) * (none) @@ -167,61 +159,61 @@ import java.util.Locale; *
number * (none) - * NumberFormat.getInstance(getLocale()) + * {@link NumberFormat#getInstance(Locale) NumberFormat.getInstance}{@code (getLocale())} *
integer - * NumberFormat.getIntegerInstance(getLocale()) + * {@link NumberFormat#getIntegerInstance(Locale) NumberFormat.getIntegerInstance}{@code (getLocale())} *
currency - * NumberFormat.getCurrencyInstance(getLocale()) + * {@link NumberFormat#getCurrencyInstance(Locale) NumberFormat.getCurrencyInstance}{@code (getLocale())} *
percent - * NumberFormat.getPercentInstance(getLocale()) + * {@link NumberFormat#getPercentInstance(Locale) NumberFormat.getPercentInstance}{@code (getLocale())} *
SubformatPattern - * new DecimalFormat(subformatPattern, DecimalFormatSymbols.getInstance(getLocale())) + * {@code new} {@link DecimalFormat#DecimalFormat(String,DecimalFormatSymbols) DecimalFormat}{@code (subformatPattern,} {@link DecimalFormatSymbols#getInstance(Locale) DecimalFormatSymbols.getInstance}{@code (getLocale()))} *
date * (none) - * DateFormat.getDateInstance(DateFormat.DEFAULT, getLocale()) + * {@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())} *
short - * DateFormat.getDateInstance(DateFormat.SHORT, getLocale()) + * {@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#SHORT}{@code , getLocale())} *
medium - * DateFormat.getDateInstance(DateFormat.DEFAULT, getLocale()) + * {@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())} *
long - * DateFormat.getDateInstance(DateFormat.LONG, getLocale()) + * {@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#LONG}{@code , getLocale())} *
full - * DateFormat.getDateInstance(DateFormat.FULL, getLocale()) + * {@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#FULL}{@code , getLocale())} *
SubformatPattern - * new SimpleDateFormat(subformatPattern, getLocale()) + * {@code new} {@link SimpleDateFormat#SimpleDateFormat(String,Locale) SimpleDateFormat}{@code (subformatPattern, getLocale())} *
time * (none) - * DateFormat.getTimeInstance(DateFormat.DEFAULT, getLocale()) + * {@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())} *
short - * DateFormat.getTimeInstance(DateFormat.SHORT, getLocale()) + * {@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#SHORT}{@code , getLocale())} *
medium - * DateFormat.getTimeInstance(DateFormat.DEFAULT, getLocale()) + * {@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())} *
long - * DateFormat.getTimeInstance(DateFormat.LONG, getLocale()) + * {@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#LONG}{@code , getLocale())} *
full - * DateFormat.getTimeInstance(DateFormat.FULL, getLocale()) + * {@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#FULL}{@code , getLocale())} *
SubformatPattern - * new SimpleDateFormat(subformatPattern, getLocale()) + * {@code new} {@link SimpleDateFormat#SimpleDateFormat(String,Locale) SimpleDateFormat}{@code (subformatPattern, getLocale())} *
choice * SubformatPattern - * new ChoiceFormat(subformatPattern) + * {@code new} {@link ChoiceFormat#ChoiceFormat(String) ChoiceFormat}{@code (subformatPattern)} *
*

* @@ -321,7 +313,7 @@ import java.util.Locale; * * *

- * Likewise, parsing with a MessageFormat object using patterns containing + * Likewise, parsing with a {@code MessageFormat} object using patterns containing * multiple occurrences of the same argument would return the last match. For * example, *

@@ -343,7 +335,11 @@ import java.util.Locale;
  * @see          Format
  * @see          NumberFormat
  * @see          DecimalFormat
+ * @see          DecimalFormatSymbols
  * @see          ChoiceFormat
+ * @see          DateFormat
+ * @see          SimpleDateFormat
+ *
  * @author       Mark Davis
  */
 
@@ -427,18 +423,19 @@ public class MessageFormat extends Format {
      * @exception IllegalArgumentException if the pattern is invalid
      */
     public void applyPattern(String pattern) {
-            StringBuffer[] segments = new StringBuffer[4];
-            for (int i = 0; i < segments.length; ++i) {
-                segments[i] = new StringBuffer();
-            }
-            int part = 0;
+            StringBuilder[] segments = new StringBuilder[4];
+            // Allocate only segments[SEG_RAW] here. The rest are
+            // allocated on demand.
+            segments[SEG_RAW] = new StringBuilder();
+
+            int part = SEG_RAW;
             int formatNumber = 0;
             boolean inQuote = false;
             int braceStack = 0;
             maxOffset = -1;
             for (int i = 0; i < pattern.length(); ++i) {
                 char ch = pattern.charAt(i);
-                if (part == 0) {
+                if (part == SEG_RAW) {
                     if (ch == '\'') {
                         if (i + 1 < pattern.length()
                             && pattern.charAt(i+1) == '\'') {
@@ -448,43 +445,61 @@ public class MessageFormat extends Format {
                             inQuote = !inQuote;
                         }
                     } else if (ch == '{' && !inQuote) {
-                        part = 1;
+                        part = SEG_INDEX;
+                        if (segments[SEG_INDEX] == null) {
+                            segments[SEG_INDEX] = new StringBuilder();
+                        }
                     } else {
                         segments[part].append(ch);
                     }
-                } else  if (inQuote) {              // just copy quotes in parts
-                    segments[part].append(ch);
-                    if (ch == '\'') {
-                        inQuote = false;
-                    }
-                } else {
-                    switch (ch) {
-                    case ',':
-                        if (part < 3)
-                            part += 1;
-                        else
-                            segments[part].append(ch);
-                        break;
-                    case '{':
-                        ++braceStack;
+                } else  {
+                    if (inQuote) {              // just copy quotes in parts
                         segments[part].append(ch);
-                        break;
-                    case '}':
-                        if (braceStack == 0) {
-                            part = 0;
-                            makeFormat(i, formatNumber, segments);
-                            formatNumber++;
-                        } else {
-                            --braceStack;
+                        if (ch == '\'') {
+                            inQuote = false;
+                        }
+                    } else {
+                        switch (ch) {
+                        case ',':
+                            if (part < SEG_MODIFIER) {
+                                if (segments[++part] == null) {
+                                    segments[part] = new StringBuilder();
+                                }
+                            } else {
+                                segments[part].append(ch);
+                            }
+                            break;
+                        case '{':
+                            ++braceStack;
                             segments[part].append(ch);
+                            break;
+                        case '}':
+                            if (braceStack == 0) {
+                                part = SEG_RAW;
+                                makeFormat(i, formatNumber, segments);
+                                formatNumber++;
+                                // throw away other segments
+                                segments[SEG_INDEX] = null;
+                                segments[SEG_TYPE] = null;
+                                segments[SEG_MODIFIER] = null;
+                            } else {
+                                --braceStack;
+                                segments[part].append(ch);
+                            }
+                            break;
+                        case ' ':
+                            // Skip any leading space chars for SEG_TYPE.
+                            if (part != SEG_TYPE || segments[SEG_TYPE].length() > 0) {
+                                segments[part].append(ch);
+                            }
+                            break;
+                        case '\'':
+                            inQuote = true;
+                            // fall through, so we keep quotes in other parts
+                        default:
+                            segments[part].append(ch);
+                            break;
                         }
-                        break;
-                    case '\'':
-                        inQuote = true;
-                        // fall through, so we keep quotes in other parts
-                    default:
-                        segments[part].append(ch);
-                        break;
                     }
                 }
             }
@@ -506,65 +521,57 @@ public class MessageFormat extends Format {
     public String toPattern() {
         // later, make this more extensible
         int lastOffset = 0;
-        StringBuffer result = new StringBuffer();
+        StringBuilder result = new StringBuilder();
         for (int i = 0; i <= maxOffset; ++i) {
-            copyAndFixQuotes(pattern, lastOffset, offsets[i],result);
+            copyAndFixQuotes(pattern, lastOffset, offsets[i], result);
             lastOffset = offsets[i];
-            result.append('{');
-            result.append(argumentNumbers[i]);
-            if (formats[i] == null) {
+            result.append('{').append(argumentNumbers[i]);
+            Format fmt = formats[i];
+            if (fmt == null) {
                 // do nothing, string format
-            } else if (formats[i] instanceof DecimalFormat) {
-                if (formats[i].equals(NumberFormat.getInstance(locale))) {
+            } else if (fmt instanceof NumberFormat) {
+                if (fmt.equals(NumberFormat.getInstance(locale))) {
                     result.append(",number");
-                } else if (formats[i].equals(NumberFormat.getCurrencyInstance(locale))) {
+                } else if (fmt.equals(NumberFormat.getCurrencyInstance(locale))) {
                     result.append(",number,currency");
-                } else if (formats[i].equals(NumberFormat.getPercentInstance(locale))) {
+                } else if (fmt.equals(NumberFormat.getPercentInstance(locale))) {
                     result.append(",number,percent");
-                } else if (formats[i].equals(NumberFormat.getIntegerInstance(locale))) {
+                } else if (fmt.equals(NumberFormat.getIntegerInstance(locale))) {
                     result.append(",number,integer");
                 } else {
-                    result.append(",number," +
-                                  ((DecimalFormat)formats[i]).toPattern());
+                    if (fmt instanceof DecimalFormat) {
+                        result.append(",number,").append(((DecimalFormat)fmt).toPattern());
+                    } else if (fmt instanceof ChoiceFormat) {
+                        result.append(",choice,").append(((ChoiceFormat)fmt).toPattern());
+                    } else {
+                        // UNKNOWN
+                    }
                 }
-            } else if (formats[i] instanceof SimpleDateFormat) {
-                if (formats[i].equals(DateFormat.getDateInstance(
-                                                               DateFormat.DEFAULT,locale))) {
-                    result.append(",date");
-                } else if (formats[i].equals(DateFormat.getDateInstance(
-                                                                      DateFormat.SHORT,locale))) {
-                    result.append(",date,short");
-                } else if (formats[i].equals(DateFormat.getDateInstance(
-                                                                      DateFormat.DEFAULT,locale))) {
-                    result.append(",date,medium");
-                } else if (formats[i].equals(DateFormat.getDateInstance(
-                                                                      DateFormat.LONG,locale))) {
-                    result.append(",date,long");
-                } else if (formats[i].equals(DateFormat.getDateInstance(
-                                                                      DateFormat.FULL,locale))) {
-                    result.append(",date,full");
-                } else if (formats[i].equals(DateFormat.getTimeInstance(
-                                                                      DateFormat.DEFAULT,locale))) {
-                    result.append(",time");
-                } else if (formats[i].equals(DateFormat.getTimeInstance(
-                                                                      DateFormat.SHORT,locale))) {
-                    result.append(",time,short");
-                } else if (formats[i].equals(DateFormat.getTimeInstance(
-                                                                      DateFormat.DEFAULT,locale))) {
-                    result.append(",time,medium");
-                } else if (formats[i].equals(DateFormat.getTimeInstance(
-                                                                      DateFormat.LONG,locale))) {
-                    result.append(",time,long");
-                } else if (formats[i].equals(DateFormat.getTimeInstance(
-                                                                      DateFormat.FULL,locale))) {
-                    result.append(",time,full");
-                } else {
-                    result.append(",date,"
-                                  + ((SimpleDateFormat)formats[i]).toPattern());
+            } else if (fmt instanceof DateFormat) {
+                int index;
+                for (index = MODIFIER_DEFAULT; index < DATE_TIME_MODIFIERS.length; index++) {
+                    DateFormat df = DateFormat.getDateInstance(DATE_TIME_MODIFIERS[index],
+                                                               locale);
+                    if (fmt.equals(df)) {
+                        result.append(",date");
+                        break;
+                    }
+                    df = DateFormat.getTimeInstance(DATE_TIME_MODIFIERS[index],
+                                                    locale);
+                    if (fmt.equals(df)) {
+                        result.append(",time");
+                        break;
+                    }
+                }
+                if (index >= DATE_TIME_MODIFIERS.length) {
+                    if (fmt instanceof SimpleDateFormat) {
+                        result.append(",date,").append(((SimpleDateFormat)fmt).toPattern());
+                    } else {
+                        // UNKNOWN
+                    }
+                } else if (index != MODIFIER_DEFAULT) {
+                    result.append(',').append(DATE_TIME_MODIFIER_KEYWORDS[index]);
                 }
-            } else if (formats[i] instanceof ChoiceFormat) {
-                result.append(",choice,"
-                              + ((ChoiceFormat)formats[i]).toPattern());
             } else {
                 //result.append(", unknown");
             }
@@ -678,7 +685,7 @@ public class MessageFormat extends Format {
      *
      * @param formatElementIndex the index of a format element within the pattern
      * @param newFormat the format to use for the specified format element
-     * @exception ArrayIndexOutOfBoundsException if formatElementIndex is equal to or
+     * @exception ArrayIndexOutOfBoundsException if {@code formatElementIndex} is equal to or
      *            larger than the number of format elements in the pattern string
      */
     public void setFormat(int formatElementIndex, Format newFormat) {
@@ -972,7 +979,8 @@ public class MessageFormat extends Format {
                 if (patternOffset >= tempLength) {
                     next = source.length();
                 }else{
-                    next = source.indexOf( pattern.substring(patternOffset,tempLength), sourceOffset);
+                    next = source.indexOf(pattern.substring(patternOffset, tempLength),
+                                          sourceOffset);
                 }
 
                 if (next < 0) {
@@ -1226,7 +1234,7 @@ public class MessageFormat extends Format {
             lastOffset = offsets[i];
             int argumentNumber = argumentNumbers[i];
             if (arguments == null || argumentNumber >= arguments.length) {
-                result.append("{" + argumentNumber + "}");
+                result.append('{').append(argumentNumber).append('}');
                 continue;
             }
             // int argRecursion = ((recursionProtection >> (argumentNumber*2)) & 0x3);
@@ -1338,25 +1346,83 @@ public class MessageFormat extends Format {
         }
     }
 
-    private static final String[] typeList =
-    {"", "", "number", "", "date", "", "time", "", "choice"};
-    private static final String[] modifierList =
-    {"", "", "currency", "", "percent", "", "integer"};
-    private static final String[] dateModifierList =
-    {"", "", "short", "", "medium", "", "long", "", "full"};
+    // Indices for segments
+    private static final int SEG_RAW      = 0;
+    private static final int SEG_INDEX    = 1;
+    private static final int SEG_TYPE     = 2;
+    private static final int SEG_MODIFIER = 3; // modifier or subformat
+
+    // Indices for type keywords
+    private static final int TYPE_NULL    = 0;
+    private static final int TYPE_NUMBER  = 1;
+    private static final int TYPE_DATE    = 2;
+    private static final int TYPE_TIME    = 3;
+    private static final int TYPE_CHOICE  = 4;
+
+    private static final String[] TYPE_KEYWORDS = {
+        "",
+        "number",
+        "date",
+        "time",
+        "choice"
+    };
+
+    // Indices for number modifiers
+    private static final int MODIFIER_DEFAULT  = 0; // common in number and date-time
+    private static final int MODIFIER_CURRENCY = 1;
+    private static final int MODIFIER_PERCENT  = 2;
+    private static final int MODIFIER_INTEGER  = 3;
+
+    private static final String[] NUMBER_MODIFIER_KEYWORDS = {
+        "",
+        "currency",
+        "percent",
+        "integer"
+    };
+
+    // Indices for date-time modifiers
+    private static final int MODIFIER_SHORT   = 1;
+    private static final int MODIFIER_MEDIUM  = 2;
+    private static final int MODIFIER_LONG    = 3;
+    private static final int MODIFIER_FULL    = 4;
+
+    private static final String[] DATE_TIME_MODIFIER_KEYWORDS = {
+        "",
+        "short",
+        "medium",
+        "long",
+        "full"
+    };
+
+    // Date-time style values corresponding to the date-time modifiers.
+    private static final int[] DATE_TIME_MODIFIERS = {
+        DateFormat.DEFAULT,
+        DateFormat.SHORT,
+        DateFormat.MEDIUM,
+        DateFormat.LONG,
+        DateFormat.FULL,
+    };
 
     private void makeFormat(int position, int offsetNumber,
-                            StringBuffer[] segments)
+                            StringBuilder[] textSegments)
     {
+        String[] segments = new String[textSegments.length];
+        for (int i = 0; i < textSegments.length; i++) {
+            StringBuilder oneseg = textSegments[i];
+            segments[i] = (oneseg != null) ? oneseg.toString() : "";
+        }
+
         // get the argument number
         int argumentNumber;
         try {
-            argumentNumber = Integer.parseInt(segments[1].toString()); // always unlocalized!
+            argumentNumber = Integer.parseInt(segments[SEG_INDEX]); // always unlocalized!
         } catch (NumberFormatException e) {
-            throw new IllegalArgumentException("can't parse argument number: " + segments[1]);
+            throw new IllegalArgumentException("can't parse argument number: "
+                                               + segments[SEG_INDEX], e);
         }
         if (argumentNumber < 0) {
-            throw new IllegalArgumentException("negative argument number: " + argumentNumber);
+            throw new IllegalArgumentException("negative argument number: "
+                                               + argumentNumber);
         }
 
         // resize format information arrays if necessary
@@ -1374,120 +1440,129 @@ public class MessageFormat extends Format {
         }
         int oldMaxOffset = maxOffset;
         maxOffset = offsetNumber;
-        offsets[offsetNumber] = segments[0].length();
+        offsets[offsetNumber] = segments[SEG_RAW].length();
         argumentNumbers[offsetNumber] = argumentNumber;
 
         // now get the format
         Format newFormat = null;
-        switch (findKeyword(segments[2].toString(), typeList)) {
-        case 0:
-            break;
-        case 1: case 2:// number
-            switch (findKeyword(segments[3].toString(), modifierList)) {
-            case 0: // default;
-                newFormat = NumberFormat.getInstance(locale);
-                break;
-            case 1: case 2:// currency
-                newFormat = NumberFormat.getCurrencyInstance(locale);
-                break;
-            case 3: case 4:// percent
-                newFormat = NumberFormat.getPercentInstance(locale);
-                break;
-            case 5: case 6:// integer
-                newFormat = NumberFormat.getIntegerInstance(locale);
-                break;
-            default: // pattern
-                newFormat = new DecimalFormat(segments[3].toString(), DecimalFormatSymbols.getInstance(locale));
+        if (segments[SEG_TYPE].length() != 0) {
+            int type = findKeyword(segments[SEG_TYPE], TYPE_KEYWORDS);
+            switch (type) {
+            case TYPE_NULL:
+                // Type "" is allowed. e.g., "{0,}", "{0,,}", and "{0,,#}"
+                // are treated as "{0}".
                 break;
-            }
-            break;
-        case 3: case 4: // date
-            switch (findKeyword(segments[3].toString(), dateModifierList)) {
-            case 0: // default
-                newFormat = DateFormat.getDateInstance(DateFormat.DEFAULT, locale);
-                break;
-            case 1: case 2: // short
-                newFormat = DateFormat.getDateInstance(DateFormat.SHORT, locale);
-                break;
-            case 3: case 4: // medium
-                newFormat = DateFormat.getDateInstance(DateFormat.DEFAULT, locale);
-                break;
-            case 5: case 6: // long
-                newFormat = DateFormat.getDateInstance(DateFormat.LONG, locale);
-                break;
-            case 7: case 8: // full
-                newFormat = DateFormat.getDateInstance(DateFormat.FULL, locale);
-                break;
-            default:
-                newFormat = new SimpleDateFormat(segments[3].toString(), locale);
-                break;
-            }
-            break;
-        case 5: case 6:// time
-            switch (findKeyword(segments[3].toString(), dateModifierList)) {
-            case 0: // default
-                newFormat = DateFormat.getTimeInstance(DateFormat.DEFAULT, locale);
-                break;
-            case 1: case 2: // short
-                newFormat = DateFormat.getTimeInstance(DateFormat.SHORT, locale);
-                break;
-            case 3: case 4: // medium
-                newFormat = DateFormat.getTimeInstance(DateFormat.DEFAULT, locale);
+
+            case TYPE_NUMBER:
+                switch (findKeyword(segments[SEG_MODIFIER], NUMBER_MODIFIER_KEYWORDS)) {
+                case MODIFIER_DEFAULT:
+                    newFormat = NumberFormat.getInstance(locale);
+                    break;
+                case MODIFIER_CURRENCY:
+                    newFormat = NumberFormat.getCurrencyInstance(locale);
+                    break;
+                case MODIFIER_PERCENT:
+                    newFormat = NumberFormat.getPercentInstance(locale);
+                    break;
+                case MODIFIER_INTEGER:
+                    newFormat = NumberFormat.getIntegerInstance(locale);
+                    break;
+                default: // DecimalFormat pattern
+                    try {
+                        newFormat = new DecimalFormat(segments[SEG_MODIFIER],
+                                                      DecimalFormatSymbols.getInstance(locale));
+                    } catch (IllegalArgumentException e) {
+                        maxOffset = oldMaxOffset;
+                        throw e;
+                    }
+                    break;
+                }
                 break;
-            case 5: case 6: // long
-                newFormat = DateFormat.getTimeInstance(DateFormat.LONG, locale);
+
+            case TYPE_DATE:
+            case TYPE_TIME:
+                int mod = findKeyword(segments[SEG_MODIFIER], DATE_TIME_MODIFIER_KEYWORDS);
+                if (mod >= 0 && mod < DATE_TIME_MODIFIER_KEYWORDS.length) {
+                    if (type == TYPE_DATE) {
+                        newFormat = DateFormat.getDateInstance(DATE_TIME_MODIFIERS[mod],
+                                                               locale);
+                    } else {
+                        newFormat = DateFormat.getTimeInstance(DATE_TIME_MODIFIERS[mod],
+                                                               locale);
+                    }
+                } else {
+                    // SimpleDateFormat pattern
+                    try {
+                        newFormat = new SimpleDateFormat(segments[SEG_MODIFIER], locale);
+                    } catch (IllegalArgumentException e) {
+                        maxOffset = oldMaxOffset;
+                        throw e;
+                    }
+                }
                 break;
-            case 7: case 8: // full
-                newFormat = DateFormat.getTimeInstance(DateFormat.FULL, locale);
+
+            case TYPE_CHOICE:
+                try {
+                    // ChoiceFormat pattern
+                    newFormat = new ChoiceFormat(segments[SEG_MODIFIER]);
+                } catch (Exception e) {
+                    maxOffset = oldMaxOffset;
+                    throw new IllegalArgumentException("Choice Pattern incorrect: "
+                                                       + segments[SEG_MODIFIER], e);
+                }
                 break;
+
             default:
-                newFormat = new SimpleDateFormat(segments[3].toString(), locale);
-                break;
-            }
-            break;
-        case 7: case 8:// choice
-            try {
-                newFormat = new ChoiceFormat(segments[3].toString());
-            } catch (Exception e) {
                 maxOffset = oldMaxOffset;
-                throw new IllegalArgumentException(
-                                         "Choice Pattern incorrect");
+                throw new IllegalArgumentException("unknown format type: " +
+                                                   segments[SEG_TYPE]);
             }
-            break;
-        default:
-            maxOffset = oldMaxOffset;
-            throw new IllegalArgumentException("unknown format type: " +
-                                               segments[2].toString());
         }
         formats[offsetNumber] = newFormat;
-        segments[1].setLength(0);   // throw away other segments
-        segments[2].setLength(0);
-        segments[3].setLength(0);
     }
 
     private static final int findKeyword(String s, String[] list) {
-        s = s.trim().toLowerCase();
         for (int i = 0; i < list.length; ++i) {
             if (s.equals(list[i]))
                 return i;
         }
+
+        // Try trimmed lowercase.
+        String ls = s.trim().toLowerCase(Locale.ROOT);
+        if (ls != s) {
+            for (int i = 0; i < list.length; ++i) {
+                if (ls.equals(list[i]))
+                    return i;
+            }
+        }
         return -1;
     }
 
-    private static final void copyAndFixQuotes(
-                                               String source, int start, int end, StringBuffer target) {
+    private static final void copyAndFixQuotes(String source, int start, int end,
+                                               StringBuilder target) {
+        boolean quoted = false;
+
         for (int i = start; i < end; ++i) {
             char ch = source.charAt(i);
             if (ch == '{') {
-                target.append("'{'");
-            } else if (ch == '}') {
-                target.append("'}'");
+                if (!quoted) {
+                    target.append('\'');
+                    quoted = true;
+                }
+                target.append(ch);
             } else if (ch == '\'') {
                 target.append("''");
             } else {
+                if (quoted) {
+                    target.append('\'');
+                    quoted = false;
+                }
                 target.append(ch);
             }
         }
+        if (quoted) {
+            target.append('\'');
+        }
     }
 
     /**
diff --git a/src/share/classes/java/text/SimpleDateFormat.java b/src/share/classes/java/text/SimpleDateFormat.java
index 9ae84f828d08bca6a3e43fd20b5e86ef2ef2eae8..fd2876aca056bc2bdf13279c613ff8aa4e961524 100644
--- a/src/share/classes/java/text/SimpleDateFormat.java
+++ b/src/share/classes/java/text/SimpleDateFormat.java
@@ -1662,6 +1662,81 @@ public class SimpleDateFormat extends DateFormat {
         return 0;
     }
 
+    /**
+     * Parses numeric forms of time zone offset, such as "hh:mm", and
+     * sets calb to the parsed value.
+     *
+     * @param text  the text to be parsed
+     * @param start the character position to start parsing
+     * @param sign  1: positive; -1: negative
+     * @param count 0: 'Z' or "GMT+hh:mm" parsing; 1 - 3: the number of 'X's
+     * @param colon true - colon required between hh and mm; false - no colon required
+     * @param calb  a CalendarBuilder in which the parsed value is stored
+     * @return updated parsed position, or its negative value to indicate a parsing error
+     */
+    private int subParseNumericZone(String text, int start, int sign, int count,
+                                    boolean colon, CalendarBuilder calb) {
+        int index = start;
+
+      parse:
+        try {
+            char c = text.charAt(index++);
+            // Parse hh
+            int hours;
+            if (!isDigit(c)) {
+                break parse;
+            }
+            hours = c - '0';
+            c = text.charAt(index++);
+            if (isDigit(c)) {
+                hours = hours * 10 + (c - '0');
+            } else {
+                // If no colon in RFC 822 or 'X' (ISO), two digits are
+                // required.
+                if (count > 0 || !colon) {
+                    break parse;
+                }
+                --index;
+            }
+            if (hours > 23) {
+                break parse;
+            }
+            int minutes = 0;
+            if (count != 1) {
+                // Proceed with parsing mm
+                c = text.charAt(index++);
+                if (colon) {
+                    if (c != ':') {
+                        break parse;
+                    }
+                    c = text.charAt(index++);
+                }
+                if (!isDigit(c)) {
+                    break parse;
+                }
+                minutes = c - '0';
+                c = text.charAt(index++);
+                if (!isDigit(c)) {
+                    break parse;
+                }
+                minutes = minutes * 10 + (c - '0');
+                if (minutes > 59) {
+                    break parse;
+                }
+            }
+            minutes += hours * 60;
+            calb.set(Calendar.ZONE_OFFSET, minutes * MILLIS_PER_MINUTE * sign)
+                .set(Calendar.DST_OFFSET, 0);
+            return index;
+        } catch (IndexOutOfBoundsException e) {
+        }
+        return  1 - index; // -(index - 1)
+    }
+
+    private boolean isDigit(char c) {
+        return c >= '0' && c <= '9';
+    }
+
     /**
      * Private member function that converts the parsed date strings into
      * timeFields. Returns -start (for ParsePosition) if failed.
@@ -1907,248 +1982,95 @@ public class SimpleDateFormat extends DateFormat {
 
             case PATTERN_ZONE_NAME:  // 'z'
             case PATTERN_ZONE_VALUE: // 'Z'
-                // First try to parse generic forms such as GMT-07:00. Do this first
-                // in case localized TimeZoneNames contains the string "GMT"
-                // for a zone; in that case, we don't want to match the first three
-                // characters of GMT+/-hh:mm etc.
                 {
                     int sign = 0;
-                    int offset;
-
-                    // For time zones that have no known names, look for strings
-                    // of the form:
-                    //    GMT[+-]hours:minutes or
-                    //    GMT.
-                    if ((text.length() - start) >= GMT.length() &&
-                        text.regionMatches(true, start, GMT, 0, GMT.length())) {
-                        int num;
-                        calb.set(Calendar.DST_OFFSET, 0);
-                        pos.index = start + GMT.length();
-
-                        try { // try-catch for "GMT" only time zone string
-                            char c = text.charAt(pos.index);
-                            if (c == '+') {
-                                sign = 1;
-                            } else if (c == '-') {
-                                sign = -1;
-                            }
-                        }
-                        catch(StringIndexOutOfBoundsException e) {}
-
-                        if (sign == 0) {    /* "GMT" without offset */
-                            calb.set(Calendar.ZONE_OFFSET, 0);
-                            return pos.index;
+                    try {
+                        char c = text.charAt(pos.index);
+                        if (c == '+') {
+                            sign = 1;
+                        } else if (c == '-') {
+                            sign = -1;
                         }
-
-                        // Look for hours.
-                        try {
-                            char c = text.charAt(++pos.index);
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
-                            }
-                            num = c - '0';
-
-                            if (text.charAt(++pos.index) != ':') {
-                                c = text.charAt(pos.index);
-                                if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                    break parsing;
+                        if (sign == 0) {
+                            // Try parsing a custom time zone "GMT+hh:mm" or "GMT".
+                            if ((c == 'G' || c == 'g')
+                                && (text.length() - start) >= GMT.length()
+                                && text.regionMatches(true, start, GMT, 0, GMT.length())) {
+                                pos.index = start + GMT.length();
+
+                                if ((text.length() - pos.index) > 0) {
+                                    c = text.charAt(pos.index);
+                                    if (c == '+') {
+                                        sign = 1;
+                                    } else if (c == '-') {
+                                        sign = -1;
+                                    }
                                 }
-                                num *= 10;
-                                num += c - '0';
-                                pos.index++;
-                            }
-                            if (num > 23) {
-                                --pos.index;
-                                break parsing;
-                            }
-                            if  (text.charAt(pos.index) != ':') {
-                                break parsing;
-                            }
 
-                            // Look for minutes.
-                            offset = num * 60;
-                            c = text.charAt(++pos.index);
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
-                            }
-                            num = c - '0';
-                            c = text.charAt(++pos.index);
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
-                            }
-                            num *= 10;
-                            num += c - '0';
+                                if (sign == 0) {    /* "GMT" without offset */
+                                    calb.set(Calendar.ZONE_OFFSET, 0)
+                                        .set(Calendar.DST_OFFSET, 0);
+                                    return pos.index;
+                                }
 
-                            if (num > 59) {
-                                break parsing;
-                            }
-                        } catch (StringIndexOutOfBoundsException e) {
-                            break parsing;
-                        }
-                        offset += num;
-                        // Fall through for final processing below of 'offset' and 'sign'.
-                    } else {
-                        // If the first character is a sign, look for numeric timezones of
-                        // the form [+-]hhmm as specified by RFC 822. Otherwise, check
-                        // for named time zones by looking through the locale data from
-                        // the TimeZoneNames strings.
-                        try {
-                            char c = text.charAt(pos.index);
-                            if (c == '+') {
-                                sign = 1;
-                            } else if (c == '-') {
-                                sign = -1;
+                                // Parse the rest as "hh:mm"
+                                int i = subParseNumericZone(text, ++pos.index,
+                                                            sign, 0, true, calb);
+                                if (i > 0) {
+                                    return i;
+                                }
+                                pos.index = -i;
                             } else {
-                                // Try parsing the text as a time zone name (abbr).
+                                // Try parsing the text as a time zone
+                                // name or abbreviation.
                                 int i = subParseZoneString(text, pos.index, calb);
-                                if (i != 0) {
+                                if (i > 0) {
                                     return i;
                                 }
-                                break parsing;
-                            }
-
-                            // Parse the text as an RFC 822 time zone string. This code is
-                            // actually a little more permissive than RFC 822.  It will
-                            // try to do its best with numbers that aren't strictly 4
-                            // digits long.
-
-                            // Look for hh.
-                            int hours = 0;
-                            c = text.charAt(++pos.index);
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
+                                pos.index = -i;
                             }
-                            hours = c - '0';
-                            c = text.charAt(++pos.index);
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
-                            }
-                            hours *= 10;
-                            hours += c - '0';
-
-                            if (hours > 23) {
-                                break parsing;
-                            }
-
-                            // Look for mm.
-                            int minutes = 0;
-                            c = text.charAt(++pos.index);
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
-                            }
-                            minutes = c - '0';
-                            c = text.charAt(++pos.index);
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
-                            }
-                            minutes *= 10;
-                            minutes += c - '0';
-
-                            if (minutes > 59) {
-                                break parsing;
+                        } else {
+                            // Parse the rest as "hhmm" (RFC 822)
+                            int i = subParseNumericZone(text, ++pos.index,
+                                                        sign, 0, false, calb);
+                            if (i > 0) {
+                                return i;
                             }
-
-                            offset = hours * 60 + minutes;
-                        } catch (StringIndexOutOfBoundsException e) {
-                            break parsing;
+                            pos.index = -i;
                         }
-                    }
-
-                    // Do the final processing for both of the above cases.  We only
-                    // arrive here if the form GMT+/-... or an RFC 822 form was seen.
-                    if (sign != 0) {
-                        offset *= MILLIS_PER_MINUTE * sign;
-                        calb.set(Calendar.ZONE_OFFSET, offset).set(Calendar.DST_OFFSET, 0);
-                        return ++pos.index;
+                    } catch (IndexOutOfBoundsException e) {
                     }
                 }
                 break parsing;
 
             case PATTERN_ISO_ZONE:   // 'X'
                 {
-                    int sign = 0;
-                    int offset = 0;
-
-                    iso8601: {
-                        try {
-                            char c = text.charAt(pos.index);
-                            if (c == 'Z') {
-                                calb.set(Calendar.ZONE_OFFSET, 0).set(Calendar.DST_OFFSET, 0);
-                                return ++pos.index;
-                            }
-
-                            // parse text as "+/-hh[[:]mm]" based on count
-                            if (c == '+') {
-                                sign = 1;
-                            } else if (c == '-') {
-                                sign = -1;
-                            }
-                            // Look for hh.
-                            int hours = 0;
-                            c = text.charAt(++pos.index);
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
-                            }
-                            hours = c - '0';
-                            c = text.charAt(++pos.index);
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
-                            }
-                            hours *= 10;
-                            hours += c - '0';
-                            if (hours > 23) {
-                                break parsing;
-                            }
-
-                            if (count == 1) { // "X"
-                                offset = hours * 60;
-                                break iso8601;
-                            }
-
-                            c = text.charAt(++pos.index);
-                            // Skip ':' if "XXX"
-                            if (c == ':') {
-                                if (count == 2) {
-                                    break parsing;
-                                }
-                                c = text.charAt(++pos.index);
-                            } else {
-                                if (count == 3) {
-                                    // missing ':'
-                                    break parsing;
-                                }
-                            }
-
-                            // Look for mm.
-                            int minutes = 0;
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
-                            }
-                            minutes = c - '0';
-                            c = text.charAt(++pos.index);
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
-                            }
-                            minutes *= 10;
-                            minutes += c - '0';
-
-                            if (minutes > 59) {
-                                break parsing;
-                            }
-
-                            offset = hours * 60 + minutes;
-                        } catch (StringIndexOutOfBoundsException e) {
-                            break parsing;
-                        }
+                    if ((text.length() - pos.index) <= 0) {
+                        break parsing;
                     }
 
-                    // Do the final processing for both of the above cases.  We only
-                    // arrive here if the form GMT+/-... or an RFC 822 form was seen.
-                    if (sign != 0) {
-                        offset *= MILLIS_PER_MINUTE * sign;
-                        calb.set(Calendar.ZONE_OFFSET, offset).set(Calendar.DST_OFFSET, 0);
+                    int sign = 0;
+                    char c = text.charAt(pos.index);
+                    if (c == 'Z') {
+                        calb.set(Calendar.ZONE_OFFSET, 0).set(Calendar.DST_OFFSET, 0);
                         return ++pos.index;
                     }
+
+                    // parse text as "+/-hh[[:]mm]" based on count
+                    if (c == '+') {
+                        sign = 1;
+                    } else if (c == '-') {
+                        sign = -1;
+                    } else {
+                        ++pos.index;
+                        break parsing;
+                    }
+                    int i = subParseNumericZone(text, ++pos.index, sign, count,
+                                                count == 3, calb);
+                    if (i > 0) {
+                        return i;
+                    }
+                    pos.index = -i;
                 }
                 break parsing;
 
diff --git a/src/share/classes/java/util/Locale.java b/src/share/classes/java/util/Locale.java
index ecaa9cca68a4a35feeb266d6f06194e2a4949e53..1f0fbba1eaea8214b94ade566cddc02b94b0830b 100644
--- a/src/share/classes/java/util/Locale.java
+++ b/src/share/classes/java/util/Locale.java
@@ -1449,10 +1449,15 @@ public final class Locale implements Cloneable, Serializable {
      * three-letter language abbreviation is not available for this locale.
      */
     public String getISO3Language() throws MissingResourceException {
-        String language3 = getISO3Code(_baseLocale.getLanguage(), LocaleISOData.isoLanguageTable);
+        String lang = _baseLocale.getLanguage();
+        if (lang.length() == 3) {
+            return lang;
+        }
+
+        String language3 = getISO3Code(lang, LocaleISOData.isoLanguageTable);
         if (language3 == null) {
             throw new MissingResourceException("Couldn't find 3-letter language code for "
-                    + _baseLocale.getLanguage(), "FormatData_" + toString(), "ShortLanguage");
+                    + lang, "FormatData_" + toString(), "ShortLanguage");
         }
         return language3;
     }
diff --git a/src/share/classes/javax/print/attribute/standard/DialogTypeSelection.java b/src/share/classes/javax/print/attribute/standard/DialogTypeSelection.java
index 1dae59a15258cd5fb8863669b7ff08b1b9e668f1..4cd68bb59afa09d1d95af1140eef3a8291a91313 100644
--- a/src/share/classes/javax/print/attribute/standard/DialogTypeSelection.java
+++ b/src/share/classes/javax/print/attribute/standard/DialogTypeSelection.java
@@ -52,6 +52,8 @@ import javax.print.attribute.PrintRequestAttribute;
 public final class DialogTypeSelection extends EnumSyntax
         implements PrintRequestAttribute {
 
+    private static final long serialVersionUID = 7518682952133256029L;
+
     /**
      *
      */
diff --git a/src/share/classes/javax/sound/midi/MidiSystem.java b/src/share/classes/javax/sound/midi/MidiSystem.java
index d3ce81e22939160461f62e9f22014999d35bb259..b2a47dc96540cbf76878015be43f5a941706e9f5 100644
--- a/src/share/classes/javax/sound/midi/MidiSystem.java
+++ b/src/share/classes/javax/sound/midi/MidiSystem.java
@@ -310,7 +310,7 @@ public class MidiSystem {
         } else {
             transmitter = device.getTransmitter();
         }
-        if (!(transmitter instanceof MidiDeviceReceiver)) {
+        if (!(transmitter instanceof MidiDeviceTransmitter)) {
             transmitter = new MidiDeviceTransmitterEnvelope(device, transmitter);
         }
         return transmitter;
diff --git a/src/share/classes/javax/swing/DefaultDesktopManager.java b/src/share/classes/javax/swing/DefaultDesktopManager.java
index c5d643301e46137fbb62af58a73b3f2757d2af0d..8ab24e56dd755345d7d01c176e035c969a567be0 100644
--- a/src/share/classes/javax/swing/DefaultDesktopManager.java
+++ b/src/share/classes/javax/swing/DefaultDesktopManager.java
@@ -359,7 +359,22 @@ public class DefaultDesktopManager implements DesktopManager, java.io.Serializab
                         f.getWidth()-1, f.getHeight()-1);
               }
               g.drawRect( newX, newY, f.getWidth()-1, f.getHeight()-1);
-              currentLoc = new Point (newX, newY);
+              /* Work around for 6635462: XOR mode may cause a SurfaceLost on first use.
+              * Swing doesn't expect that its XOR drawRect did
+              * not complete, so believes that on re-entering at
+              * the next update location, that there is an XOR rect
+              * to draw out at "currentLoc". But in fact
+              * its now got a new clean surface without that rect,
+              * so drawing it "out" in fact draws it on, leaving garbage.
+              * So only update/set currentLoc if the draw completed.
+              */
+              sun.java2d.SurfaceData sData =
+                  ((sun.java2d.SunGraphics2D)g).getSurfaceData();
+
+              if (!sData.isSurfaceLost()) {
+                  currentLoc = new Point (newX, newY);
+              }
+;
               g.dispose();
             }
         } else if (dragMode == FASTER_DRAG_MODE) {
@@ -412,7 +427,14 @@ public class DefaultDesktopManager implements DesktopManager, java.io.Serializab
                 g.drawRect( currentBounds.x, currentBounds.y, currentBounds.width-1, currentBounds.height-1);
               }
               g.drawRect( newX, newY, newWidth-1, newHeight-1);
-              currentBounds = new Rectangle (newX, newY, newWidth, newHeight);
+
+              // Work around for 6635462, see comment in dragFrame()
+              sun.java2d.SurfaceData sData =
+                  ((sun.java2d.SunGraphics2D)g).getSurfaceData();
+              if (!sData.isSurfaceLost()) {
+                  currentBounds = new Rectangle (newX, newY, newWidth, newHeight);
+              }
+
               g.setPaintMode();
               g.dispose();
             }
diff --git a/src/share/classes/javax/swing/JSlider.java b/src/share/classes/javax/swing/JSlider.java
index 156b9e4fb99ed32700204703856a0af14d236e91..8d188b95bf8d2a42b639d9aef2daeff0d1b179c4 100644
--- a/src/share/classes/javax/swing/JSlider.java
+++ b/src/share/classes/javax/swing/JSlider.java
@@ -40,7 +40,8 @@ import java.beans.*;
 
 /**
  * A component that lets the user graphically select a value by sliding
- * a knob within a bounded interval.
+ * a knob within a bounded interval. The knob is always positioned
+ * at the points that match integer values within the specified interval.
  * 

* The slider can show both * major tick marks, and minor tick marks between the major ones. The number of diff --git a/src/share/classes/javax/swing/plaf/basic/BasicSpinnerUI.java b/src/share/classes/javax/swing/plaf/basic/BasicSpinnerUI.java index b26f226c043a32df235121c29515219f36c76ea6..a57638e39ebb5c01121b679aac07017351c91a32 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicSpinnerUI.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicSpinnerUI.java @@ -908,6 +908,14 @@ public class BasicSpinnerUI extends SpinnerUI int height = parent.getHeight(); Insets insets = parent.getInsets(); + + if (nextButton == null && previousButton == null) { + setBounds(editor, insets.left, insets.top, width - insets.left - insets.right, + height - insets.top - insets.bottom); + + return; + } + Dimension nextD = preferredSize(nextButton); Dimension previousD = preferredSize(previousButton); int buttonsWidth = Math.max(nextD.width, previousD.width); diff --git a/src/share/classes/sun/awt/FontConfiguration.java b/src/share/classes/sun/awt/FontConfiguration.java index a2593cc2ff5ea98ebcfdc4e96b92ff5c8ab9736c..ba8f6e56a014f0b9a254cf917361293e572541de 100644 --- a/src/share/classes/sun/awt/FontConfiguration.java +++ b/src/share/classes/sun/awt/FontConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,10 +37,10 @@ import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; -import java.util.Iterator; import java.util.Locale; import java.util.Map.Entry; import java.util.Properties; @@ -329,6 +329,8 @@ public abstract class FontConfiguration { * tables. */ public static void saveBinary(OutputStream out) throws IOException { + sanityCheck(); + DataOutputStream dataOut = new DataOutputStream(out); writeShortTable(dataOut, head); writeShortTable(dataOut, table_scriptIDs); @@ -350,7 +352,6 @@ public abstract class FontConfiguration { if (verbose) { dump(); } - sanityCheck(); } //private static boolean loadingProperties; @@ -1343,6 +1344,11 @@ public abstract class FontConfiguration { private static short[] table_stringIDs; private static char[] table_stringTable; + /** + * Checks consistencies of complied fontconfig data. This method + * is called only at the build-time from + * build.tools.compilefontconfig.CompileFontConfig. + */ private static void sanityCheck() { int errors = 0; @@ -1358,12 +1364,20 @@ public abstract class FontConfiguration { //componentFontNameID starts from "1" for (int ii = 1; ii < table_filenames.length; ii++) { if (table_filenames[ii] == -1) { - System.out.println("\n Warning: " - + " entry is missing!!!"); - if (!osName.contains("Linux")) { + // The corresponding finename entry for a component + // font name is mandatory on Windows, but it's + // optional on Solaris and Linux. + if (osName.contains("Windows")) { + System.err.println("\n Error: entry is missing!!!"); errors++; + } else { + if (verbose && !isEmpty(table_filenames)) { + System.err.println("\n Note: 'filename' entry is undefined for \"" + + getString(table_componentFontNameIDs[ii]) + + "\""); + } } } } @@ -1382,7 +1396,7 @@ public abstract class FontConfiguration { int jj = iii * NUM_STYLES + iij; short ffid = table_scriptFonts[fid + jj]; if (ffid == 0) { - System.out.println("\n Error: <" + System.err.println("\n Error: <" + getFontName(iii) + "." + getStyleName(iij) + "." + getString(table_scriptIDs[ii]) @@ -1402,7 +1416,7 @@ public abstract class FontConfiguration { script.contains("symbol")) { continue; } - System.out.println("\nError: " + System.err.println("\nError: " + " entry is missing!!!"); @@ -1411,11 +1425,19 @@ public abstract class FontConfiguration { } } if (errors != 0) { - System.out.println("!!THERE ARE " + errors + " ERROR(S) IN " + System.err.println("!!THERE ARE " + errors + " ERROR(S) IN " + "THE FONTCONFIG FILE, PLEASE CHECK ITS CONTENT!!\n"); System.exit(1); + } + } + private static boolean isEmpty(short[] a) { + for (short s : a) { + if (s != -1) { + return false; + } } + return true; } //dump the fontconfig data tables @@ -1652,20 +1674,16 @@ public abstract class FontConfiguration { private static void writeShortTable(DataOutputStream out, short[] data) throws IOException { - for (int i = 0; i < data.length; i++) { - out.writeShort(data[i]); + for (short val : data) { + out.writeShort(val); } } - private static short[] toList(HashMap map) { + private static short[] toList(HashMap map) { short[] list = new short[map.size()]; - for (int i = 0; i < list.length; i++) { - list[i] = -1; - } - Iterator iterator = map.entrySet().iterator(); - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); - list[entry.getValue().shortValue()] = getStringID(entry.getKey()); + Arrays.fill(list, (short) -1); + for (Entry entry : map.entrySet()) { + list[entry.getValue()] = getStringID(entry.getKey()); } return list; } @@ -1763,25 +1781,19 @@ public abstract class FontConfiguration { int len = table_scriptIDs.length + scriptFonts.size() * 20; table_scriptFonts = new short[len]; - Iterator iterator = scriptAllfonts.entrySet().iterator(); - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); - table_scriptFonts[entry.getKey().intValue()] = (short)entry.getValue().shortValue(); + for (Entry entry : scriptAllfonts.entrySet()) { + table_scriptFonts[entry.getKey().intValue()] = entry.getValue(); } int off = table_scriptIDs.length; - iterator = scriptFonts.entrySet().iterator(); - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); + for (Entry entry : scriptFonts.entrySet()) { table_scriptFonts[entry.getKey().intValue()] = (short)-off; Short[] v = entry.getValue(); - int i = 0; - while (i < 20) { + for (int i = 0; i < 20; i++) { if (v[i] != null) { - table_scriptFonts[off++] = v[i].shortValue(); + table_scriptFonts[off++] = v[i]; } else { table_scriptFonts[off++] = 0; } - i++; } } @@ -1792,9 +1804,7 @@ public abstract class FontConfiguration { //(3) sequences elcID -> XXXX[1|5] -> scriptID[] head[INDEX_sequences] = (short)(head[INDEX_elcIDs] + table_elcIDs.length); table_sequences = new short[elcIDs.size() * NUM_FONTS]; - iterator = sequences.entrySet().iterator(); - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); + for (Entry entry : sequences.entrySet()) { //table_sequences[entry.getKey().intValue()] = (short)-off; int k = entry.getKey().intValue(); short[] v = entry.getValue(); @@ -1827,31 +1837,24 @@ public abstract class FontConfiguration { //(6)componentFontNameID -> filenameID head[INDEX_filenames] = (short)(head[INDEX_componentFontNameIDs] + table_componentFontNameIDs.length); table_filenames = new short[table_componentFontNameIDs.length]; - for (int i = 0; i < table_filenames.length; i++) { - table_filenames[i] = -1; - } - iterator = filenames.entrySet().iterator(); - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); - table_filenames[entry.getKey().shortValue()] = entry.getValue().shortValue(); + Arrays.fill(table_filenames, (short) -1); + + for (Entry entry : filenames.entrySet()) { + table_filenames[entry.getKey()] = entry.getValue(); } //(7)scriptID-> awtfontpath //the paths are stored as scriptID -> stringID in awtfontpahts head[INDEX_awtfontpaths] = (short)(head[INDEX_filenames] + table_filenames.length); table_awtfontpaths = new short[table_scriptIDs.length]; - iterator = awtfontpaths.entrySet().iterator(); - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); - table_awtfontpaths[entry.getKey().shortValue()] = entry.getValue().shortValue(); + for (Entry entry : awtfontpaths.entrySet()) { + table_awtfontpaths[entry.getKey()] = entry.getValue(); } //(8)exclusions head[INDEX_exclusions] = (short)(head[INDEX_awtfontpaths] + table_awtfontpaths.length); table_exclusions = new short[scriptIDs.size()]; - iterator = exclusions.entrySet().iterator(); - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); + for (Entry entry : exclusions.entrySet()) { int[] exI = entry.getValue(); char[] exC = new char[exI.length * 2]; int j = 0; @@ -1859,17 +1862,15 @@ public abstract class FontConfiguration { exC[j++] = (char) (exI[i] >> 16); exC[j++] = (char) (exI[i] & 0xffff); } - table_exclusions[entry.getKey().shortValue()] = getStringID(new String (exC)); + table_exclusions[entry.getKey()] = getStringID(new String (exC)); } //(9)proportionals head[INDEX_proportionals] = (short)(head[INDEX_exclusions] + table_exclusions.length); table_proportionals = new short[proportionals.size() * 2]; - iterator = proportionals.entrySet().iterator(); int j = 0; - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); - table_proportionals[j++] = entry.getKey().shortValue(); - table_proportionals[j++] = entry.getValue().shortValue(); + for (Entry entry : proportionals.entrySet()) { + table_proportionals[j++] = entry.getKey(); + table_proportionals[j++] = entry.getValue(); } //(10) see (1) for info, the only difference is "xxx.motif" @@ -1878,22 +1879,18 @@ public abstract class FontConfiguration { len = table_scriptIDs.length + scriptFontsMotif.size() * 20; table_scriptFontsMotif = new short[len]; - iterator = scriptAllfontsMotif.entrySet().iterator(); - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); + for (Entry entry : scriptAllfontsMotif.entrySet()) { table_scriptFontsMotif[entry.getKey().intValue()] = - (short)entry.getValue().shortValue(); + (short)entry.getValue(); } off = table_scriptIDs.length; - iterator = scriptFontsMotif.entrySet().iterator(); - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); + for (Entry entry : scriptFontsMotif.entrySet()) { table_scriptFontsMotif[entry.getKey().intValue()] = (short)-off; Short[] v = entry.getValue(); int i = 0; while (i < 20) { if (v[i] != null) { - table_scriptFontsMotif[off++] = v[i].shortValue(); + table_scriptFontsMotif[off++] = v[i]; } else { table_scriptFontsMotif[off++] = 0; } @@ -1907,12 +1904,10 @@ public abstract class FontConfiguration { //(11)short[] alphabeticSuffix head[INDEX_alphabeticSuffix] = (short)(head[INDEX_scriptFontsMotif] + table_scriptFontsMotif.length); table_alphabeticSuffix = new short[alphabeticSuffix.size() * 2]; - iterator = alphabeticSuffix.entrySet().iterator(); j = 0; - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); - table_alphabeticSuffix[j++] = entry.getKey().shortValue(); - table_alphabeticSuffix[j++] = entry.getValue().shortValue(); + for (Entry entry : alphabeticSuffix.entrySet()) { + table_alphabeticSuffix[j++] = entry.getKey(); + table_alphabeticSuffix[j++] = entry.getValue(); } //(15)short[] fallbackScriptIDs; just put the ID in head diff --git a/src/share/classes/sun/awt/SunToolkit.java b/src/share/classes/sun/awt/SunToolkit.java index 58ff2860b90ef10d61710aad42cfb51d77462518..0442aeeaba61a4ab268516ffd2769104fe63469b 100644 --- a/src/share/classes/sun/awt/SunToolkit.java +++ b/src/share/classes/sun/awt/SunToolkit.java @@ -102,26 +102,6 @@ public abstract class SunToolkit extends Toolkit public final static int MAX_BUTTONS_SUPPORTED = 20; public SunToolkit() { - /* If awt.threadgroup is set to class name the instance of - * this class is created (should be subclass of ThreadGroup) - * and EventDispatchThread is created inside of it - * - * If loaded class overrides uncaughtException instance - * handles all uncaught exception on EventDispatchThread - */ - ThreadGroup threadGroup = null; - String tgName = System.getProperty("awt.threadgroup", ""); - - if (tgName.length() != 0) { - try { - Constructor ctor = Class.forName(tgName). - getConstructor(new Class[] {String.class}); - threadGroup = (ThreadGroup)ctor.newInstance(new Object[] {"AWT-ThreadGroup"}); - } catch (Exception e) { - System.err.println("Failed loading " + tgName + ": " + e); - } - } - Runnable initEQ = new Runnable() { public void run () { EventQueue eventQueue; @@ -144,17 +124,7 @@ public abstract class SunToolkit extends Toolkit } }; - if (threadGroup != null) { - Thread eqInitThread = new Thread(threadGroup, initEQ, "EventQueue-Init"); - eqInitThread.start(); - try { - eqInitThread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } else { - initEQ.run(); - } + initEQ.run(); } public boolean useBufferPerWindow() { diff --git a/src/share/classes/sun/dc/DuctusRenderingEngine.java b/src/share/classes/sun/dc/DuctusRenderingEngine.java index 61f9b3923a865887a4d3d922107faaaa8a53b137..b39c4686d6c4da8df11c89baf0e220a18526cb44 100644 --- a/src/share/classes/sun/dc/DuctusRenderingEngine.java +++ b/src/share/classes/sun/dc/DuctusRenderingEngine.java @@ -635,6 +635,88 @@ public class DuctusRenderingEngine extends RenderingEngine { return r; } + /** + * {@inheritDoc} + */ + @Override + public AATileGenerator getAATileGenerator(double x, double y, + double dx1, double dy1, + double dx2, double dy2, + double lw1, double lw2, + Region clip, + int bbox[]) + { + // REMIND: Deal with large coordinates! + double ldx1, ldy1, ldx2, ldy2; + boolean innerpgram = (lw1 > 0 && lw2 > 0); + + if (innerpgram) { + ldx1 = dx1 * lw1; + ldy1 = dy1 * lw1; + ldx2 = dx2 * lw2; + ldy2 = dy2 * lw2; + x -= (ldx1 + ldx2) / 2.0; + y -= (ldy1 + ldy2) / 2.0; + dx1 += ldx1; + dy1 += ldy1; + dx2 += ldx2; + dy2 += ldy2; + if (lw1 > 1 && lw2 > 1) { + // Inner parallelogram was entirely consumed by stroke... + innerpgram = false; + } + } else { + ldx1 = ldy1 = ldx2 = ldy2 = 0; + } + + Rasterizer r = getRasterizer(); + + r.setUsage(Rasterizer.EOFILL); + + r.beginPath(); + r.beginSubpath((float) x, (float) y); + r.appendLine((float) (x+dx1), (float) (y+dy1)); + r.appendLine((float) (x+dx1+dx2), (float) (y+dy1+dy2)); + r.appendLine((float) (x+dx2), (float) (y+dy2)); + r.closedSubpath(); + if (innerpgram) { + x += ldx1 + ldx2; + y += ldy1 + ldy2; + dx1 -= 2.0 * ldx1; + dy1 -= 2.0 * ldy1; + dx2 -= 2.0 * ldx2; + dy2 -= 2.0 * ldy2; + r.beginSubpath((float) x, (float) y); + r.appendLine((float) (x+dx1), (float) (y+dy1)); + r.appendLine((float) (x+dx1+dx2), (float) (y+dy1+dy2)); + r.appendLine((float) (x+dx2), (float) (y+dy2)); + r.closedSubpath(); + } + + try { + r.endPath(); + r.getAlphaBox(bbox); + clip.clipBoxToBounds(bbox); + if (bbox[0] >= bbox[2] || bbox[1] >= bbox[3]) { + dropRasterizer(r); + return null; + } + r.setOutputArea(bbox[0], bbox[1], + bbox[2] - bbox[0], + bbox[3] - bbox[1]); + } catch (PRException e) { + /* + * This exeption is thrown from the native part of the Ductus + * (only in case of a debug build) to indicate that some + * segments of the path have very large coordinates. + * See 4485298 for more info. + */ + System.err.println("DuctusRenderingEngine.getAATileGenerator: "+e); + } + + return r; + } + private void feedConsumer(PathConsumer consumer, PathIterator pi) { try { consumer.beginPath(); diff --git a/src/share/classes/sun/font/FileFontStrike.java b/src/share/classes/sun/font/FileFontStrike.java index ce4d87c2a99afc874d63fc99ebee6e3c62d3eb4b..ae6045f696cb7fbfc369a51da14b46ec94e4481f 100644 --- a/src/share/classes/sun/font/FileFontStrike.java +++ b/src/share/classes/sun/font/FileFontStrike.java @@ -58,10 +58,10 @@ public class FileFontStrike extends PhysicalStrike { private static final int SEGINTARRAY = 3; private static final int SEGLONGARRAY = 4; - private int glyphCacheFormat = UNINITIALISED; + private volatile int glyphCacheFormat = UNINITIALISED; - /* segmented arrays are blocks of 256 */ - private static final int SEGSHIFT = 8; + /* segmented arrays are blocks of 32 */ + private static final int SEGSHIFT = 5; private static final int SEGSIZE = 1 << SEGSHIFT; private boolean segmentedCache; @@ -171,7 +171,7 @@ public class FileFontStrike extends PhysicalStrike { mapper = fileFont.getMapper(); int numGlyphs = mapper.getNumGlyphs(); - /* Always segment for fonts with > 2K glyphs, but also for smaller + /* Always segment for fonts with > 256 glyphs, but also for smaller * fonts with non-typical sizes and transforms. * Segmenting for all non-typical pt sizes helps to minimise memory * usage when very many distinct strikes are created. @@ -522,32 +522,33 @@ public class FileFontStrike extends PhysicalStrike { } /* Called only from synchronized code or constructor */ - private void initGlyphCache() { + private synchronized void initGlyphCache() { int numGlyphs = mapper.getNumGlyphs(); - + int tmpFormat = UNINITIALISED; if (segmentedCache) { int numSegments = (numGlyphs + SEGSIZE-1)/SEGSIZE; if (longAddresses) { - glyphCacheFormat = SEGLONGARRAY; + tmpFormat = SEGLONGARRAY; segLongGlyphImages = new long[numSegments][]; this.disposer.segLongGlyphImages = segLongGlyphImages; } else { - glyphCacheFormat = SEGINTARRAY; + tmpFormat = SEGINTARRAY; segIntGlyphImages = new int[numSegments][]; this.disposer.segIntGlyphImages = segIntGlyphImages; } } else { if (longAddresses) { - glyphCacheFormat = LONGARRAY; + tmpFormat = LONGARRAY; longGlyphImages = new long[numGlyphs]; this.disposer.longGlyphImages = longGlyphImages; } else { - glyphCacheFormat = INTARRAY; + tmpFormat = INTARRAY; intGlyphImages = new int[numGlyphs]; this.disposer.intGlyphImages = intGlyphImages; } } + glyphCacheFormat = tmpFormat; } float getGlyphAdvance(int glyphCode) { diff --git a/src/share/classes/sun/font/Font2D.java b/src/share/classes/sun/font/Font2D.java index 3fab32c8434b3f1e39e7f581f2a4bdacf7d0a80d..b78292722b5dff5ff9ae1e3a42f43647e266284b 100644 --- a/src/share/classes/sun/font/Font2D.java +++ b/src/share/classes/sun/font/Font2D.java @@ -343,7 +343,21 @@ public abstract class Font2D { } strike = createStrike(desc); //StrikeCache.addStrike(); - strikeRef = StrikeCache.getStrikeRef(strike); + /* If we are creating many strikes on this font which + * involve non-quadrant rotations, or more general + * transforms which include shears, then force the use + * of weak references rather than soft references. + * This means that it won't live much beyond the next GC, + * which is what we want for what is likely a transient strike. + */ + int txType = desc.glyphTx.getType(); + if (txType == AffineTransform.TYPE_GENERAL_TRANSFORM || + (txType & AffineTransform.TYPE_GENERAL_ROTATION) != 0 && + strikeCache.size() > 10) { + strikeRef = StrikeCache.getStrikeRef(strike, true); + } else { + strikeRef = StrikeCache.getStrikeRef(strike); + } strikeCache.put(desc, strikeRef); //strike.lastlookupTime = System.currentTimeMillis(); lastFontStrike = new SoftReference(strike); diff --git a/src/share/classes/sun/java2d/SurfaceData.java b/src/share/classes/sun/java2d/SurfaceData.java index 55bb05e46c4458ae067252b9452f645f2fe3f55e..9916c5b38a8d7059344d80c98f755d8dfb16ae3b 100644 --- a/src/share/classes/sun/java2d/SurfaceData.java +++ b/src/share/classes/sun/java2d/SurfaceData.java @@ -367,16 +367,17 @@ public abstract class SurfaceData public static final TextPipe aaTextRenderer; public static final TextPipe lcdTextRenderer; - protected static final CompositePipe colorPipe; + protected static final AlphaColorPipe colorPipe; protected static final PixelToShapeConverter colorViaShape; protected static final PixelToParallelogramConverter colorViaPgram; protected static final TextPipe colorText; protected static final CompositePipe clipColorPipe; protected static final TextPipe clipColorText; protected static final AAShapePipe AAColorShape; - protected static final PixelToShapeConverter AAColorViaShape; + protected static final PixelToParallelogramConverter AAColorViaShape; + protected static final PixelToParallelogramConverter AAColorViaPgram; protected static final AAShapePipe AAClipColorShape; - protected static final PixelToShapeConverter AAClipColorViaShape; + protected static final PixelToParallelogramConverter AAClipColorViaShape; protected static final CompositePipe paintPipe; protected static final SpanShapeRenderer paintShape; @@ -385,9 +386,9 @@ public abstract class SurfaceData protected static final CompositePipe clipPaintPipe; protected static final TextPipe clipPaintText; protected static final AAShapePipe AAPaintShape; - protected static final PixelToShapeConverter AAPaintViaShape; + protected static final PixelToParallelogramConverter AAPaintViaShape; protected static final AAShapePipe AAClipPaintShape; - protected static final PixelToShapeConverter AAClipPaintViaShape; + protected static final PixelToParallelogramConverter AAClipPaintViaShape; protected static final CompositePipe compPipe; protected static final SpanShapeRenderer compShape; @@ -396,9 +397,9 @@ public abstract class SurfaceData protected static final CompositePipe clipCompPipe; protected static final TextPipe clipCompText; protected static final AAShapePipe AACompShape; - protected static final PixelToShapeConverter AACompViaShape; + protected static final PixelToParallelogramConverter AACompViaShape; protected static final AAShapePipe AAClipCompShape; - protected static final PixelToShapeConverter AAClipCompViaShape; + protected static final PixelToParallelogramConverter AAClipCompViaShape; protected static final DrawImagePipe imagepipe; @@ -427,6 +428,22 @@ public abstract class SurfaceData } } + private static PixelToParallelogramConverter + makeConverter(AAShapePipe renderer, + ParallelogramPipe pgrampipe) + { + return new PixelToParallelogramConverter(renderer, + pgrampipe, + 1.0/8.0, 0.499, + false); + } + + private static PixelToParallelogramConverter + makeConverter(AAShapePipe renderer) + { + return makeConverter(renderer, renderer); + } + static { colorPrimitives = new LoopPipe(); @@ -445,9 +462,10 @@ public abstract class SurfaceData clipColorPipe = new SpanClipRenderer(colorPipe); clipColorText = new TextRenderer(clipColorPipe); AAColorShape = new AAShapePipe(colorPipe); - AAColorViaShape = new PixelToShapeConverter(AAColorShape); + AAColorViaShape = makeConverter(AAColorShape); + AAColorViaPgram = makeConverter(AAColorShape, colorPipe); AAClipColorShape = new AAShapePipe(clipColorPipe); - AAClipColorViaShape = new PixelToShapeConverter(AAClipColorShape); + AAClipColorViaShape = makeConverter(AAClipColorShape); paintPipe = new AlphaPaintPipe(); paintShape = new SpanShapeRenderer.Composite(paintPipe); @@ -456,9 +474,9 @@ public abstract class SurfaceData clipPaintPipe = new SpanClipRenderer(paintPipe); clipPaintText = new TextRenderer(clipPaintPipe); AAPaintShape = new AAShapePipe(paintPipe); - AAPaintViaShape = new PixelToShapeConverter(AAPaintShape); + AAPaintViaShape = makeConverter(AAPaintShape); AAClipPaintShape = new AAShapePipe(clipPaintPipe); - AAClipPaintViaShape = new PixelToShapeConverter(AAClipPaintShape); + AAClipPaintViaShape = makeConverter(AAClipPaintShape); compPipe = new GeneralCompositePipe(); compShape = new SpanShapeRenderer.Composite(compPipe); @@ -467,9 +485,9 @@ public abstract class SurfaceData clipCompPipe = new SpanClipRenderer(compPipe); clipCompText = new TextRenderer(clipCompPipe); AACompShape = new AAShapePipe(compPipe); - AACompViaShape = new PixelToShapeConverter(AACompShape); + AACompViaShape = makeConverter(AACompShape); AAClipCompShape = new AAShapePipe(clipCompPipe); - AAClipCompViaShape = new PixelToShapeConverter(AAClipCompShape); + AAClipCompViaShape = makeConverter(AAClipCompShape); imagepipe = new DrawImage(); } @@ -591,12 +609,12 @@ public abstract class SurfaceData if (sg2d.clipState == sg2d.CLIP_SHAPE) { sg2d.drawpipe = AAClipCompViaShape; sg2d.fillpipe = AAClipCompViaShape; - sg2d.shapepipe = AAClipCompShape; + sg2d.shapepipe = AAClipCompViaShape; sg2d.textpipe = clipCompText; } else { sg2d.drawpipe = AACompViaShape; sg2d.fillpipe = AACompViaShape; - sg2d.shapepipe = AACompShape; + sg2d.shapepipe = AACompViaShape; sg2d.textpipe = compText; } } else { @@ -616,13 +634,17 @@ public abstract class SurfaceData if (sg2d.clipState == sg2d.CLIP_SHAPE) { sg2d.drawpipe = AAClipColorViaShape; sg2d.fillpipe = AAClipColorViaShape; - sg2d.shapepipe = AAClipColorShape; + sg2d.shapepipe = AAClipColorViaShape; sg2d.textpipe = clipColorText; } else { - sg2d.drawpipe = AAColorViaShape; - sg2d.fillpipe = AAColorViaShape; - sg2d.shapepipe = AAColorShape; - if (sg2d.paintState > sg2d.PAINT_OPAQUECOLOR || + PixelToParallelogramConverter converter = + (sg2d.alphafill.canDoParallelograms() + ? AAColorViaPgram + : AAColorViaShape); + sg2d.drawpipe = converter; + sg2d.fillpipe = converter; + sg2d.shapepipe = converter; + if (sg2d.paintState > sg2d.PAINT_ALPHACOLOR || sg2d.compositeState > sg2d.COMP_ISCOPY) { sg2d.textpipe = colorText; @@ -634,12 +656,12 @@ public abstract class SurfaceData if (sg2d.clipState == sg2d.CLIP_SHAPE) { sg2d.drawpipe = AAClipPaintViaShape; sg2d.fillpipe = AAClipPaintViaShape; - sg2d.shapepipe = AAClipPaintShape; + sg2d.shapepipe = AAClipPaintViaShape; sg2d.textpipe = clipPaintText; } else { sg2d.drawpipe = AAPaintViaShape; sg2d.fillpipe = AAPaintViaShape; - sg2d.shapepipe = AAPaintShape; + sg2d.shapepipe = AAPaintViaShape; sg2d.textpipe = paintText; } } @@ -793,6 +815,18 @@ public abstract class SurfaceData } } + private static CompositeType getFillCompositeType(SunGraphics2D sg2d) { + CompositeType compType = sg2d.imageComp; + if (sg2d.compositeState == sg2d.COMP_ISCOPY) { + if (compType == CompositeType.SrcOverNoEa) { + compType = CompositeType.OpaqueSrcOverNoEa; + } else { + compType = CompositeType.SrcNoEa; + } + } + return compType; + } + /** * Returns a MaskFill object that can be used on this destination * with the source (paint) and composite types determined by the given @@ -802,9 +836,10 @@ public abstract class SurfaceData * surface) before returning a specific MaskFill object. */ protected MaskFill getMaskFill(SunGraphics2D sg2d) { - return MaskFill.getFromCache(getPaintSurfaceType(sg2d), - sg2d.imageComp, - getSurfaceType()); + SurfaceType src = getPaintSurfaceType(sg2d); + CompositeType comp = getFillCompositeType(sg2d); + SurfaceType dst = getSurfaceType(); + return MaskFill.getFromCache(src, comp, dst); } private static RenderCache loopcache = new RenderCache(30); @@ -816,9 +851,7 @@ public abstract class SurfaceData */ public RenderLoops getRenderLoops(SunGraphics2D sg2d) { SurfaceType src = getPaintSurfaceType(sg2d); - CompositeType comp = (sg2d.compositeState == sg2d.COMP_ISCOPY - ? CompositeType.SrcNoEa - : sg2d.imageComp); + CompositeType comp = getFillCompositeType(sg2d); SurfaceType dst = sg2d.getSurfaceData().getSurfaceType(); Object o = loopcache.get(src, comp, dst); diff --git a/src/share/classes/sun/java2d/loops/CompositeType.java b/src/share/classes/sun/java2d/loops/CompositeType.java index 7c47cb3cae8eaa23b5038659f7888b92243460dc..ec6d6d8064c58d3f946a4e043b7db8c4d98d5c04 100644 --- a/src/share/classes/sun/java2d/loops/CompositeType.java +++ b/src/share/classes/sun/java2d/loops/CompositeType.java @@ -27,6 +27,7 @@ package sun.java2d.loops; import java.awt.image.BufferedImage; import java.awt.AlphaComposite; +import java.util.HashMap; /** * A CompositeType object provides a chained description of a type of @@ -51,6 +52,11 @@ import java.awt.AlphaComposite; * the indicated algorithm if all of the more specific searches fail. */ public final class CompositeType { + + private static int unusedUID = 1; + private static final HashMap compositeUIDMap = + new HashMap(100); + /* * CONSTANTS USED BY ALL PRIMITIVES TO DESCRIBE THE COMPOSITING * ALGORITHMS THEY CAN PERFORM @@ -152,6 +158,22 @@ public final class CompositeType { public static final CompositeType SrcOverNoEa = SrcOver.deriveSubType(DESC_SRC_OVER_NO_EA); + /* + * A special CompositeType for the case where we are filling in + * SrcOverNoEa mode with an opaque color. In that case then the + * best loop for us to use would be a SrcNoEa loop, but what if + * there is no such loop? In that case then we would end up + * backing off to a Src loop (which should still be fine) or an + * AnyAlpha loop which would be slower than a SrcOver loop in + * most cases. + * The fix is to use the following chain which looks for loops + * in the following order: + * SrcNoEa, Src, SrcOverNoEa, SrcOver, AnyAlpha + */ + public static final CompositeType + OpaqueSrcOverNoEa = SrcOverNoEa.deriveSubType(DESC_SRC) + .deriveSubType(DESC_SRC_NO_EA); + /* * END OF CompositeType OBJECTS FOR THE VARIOUS CONSTANTS */ @@ -210,7 +232,6 @@ public final class CompositeType { } } - private static int unusedUID = 1; private int uniqueID; private String desc; private CompositeType next; @@ -218,14 +239,20 @@ public final class CompositeType { private CompositeType(CompositeType parent, String desc) { next = parent; this.desc = desc; - this.uniqueID = makeUniqueID(); + this.uniqueID = makeUniqueID(desc); } - private synchronized static final int makeUniqueID() { - if (unusedUID > 255) { - throw new InternalError("composite type id overflow"); + public synchronized static final int makeUniqueID(String desc) { + Integer i = compositeUIDMap.get(desc); + + if (i == null) { + if (unusedUID > 255) { + throw new InternalError("composite type id overflow"); + } + i = unusedUID++; + compositeUIDMap.put(desc, i); } - return unusedUID++; + return i; } public int getUniqueID() { diff --git a/src/share/classes/sun/java2d/loops/MaskFill.java b/src/share/classes/sun/java2d/loops/MaskFill.java index f3807ffd8bd855b4d845a93d2e30676612e7b290..557da13c848117679fc378c909f725547eb1e5a7 100644 --- a/src/share/classes/sun/java2d/loops/MaskFill.java +++ b/src/share/classes/sun/java2d/loops/MaskFill.java @@ -50,6 +50,10 @@ import sun.java2d.SurfaceData; public class MaskFill extends GraphicsPrimitive { public static final String methodSignature = "MaskFill(...)".toString(); + public static final String fillPgramSignature = + "FillAAPgram(...)".toString(); + public static final String drawPgramSignature = + "DrawAAPgram(...)".toString(); public static final int primTypeID = makePrimTypeID(); @@ -92,6 +96,14 @@ public class MaskFill extends GraphicsPrimitive return fill; } + protected MaskFill(String alternateSignature, + SurfaceType srctype, + CompositeType comptype, + SurfaceType dsttype) + { + super(alternateSignature, primTypeID, srctype, comptype, dsttype); + } + protected MaskFill(SurfaceType srctype, CompositeType comptype, SurfaceType dsttype) @@ -115,6 +127,23 @@ public class MaskFill extends GraphicsPrimitive int x, int y, int w, int h, byte[] mask, int maskoff, int maskscan); + public native void FillAAPgram(SunGraphics2D sg2d, SurfaceData sData, + Composite comp, + double x, double y, + double dx1, double dy1, + double dx2, double dy2); + + public native void DrawAAPgram(SunGraphics2D sg2d, SurfaceData sData, + Composite comp, + double x, double y, + double dx1, double dy1, + double dx2, double dy2, + double lw1, double lw2); + + public boolean canDoParallelograms() { + return (getNativePrim() != 0); + } + static { GraphicsPrimitiveMgr.registerGeneral(new MaskFill(null, null, null)); } @@ -182,12 +211,22 @@ public class MaskFill extends GraphicsPrimitive private static class TraceMaskFill extends MaskFill { MaskFill target; + MaskFill fillPgramTarget; + MaskFill drawPgramTarget; public TraceMaskFill(MaskFill target) { super(target.getSourceType(), target.getCompositeType(), target.getDestType()); this.target = target; + this.fillPgramTarget = new MaskFill(fillPgramSignature, + target.getSourceType(), + target.getCompositeType(), + target.getDestType()); + this.drawPgramTarget = new MaskFill(drawPgramSignature, + target.getSourceType(), + target.getCompositeType(), + target.getDestType()); } public GraphicsPrimitive traceWrap() { @@ -203,5 +242,32 @@ public class MaskFill extends GraphicsPrimitive target.MaskFill(sg2d, sData, comp, x, y, w, h, mask, maskoff, maskscan); } + + public void FillAAPgram(SunGraphics2D sg2d, SurfaceData sData, + Composite comp, + double x, double y, + double dx1, double dy1, + double dx2, double dy2) + { + tracePrimitive(fillPgramTarget); + target.FillAAPgram(sg2d, sData, comp, + x, y, dx1, dy1, dx2, dy2); + } + + public void DrawAAPgram(SunGraphics2D sg2d, SurfaceData sData, + Composite comp, + double x, double y, + double dx1, double dy1, + double dx2, double dy2, + double lw1, double lw2) + { + tracePrimitive(drawPgramTarget); + target.DrawAAPgram(sg2d, sData, comp, + x, y, dx1, dy1, dx2, dy2, lw1, lw2); + } + + public boolean canDoParallelograms() { + return target.canDoParallelograms(); + } } } diff --git a/src/share/classes/sun/java2d/pipe/AAShapePipe.java b/src/share/classes/sun/java2d/pipe/AAShapePipe.java index 9edff382b0f9225357d931b6d70dac7722c741e3..8654bede25c0089b933f6a1b6bc6b85b48ccb04f 100644 --- a/src/share/classes/sun/java2d/pipe/AAShapePipe.java +++ b/src/share/classes/sun/java2d/pipe/AAShapePipe.java @@ -28,6 +28,7 @@ package sun.java2d.pipe; import java.awt.BasicStroke; import java.awt.Rectangle; import java.awt.Shape; +import java.awt.geom.Rectangle2D; import java.awt.geom.PathIterator; import sun.awt.SunHints; import sun.java2d.SunGraphics2D; @@ -39,7 +40,9 @@ import sun.java2d.SunGraphics2D; * This class sets up the Generator and computes the alpha tiles * and then passes them on to a CompositePipe object for painting. */ -public class AAShapePipe implements ShapeDrawPipe { +public class AAShapePipe + implements ShapeDrawPipe, ParallelogramPipe +{ static RenderingEngine renderengine = RenderingEngine.getInstance(); CompositePipe outpipe; @@ -65,6 +68,59 @@ public class AAShapePipe implements ShapeDrawPipe { renderPath(sg, s, null); } + private static Rectangle2D computeBBox(double x, double y, + double dx1, double dy1, + double dx2, double dy2) + { + double lox, loy, hix, hiy; + lox = hix = x; + loy = hiy = y; + if (dx1 < 0) { lox += dx1; } else { hix += dx1; } + if (dy1 < 0) { loy += dy1; } else { hiy += dy1; } + if (dx2 < 0) { lox += dx2; } else { hix += dx2; } + if (dy2 < 0) { loy += dy2; } else { hiy += dy2; } + return new Rectangle2D.Double(lox, loy, hix-lox, hiy-loy); + } + + public void fillParallelogram(SunGraphics2D sg, + double x, double y, + double dx1, double dy1, + double dx2, double dy2) + { + Region clip = sg.getCompClip(); + int abox[] = new int[4]; + AATileGenerator aatg = + renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, 0, 0, + clip, abox); + if (aatg == null) { + // Nothing to render + return; + } + + renderTiles(sg, computeBBox(x, y, dx1, dy1, dx2, dy2), aatg, abox); + } + + public void drawParallelogram(SunGraphics2D sg, + double x, double y, + double dx1, double dy1, + double dx2, double dy2, + double lw1, double lw2) + { + Region clip = sg.getCompClip(); + int abox[] = new int[4]; + AATileGenerator aatg = + renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, 0, 0, + clip, abox); + if (aatg == null) { + // Nothing to render + return; + } + + // Note that bbox is of the original shape, not the wide path. + // This is appropriate for handing to Paint methods... + renderTiles(sg, computeBBox(x, y, dx1, dy1, dx2, dy2), aatg, abox); + } + private static byte[] theTile; public synchronized static byte[] getAlphaTile(int len) { @@ -85,8 +141,6 @@ public class AAShapePipe implements ShapeDrawPipe { boolean adjust = (bs != null && sg.strokeHint != SunHints.INTVAL_STROKE_PURE); boolean thin = (sg.strokeState <= sg.STROKE_THINDASHED); - Object context = null; - byte alpha[] = null; Region clip = sg.getCompClip(); int abox[] = new int[4]; @@ -98,6 +152,14 @@ public class AAShapePipe implements ShapeDrawPipe { return; } + renderTiles(sg, s, aatg, abox); + } + + public void renderTiles(SunGraphics2D sg, Shape s, + AATileGenerator aatg, int abox[]) + { + Object context = null; + byte alpha[] = null; try { context = outpipe.startSequence(sg, s, new Rectangle(abox[0], abox[1], diff --git a/src/share/classes/sun/java2d/pipe/AlphaColorPipe.java b/src/share/classes/sun/java2d/pipe/AlphaColorPipe.java index 28c335307ba4b490d24b07cdc27a7c003f339fd2..745bdf9bc5a2c220e319c57c9ba2a3d69329ea03 100644 --- a/src/share/classes/sun/java2d/pipe/AlphaColorPipe.java +++ b/src/share/classes/sun/java2d/pipe/AlphaColorPipe.java @@ -34,7 +34,7 @@ import sun.java2d.SunGraphics2D; * into a destination that supports direct alpha compositing of a solid * color, according to one of the rules in the AlphaComposite class. */ -public class AlphaColorPipe implements CompositePipe { +public class AlphaColorPipe implements CompositePipe, ParallelogramPipe { public AlphaColorPipe() { } @@ -64,4 +64,23 @@ public class AlphaColorPipe implements CompositePipe { public void endSequence(Object context) { return; } + + public void fillParallelogram(SunGraphics2D sg, + double x, double y, + double dx1, double dy1, + double dx2, double dy2) + { + sg.alphafill.FillAAPgram(sg, sg.getSurfaceData(), sg.composite, + x, y, dx1, dy1, dx2, dy2); + } + + public void drawParallelogram(SunGraphics2D sg, + double x, double y, + double dx1, double dy1, + double dx2, double dy2, + double lw1, double lw2) + { + sg.alphafill.DrawAAPgram(sg, sg.getSurfaceData(), sg.composite, + x, y, dx1, dy1, dx2, dy2, lw1, lw2); + } } diff --git a/src/share/classes/sun/java2d/pipe/RenderingEngine.java b/src/share/classes/sun/java2d/pipe/RenderingEngine.java index bda742fc6ec9d34594f5cdbd05fe8e948f21eca3..171da288ba3981dabef5c0c44e3e042a2c4b164a 100644 --- a/src/share/classes/sun/java2d/pipe/RenderingEngine.java +++ b/src/share/classes/sun/java2d/pipe/RenderingEngine.java @@ -280,6 +280,72 @@ public abstract class RenderingEngine { boolean normalize, int bbox[]); + /** + * Construct an antialiased tile generator for the given parallelogram + * store the bounds of the tile iteration in the bbox parameter. + * The parallelogram is specified as a starting point and 2 delta + * vectors that indicate the slopes of the 2 pairs of sides of the + * parallelogram. + * The 4 corners of the parallelogram are defined by the 4 points: + *

+ * The {@code lw1} and {@code lw2} parameters provide a specification + * for an optionally stroked parallelogram if they are positive numbers. + * The {@code lw1} parameter is the ratio of the length of the {@code dx1}, + * {@code dx2} delta vector to half of the line width in that same + * direction. + * The {@code lw2} parameter provides the same ratio for the other delta + * vector. + * If {@code lw1} and {@code lw2} are both greater than zero, then + * the parallelogram figure is doubled by both expanding and contracting + * each delta vector by its corresponding {@code lw} value. + * If either (@code lw1) or {@code lw2} are also greater than 1, then + * the inner (contracted) parallelogram disappears and the figure is + * simply a single expanded parallelogram. + * The {@code clip} parameter specifies the current clip in effect + * in device coordinates and can be used to prune the data for the + * operation, but the renderer is not required to perform any + * clipping. + *

+ * Upon returning, this method will fill the {@code bbox} parameter + * with 4 values indicating the bounds of the iteration of the + * tile generator. + * The iteration order of the tiles will be as specified by the + * pseudo-code: + *

+     *     for (y = bbox[1]; y < bbox[3]; y += tileheight) {
+     *         for (x = bbox[0]; x < bbox[2]; x += tilewidth) {
+     *         }
+     *     }
+     * 
+ * If there is no output to be rendered, this method may return + * null. + * + * @param x the X coordinate of the first corner of the parallelogram + * @param y the Y coordinate of the first corner of the parallelogram + * @param dx1 the X coordinate delta of the first leg of the parallelogram + * @param dy1 the Y coordinate delta of the first leg of the parallelogram + * @param dx2 the X coordinate delta of the second leg of the parallelogram + * @param dy2 the Y coordinate delta of the second leg of the parallelogram + * @param lw1 the line width ratio for the first leg of the parallelogram + * @param lw2 the line width ratio for the second leg of the parallelogram + * @param clip the current clip in effect in device coordinates + * @param bbox returns the bounds of the iteration + * @return the {@code AATileGenerator} instance to be consulted + * for tile coverages, or null if there is no output to render + * @since 1.7 + */ + public abstract AATileGenerator getAATileGenerator(double x, double y, + double dx1, double dy1, + double dx2, double dy2, + double lw1, double lw2, + Region clip, + int bbox[]); + /** * Returns the minimum pen width that the antialiasing rasterizer * can represent without dropouts occuring. @@ -393,5 +459,24 @@ public abstract class RenderingEngine { bs, thin, normalize, bbox); } + public AATileGenerator getAATileGenerator(double x, double y, + double dx1, double dy1, + double dx2, double dy2, + double lw1, double lw2, + Region clip, + int bbox[]) + { + System.out.println(name+".getAATileGenerator("+ + x+", "+y+", "+ + dx1+", "+dy1+", "+ + dx2+", "+dy2+", "+ + lw1+", "+lw2+", "+ + clip+")"); + return target.getAATileGenerator(x, y, + dx1, dy1, + dx2, dy2, + lw1, lw2, + clip, bbox); + } } } diff --git a/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java b/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java index 42c8e8d6c766827167872ed30a7d27e988ea3610..9684edc502326cd6072e3234b22b042fd9eb3c38 100644 --- a/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java +++ b/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java @@ -557,6 +557,69 @@ public class PiscesRenderingEngine extends RenderingEngine { return ptg; } + public AATileGenerator getAATileGenerator(double x, double y, + double dx1, double dy1, + double dx2, double dy2, + double lw1, double lw2, + Region clip, + int bbox[]) + { + // REMIND: Deal with large coordinates! + double ldx1, ldy1, ldx2, ldy2; + boolean innerpgram = (lw1 > 0 && lw2 > 0); + + if (innerpgram) { + ldx1 = dx1 * lw1; + ldy1 = dy1 * lw1; + ldx2 = dx2 * lw2; + ldy2 = dy2 * lw2; + x -= (ldx1 + ldx2) / 2.0; + y -= (ldy1 + ldy2) / 2.0; + dx1 += ldx1; + dy1 += ldy1; + dx2 += ldx2; + dy2 += ldy2; + if (lw1 > 1 && lw2 > 1) { + // Inner parallelogram was entirely consumed by stroke... + innerpgram = false; + } + } else { + ldx1 = ldy1 = ldx2 = ldy2 = 0; + } + + Renderer r = new Renderer(3, 3, + clip.getLoX(), clip.getLoY(), + clip.getWidth(), clip.getHeight(), + PathIterator.WIND_EVEN_ODD); + + r.moveTo((float) x, (float) y); + r.lineTo((float) (x+dx1), (float) (y+dy1)); + r.lineTo((float) (x+dx1+dx2), (float) (y+dy1+dy2)); + r.lineTo((float) (x+dx2), (float) (y+dy2)); + r.closePath(); + + if (innerpgram) { + x += ldx1 + ldx2; + y += ldy1 + ldy2; + dx1 -= 2.0 * ldx1; + dy1 -= 2.0 * ldy1; + dx2 -= 2.0 * ldx2; + dy2 -= 2.0 * ldy2; + r.moveTo((float) x, (float) y); + r.lineTo((float) (x+dx1), (float) (y+dy1)); + r.lineTo((float) (x+dx1+dx2), (float) (y+dy1+dy2)); + r.lineTo((float) (x+dx2), (float) (y+dy2)); + r.closePath(); + } + + r.pathDone(); + + r.endRendering(); + PiscesTileGenerator ptg = new PiscesTileGenerator(r, r.MAX_AA_ALPHA); + ptg.getBbox(bbox); + return ptg; + } + /** * Returns the minimum pen width that the antialiasing rasterizer * can represent without dropouts occuring. diff --git a/src/share/native/sun/awt/image/awt_parseImage.c b/src/share/native/sun/awt/image/awt_parseImage.c index 0a50d19755b07d498b65e82f647716de09030237..b569828f5f664a7bb3be603ed072b3b2555d3b8b 100644 --- a/src/share/native/sun/awt/image/awt_parseImage.c +++ b/src/share/native/sun/awt/image/awt_parseImage.c @@ -178,7 +178,7 @@ int awt_parseRaster(JNIEnv *env, jobject jraster, RasterS_t *rasterP) { jnbits = (*env)->GetObjectField(env, rasterP->jsampleModel, g_SPPSMnBitsID); if (jmask == NULL || joffs == NULL || jnbits == NULL || - rasterP->sppsm.maxBitSize < 0 || rasterP->sppsm.maxBitSize > 8) + rasterP->sppsm.maxBitSize < 0) { JNU_ThrowInternalError(env, "Can't grab SPPSM fields"); return -1; @@ -280,6 +280,17 @@ int awt_parseRaster(JNIEnv *env, jobject jraster, RasterS_t *rasterP) { rasterP->chanOffsets); } + /* additioanl check for sppsm fields validity: make sure that + * size of raster samples doesn't exceed the data type cpacity. + */ + if (rasterP->dataType > UNKNOWN_DATA_TYPE && /* data type has been recognized */ + rasterP->sppsm.maxBitSize > 0 && /* raster has SPP sample model */ + rasterP->sppsm.maxBitSize > (rasterP->dataSize * 8)) + { + JNU_ThrowInternalError(env, "Raster samples are too big"); + return -1; + } + #if 0 fprintf(stderr,"---------------------\n"); fprintf(stderr,"Width : %d\n",rasterP->width); diff --git a/src/share/native/sun/awt/splashscreen/splashscreen_gfx_impl.h b/src/share/native/sun/awt/splashscreen/splashscreen_gfx_impl.h index f2f367c6dfa83d2f25623f0902481ca993dbf485..a0fd446e94a26a8aa186cb16199c3e0a088daa95 100644 --- a/src/share/native/sun/awt/splashscreen/splashscreen_gfx_impl.h +++ b/src/share/native/sun/awt/splashscreen/splashscreen_gfx_impl.h @@ -88,27 +88,18 @@ ditherColor(rgbquad_t value, ImageFormat * format, int row, int col) /* blend (lerp between) two rgb quads src and dst alpha is ignored the algorithm: src*alpha+dst*(1-alpha)=(src-dst)*alpha+dst, rb and g are done separately - it's possible to verify that it's almost accurate indeed */ - +*/ INLINE rgbquad_t blendRGB(rgbquad_t dst, rgbquad_t src, rgbquad_t alpha) { - const rgbquad_t dstrb = dst & 0xFF00FF; - const rgbquad_t dstg = dst & 0xFF00; - const rgbquad_t srcrb = src & 0xFF00FF; - const rgbquad_t srcg = src & 0xFF00; - - rgbquad_t drb = srcrb - dstrb; - rgbquad_t dg = srcg - dstg; - - alpha += 1; - - drb *= alpha; - dg *= alpha; - drb >>= 8; - dg >>= 8; - - return ((drb + dstrb) & 0xFF00FF) | ((dg + dstg) & 0xFF00); + const rgbquad_t a = alpha; + const rgbquad_t a1 = 0xFF - alpha; + + return MAKE_QUAD( + (rgbquad_t)((QUAD_RED(src) * a + QUAD_RED(dst) * a1) / 0xFF), + (rgbquad_t)((QUAD_GREEN(src) * a + QUAD_GREEN(dst) * a1) / 0xFF), + (rgbquad_t)((QUAD_BLUE(src) * a + QUAD_BLUE(dst) * a1) / 0xFF), + 0); } /* scales rgb quad by alpha. basically similar to what's above. src alpha is retained. diff --git a/src/share/native/sun/java2d/loops/DrawParallelogram.c b/src/share/native/sun/java2d/loops/DrawParallelogram.c index 774df48fd2cf22c0d2d341bfadec304b14baeb4d..6bff9ef8081bcfbbb61817b5dd9208f52f4a26d0 100644 --- a/src/share/native/sun/java2d/loops/DrawParallelogram.c +++ b/src/share/native/sun/java2d/loops/DrawParallelogram.c @@ -26,14 +26,11 @@ #include "math.h" #include "GraphicsPrimitiveMgr.h" #include "LineUtils.h" -#include "LoopMacros.h" #include "Trace.h" +#include "ParallelogramUtils.h" -#include "sun_java2d_loops_FillParallelogram.h" #include "sun_java2d_loops_DrawParallelogram.h" -DECLARE_SOLID_DRAWLINE(AnyInt); - #define HANDLE_PGRAM_EDGE(X1, Y1, X2, Y2, \ pRasInfo, pixel, pPrim, pFunc, pCompInfo) \ do { \ @@ -46,28 +43,6 @@ DECLARE_SOLID_DRAWLINE(AnyInt); ix1, iy1, ix2, iy2, JNI_TRUE); \ } while (0) -#define PGRAM_MIN_MAX(bmin, bmax, v0, dv1, dv2) \ - do { \ - double vmin, vmax; \ - if (dv1 < 0) { \ - vmin = v0+dv1; \ - vmax = v0; \ - } else { \ - vmin = v0; \ - vmax = v0+dv1; \ - } \ - if (dv2 < 0) { \ - vmin -= dv2; \ - } else { \ - vmax += dv2; \ - } \ - bmin = (jint) floor(vmin + 0.5); \ - bmax = (jint) floor(vmax + 0.5); \ - } while(0) - -#define PGRAM_INIT_X(starty, x, y, slope) \ - (DblToLong((x) + (slope) * ((starty)+0.5 - (y))) + LongOneHalf - 1) - typedef struct { jdouble x0; jdouble y0; @@ -136,20 +111,8 @@ Java_sun_java2d_loops_DrawParallelogram_DrawParallelogram * Sort parallelogram by y values, ensure that each delta vector * has a non-negative y delta. */ - if (dy1 < 0) { - x0 += dx1; y0 += dy1; - dx1 = -dx1; dy1 = -dy1; - } - if (dy2 < 0) { - x0 += dx2; y0 += dy2; - dx2 = -dx2; dy2 = -dy2; - } - /* Sort delta vectors so dxy1 is left of dxy2. */ - if (dx1 * dy2 > dx2 * dy1) { - double v = dx1; dx1 = dx2; dx2 = v; - v = dy1; dy1 = dy2; dy2 = v; - v = lw1; lw1 = lw2; lw2 = v; - } + SORT_PGRAM(x0, y0, dx1, dy1, dx2, dy2, + v = lw1; lw1 = lw2; lw2 = v;); // dx,dy for line width in the "1" and "2" directions. ldx1 = dx1 * lw1; @@ -161,7 +124,7 @@ Java_sun_java2d_loops_DrawParallelogram_DrawParallelogram ox0 = x0 - (ldx1 + ldx2) / 2.0; oy0 = y0 - (ldy1 + ldy2) / 2.0; - PGRAM_MIN_MAX(ix1, ix2, ox0, dx1+ldx1, dx2+ldx2); + PGRAM_MIN_MAX(ix1, ix2, ox0, dx1+ldx1, dx2+ldx2, JNI_FALSE); iy1 = (jint) floor(oy0 + 0.5); iy2 = (jint) floor(oy0 + dy1 + ldy1 + dy2 + ldy2 + 0.5); @@ -212,7 +175,7 @@ Java_sun_java2d_loops_DrawParallelogram_DrawParallelogram // Only need to generate 4 quads if the interior still // has a hole in it (i.e. if the line width ratios were // both less than 1.0) - if (lw1 < 1.0f && lw2 < 1.0f) { + if (lw1 < 1.0 && lw2 < 1.0) { // If the line widths are both less than a pixel wide // then we can use a drawline function instead for even // more performance. diff --git a/src/share/native/sun/java2d/loops/FillParallelogram.c b/src/share/native/sun/java2d/loops/FillParallelogram.c index 47a7a61eb3be15f5e6e1215cad77c7cb8a511ed6..495c442f4dc511a1d7c85be1886a0af6f64df744 100644 --- a/src/share/native/sun/java2d/loops/FillParallelogram.c +++ b/src/share/native/sun/java2d/loops/FillParallelogram.c @@ -25,31 +25,10 @@ #include "math.h" #include "GraphicsPrimitiveMgr.h" +#include "ParallelogramUtils.h" #include "sun_java2d_loops_FillParallelogram.h" -#define PGRAM_MIN_MAX(bmin, bmax, v0, dv1, dv2) \ - do { \ - double vmin, vmax; \ - if (dv1 < 0) { \ - vmin = v0+dv1; \ - vmax = v0; \ - } else { \ - vmin = v0; \ - vmax = v0+dv1; \ - } \ - if (dv2 < 0) { \ - vmin -= dv2; \ - } else { \ - vmax += dv2; \ - } \ - bmin = (jint) floor(vmin + 0.5); \ - bmax = (jint) floor(vmax + 0.5); \ - } while(0) - -#define PGRAM_INIT_X(starty, x, y, slope) \ - (DblToLong((x) + (slope) * ((starty)+0.5 - (y))) + LongOneHalf - 1) - /* * Class: sun_java2d_loops_FillParallelogram * Method: FillParallelogram @@ -76,22 +55,11 @@ Java_sun_java2d_loops_FillParallelogram_FillParallelogram /* * Sort parallelogram by y values, ensure that each delta vector - * has a non-negative y delta, and eliminate degenerate parallelograms. + * has a non-negative y delta. */ - if (dy1 < 0) { - x0 += dx1; y0 += dy1; - dx1 = -dx1; dy1 = -dy1; - } - if (dy2 < 0) { - x0 += dx2; y0 += dy2; - dx2 = -dx2; dy2 = -dy2; - } - /* Sort delta vectors so dxy1 is left of dxy2. */ - if (dx1 * dy2 > dx2 * dy1) { - double v = dx1; dx1 = dx2; dx2 = v; - v = dy1; dy1 = dy2; dy2 = v; - } - PGRAM_MIN_MAX(ix1, ix2, x0, dx1, dx2); + SORT_PGRAM(x0, y0, dx1, dy1, dx2, dy2, ); + + PGRAM_MIN_MAX(ix1, ix2, x0, dx1, dx2, JNI_FALSE); iy1 = (jint) floor(y0 + 0.5); iy2 = (jint) floor(y0 + dy1 + dy2 + 0.5); diff --git a/src/share/native/sun/java2d/loops/MaskFill.c b/src/share/native/sun/java2d/loops/MaskFill.c index c64f319064672b637bfb01b805b4d2e74c857697..6691ede7a3581787b59751ba7f6b67faf624ad28 100644 --- a/src/share/native/sun/java2d/loops/MaskFill.c +++ b/src/share/native/sun/java2d/loops/MaskFill.c @@ -23,7 +23,11 @@ * questions. */ +#include +#include +#include #include "GraphicsPrimitiveMgr.h" +#include "ParallelogramUtils.h" #include "sun_java2d_loops_MaskFill.h" @@ -93,6 +97,967 @@ Java_sun_java2d_loops_MaskFill_MaskFill } } SurfaceData_InvokeRelease(env, sdOps, &rasInfo); + } + SurfaceData_InvokeUnlock(env, sdOps, &rasInfo); +} + +#define MASK_BUF_LEN 1024 + +#define DblToMask(v) ((unsigned char) ((v)*255.9999)) + +/* Fills an aligned rectangle with potentially translucent edges. */ +static void +fillAARect(NativePrimitive *pPrim, SurfaceDataRasInfo *pRasInfo, + CompositeInfo *pCompInfo, jint color, unsigned char *pMask, + void *pDst, + jdouble x1, jdouble y1, jdouble x2, jdouble y2) +{ + jint cx1 = pRasInfo->bounds.x1; + jint cy1 = pRasInfo->bounds.y1; + jint cx2 = pRasInfo->bounds.x2; + jint cy2 = pRasInfo->bounds.y2; + jint rx1 = (jint) ceil(x1); + jint ry1 = (jint) ceil(y1); + jint rx2 = (jint) floor(x2); + jint ry2 = (jint) floor(y2); + jint width = cx2 - cx1; + jint scan = pRasInfo->scanStride; + /* Convert xy12 into the edge coverage fractions for those edges. */ + x1 = rx1-x1; + y1 = ry1-y1; + x2 = x2-rx2; + y2 = y2-ry2; + if (ry2 < ry1) { + /* Accumulate bottom coverage into top coverage. */ + y1 = y1 + y2 - 1.0; + /* prevent processing of "bottom fractional row" */ + ry2 = cy2; + } + if (rx2 < rx1) { + /* Accumulate right coverage into left coverage. */ + x1 = x1 + x2 - 1.0; + /* prevent processing of "right fractional column" */ + rx2 = cx2; + } + /* Check for a visible "top fractional row" and process it */ + if (cy1 < ry1) { + unsigned char midcov = DblToMask(y1); + jint x; + for (x = 0; x < width; x++) { + pMask[x] = midcov; + } + if (cx1 < rx1) { + pMask[0] = DblToMask(y1 * x1); + } + if (cx2 > rx2) { + pMask[width-1] = DblToMask(y1 * x2); + } + (*pPrim->funcs.maskfill)(pDst, + pMask, 0, 0, + width, 1, + color, pRasInfo, + pPrim, pCompInfo); + pDst = PtrAddBytes(pDst, scan); + cy1++; + } + /* Check for a visible "left fract, solid middle, right fract" section. */ + if (cy1 < ry2 && cy1 < cy2) { + jint midh = ((ry2 < cy2) ? ry2 : cy2) - cy1; + jint midx = cx1; + void *pMid = pDst; + /* First process the left "fractional column" if it is visible. */ + if (midx < rx1) { + pMask[0] = DblToMask(x1); + /* Note: maskscan == 0 means we reuse this value for every row. */ + (*pPrim->funcs.maskfill)(pMid, + pMask, 0, 0, + 1, midh, + color, pRasInfo, + pPrim, pCompInfo); + pMid = PtrAddBytes(pMid, pRasInfo->pixelStride); + midx++; + } + /* Process the central solid section if it is visible. */ + if (midx < rx2 && midx < cx2) { + jint midw = ((rx2 < cx2) ? rx2 : cx2) - midx; + /* A NULL mask buffer means "all coverages are 0xff" */ + (*pPrim->funcs.maskfill)(pMid, + NULL, 0, 0, + midw, midh, + color, pRasInfo, + pPrim, pCompInfo); + pMid = PtrCoord(pMid, midw, pRasInfo->pixelStride, 0, 0); + midx += midw; + } + /* Finally process the right "fractional column" if it is visible. */ + if (midx < cx2) { + pMask[0] = DblToMask(x2); + /* Note: maskscan == 0 means we reuse this value for every row. */ + (*pPrim->funcs.maskfill)(pMid, + pMask, 0, 0, + 1, midh, + color, pRasInfo, + pPrim, pCompInfo); + } + cy1 += midh; + pDst = PtrCoord(pDst, 0, 0, midh, scan); + } + /* Check for a visible "bottom fractional row" and process it */ + if (cy1 < cy2) { + unsigned char midcov = DblToMask(y2); + jint x; + for (x = 0; x < width; x++) { + pMask[x] = midcov; + } + if (cx1 < rx1) { + pMask[0] = DblToMask(y2 * x1); + } + if (cx2 > rx2) { + pMask[width-1] = DblToMask(y2 * x2); + } + (*pPrim->funcs.maskfill)(pDst, + pMask, 0, 0, + width, 1, + color, pRasInfo, + pPrim, pCompInfo); + } +} + +/* + * Support code for arbitrary tracing and MaskFill filling of + * non-rectilinear (diagonal) parallelograms. + * + * This code is based upon the following model of AA coverage. + * + * Each edge of a parallelogram (for fillPgram) or a double + * parallelogram (inner and outer parallelograms for drawPgram) + * can be rasterized independently because the geometry is well + * defined in such a way that none of the sides will ever cross + * each other and they have a fixed ordering that is fairly + * well predetermined. + * + * So, for each edge we will look at the diagonal line that + * the edge makes as it passes through a row of pixels. Some + * such diagonal lines may pass entirely through the row of + * pixels in a single pixel column. Some may cut across the + * row and pass through several pixel columns before they pass + * on to the next row. + * + * As the edge passes through the row of pixels it will affect + * the coverage of the pixels it passes through as well as all + * of the pixels to the right of the edge. The coverage will + * either be increased (by a left edge of a parallelogram) or + * decreased (by a right edge) for all pixels to the right, until + * another edge passing the opposite direction is encountered. + * + * The coverage added or subtracted by an edge as it crosses a + * given pixel is calculated using a trapezoid formula in the + * following manner: + * + * / + * +-----+---/-+-----+ + * | | / | | + * | | / | | + * +-----+/----+-----+ + * / + * + * The area to the right of that edge for the pixel where it + * crosses is given as: + * + * trapheight * (topedge + bottomedge)/2 + * + * Another thing to note is that the above formula gives the + * contribution of that edge to the given pixel where it crossed, + * but in so crossing the pixel row, it also created 100% coverage + * for all of the pixels to the right. + * + * This example was simplified in that the edge depicted crossed + * the complete pixel row and it did so entirely within the bounds + * of a single pixel column. In practice, many edges may start or + * end in a given row and thus provide only partial row coverage + * (i.e. the total "trapheight" in the formula never reaches 1.0). + * And in other cases, edges may travel sideways through several + * pixel columns on a given pixel row from where they enter it to + * where the leave it (which also mans that the trapheight for a + * given pixel will be less than 1.0, but by the time the edge + * completes its journey through the pixel row the "coverage shadow" + * that it casts on all pixels to the right eventually reaches 100%). + * + * In order to simplify the calculations so that we don't have to + * keep propagating coverages we calculate for one edge "until we + * reach another edge" we will process one edge at a time and + * simply record in a buffer the amount that an edge added to + * or subtracted from the coverage for a given pixel and its + * following right-side neighbors. Thus, the true total coverage + * of a given pixel is only determined by summing the deltas for + * that pixel and all of the pixels to its left. Since we already + * have to scan the buffer to change floating point coverages into + * mask values for a MaskFill loop, it is simple enough to sum the + * values as we perform that scan from left to right. + * + * In the above example, note that 2 deltas need to be recorded even + * though the edge only intersected a single pixel. The delta recorded + * for the pixel where the edge crossed will be approximately 55% + * (guesstimating by examining the poor ascii art) which is fine for + * determining how to render that pixel, but the rest of the pixels + * to its right should have their coverage modified by a full 100% + * and the 55% delta value we recorded for the pixel that the edge + * crossed will not get them there. We adjust for this by adding + * the "remainder" of the coverage implied by the shadow to the + * pixel immediately to the right of where we record a trapezoidal + * contribution. In this case a delta of 45% will be recorded in + * the pixel immediately to the right to raise the total to 100%. + * + * As we sum these delta values as we process the line from left + * to right, these delta values will typically drive the sum from + * 0% up to 100% and back down to 0% over the course of a single + * pixel row. In the case of a drawn (double) parallelogram the + * sum will go to 100% and back to 0% twice on most scanlines. + * + * The fillAAPgram and drawAAPgram functions drive the main flow + * of the algorithm with help from the following structures, + * macros, and functions. It is probably best to start with + * those 2 functions to gain an understanding of the algorithm. + */ +typedef struct { + jdouble x; + jdouble y; + jdouble xbot; + jdouble ybot; + jdouble xnexty; + jdouble ynextx; + jdouble xnextx; + jdouble linedx; + jdouble celldx; + jdouble celldy; + jboolean isTrailing; +} EdgeInfo; + +#define MIN_DELTA (1.0/256.0) + +/* + * Calculates slopes and deltas for an edge and stores results in an EdgeInfo. + * Returns true if the edge was valid (i.e. not ignored for some reason). + */ +static jboolean +storeEdge(EdgeInfo *pEdge, + jdouble x, jdouble y, jdouble dx, jdouble dy, + jint cx1, jint cy1, jint cx2, jint cy2, + jboolean isTrailing) +{ + jdouble xbot = x + dx; + jdouble ybot = y + dy; + jboolean ret; + + pEdge->x = x; + pEdge->y = y; + pEdge->xbot = xbot; + pEdge->ybot = ybot; + + /* Note that parallelograms are sorted so dy is always non-negative */ + if (dy > MIN_DELTA && /* NaN and horizontal protection */ + ybot > cy1 && /* NaN and "OUT_ABOVE" protection */ + y < cy2 && /* NaN and "OUT_BELOW" protection */ + xbot == xbot && /* NaN protection */ + (x < cx2 || xbot < cx2)) /* "OUT_RIGHT" protection */ + /* Note: "OUT_LEFT" segments may still contribute coverage... */ + { + /* no NaNs, dy is not horizontal, and segment contributes to clip */ + if (dx < -MIN_DELTA || dx > MIN_DELTA) { + /* dx is not vertical */ + jdouble linedx; + jdouble celldy; + jdouble nextx; + + linedx = dx / dy; + celldy = dy / dx; + if (y < cy1) { + pEdge->x = x = x + (cy1 - y) * linedx; + pEdge->y = y = cy1; + } + pEdge->linedx = linedx; + if (dx < 0) { + pEdge->celldx = -1.0; + pEdge->celldy = -celldy; + pEdge->xnextx = nextx = ceil(x) - 1.0; + } else { + pEdge->celldx = +1.0; + pEdge->celldy = celldy; + pEdge->xnextx = nextx = floor(x) + 1.0; + } + pEdge->ynextx = y + (nextx - x) * celldy; + pEdge->xnexty = x + ((floor(y) + 1) - y) * linedx; + } else { + /* dx is essentially vertical */ + if (y < cy1) { + pEdge->y = y = cy1; + } + pEdge->xbot = x; + pEdge->linedx = 0.0; + pEdge->celldx = 0.0; + pEdge->celldy = 1.0; + pEdge->xnextx = x; + pEdge->xnexty = x; + pEdge->ynextx = ybot; + } + ret = JNI_TRUE; + } else { + /* There is some reason to ignore this segment, "celldy=0" omits it */ + pEdge->ybot = y; + pEdge->linedx = dx; + pEdge->celldx = dx; + pEdge->celldy = 0.0; + pEdge->xnextx = xbot; + pEdge->xnexty = xbot; + pEdge->ynextx = y; + ret = JNI_FALSE; + } + pEdge->isTrailing = isTrailing; + return ret; +} + +/* + * Calculates and stores slopes and deltas for all edges of a parallelogram. + * Returns true if at least 1 edge was valid (i.e. not ignored for some reason). + * + * The inverted flag is true for an outer parallelogram (left and right + * edges are leading and trailing) and false for an inner parallelogram + * (where the left edge is trailing and the right edge is leading). + */ +static jboolean +storePgram(EdgeInfo *pLeftEdge, EdgeInfo *pRightEdge, + jdouble x, jdouble y, + jdouble dx1, jdouble dy1, + jdouble dx2, jdouble dy2, + jint cx1, jint cy1, jint cx2, jint cy2, + jboolean inverted) +{ + jboolean ret = JNI_FALSE; + ret = (storeEdge(pLeftEdge + 0, + x , y , dx1, dy1, + cx1, cy1, cx2, cy2, inverted) || ret); + ret = (storeEdge(pLeftEdge + 1, + x+dx1, y+dy1, dx2, dy2, + cx1, cy1, cx2, cy2, inverted) || ret); + ret = (storeEdge(pRightEdge + 0, + x , y , dx2, dy2, + cx1, cy1, cx2, cy2, !inverted) || ret); + ret = (storeEdge(pRightEdge + 1, + x+dx2, y+dy2, dx1, dy1, + cx1, cy1, cx2, cy2, !inverted) || ret); + return ret; +} + +/* + * The X0,Y0,X1,Y1 values represent a trapezoidal fragment whose + * coverage must be accounted for in the accum buffer. + * + * All four values are assumed to fall within (or on the edge of) + * a single pixel. + * + * The trapezoid area is accumulated into the proper element of + * the accum buffer and the remainder of the "slice height" is + * accumulated into the element to its right. + */ +#define INSERT_ACCUM(pACCUM, IMIN, IMAX, X0, Y0, X1, Y1, CX1, CX2, MULT) \ + do { \ + jdouble xmid = ((X0) + (X1)) * 0.5; \ + if (xmid <= (CX2)) { \ + jdouble sliceh = ((Y1) - (Y0)); \ + jdouble slicearea; \ + jint i; \ + if (xmid < (CX1)) { \ + /* Accumulate the entire slice height into accum[0]. */ \ + i = 0; \ + slicearea = sliceh; \ + } else { \ + jdouble xpos = floor(xmid); \ + i = ((jint) xpos) - (CX1); \ + slicearea = (xpos+1-xmid) * sliceh; \ + } \ + if (IMIN > i) { \ + IMIN = i; \ + } \ + (pACCUM)[i++] += (jfloat) ((MULT) * slicearea); \ + (pACCUM)[i++] += (jfloat) ((MULT) * (sliceh - slicearea)); \ + if (IMAX < i) { \ + IMAX = i; \ + } \ + } \ + } while (0) + +/* + * Accumulate the contributions for a given edge crossing a given + * scan line into the corresponding entries of the accum buffer. + * CY1 is the Y coordinate of the top edge of the scanline and CY2 + * is equal to (CY1 + 1) and is the Y coordinate of the bottom edge + * of the scanline. CX1 and CX2 are the left and right edges of the + * clip (or area of interest) being rendered. + * + * The edge is processed from the top edge to the bottom edge and + * a single pixel column at a time. + */ +#define ACCUM_EDGE(pEDGE, pACCUM, IMIN, IMAX, CX1, CY1, CX2, CY2) \ + do { \ + jdouble x, y, xnext, ynext, xlast, ylast, dx, dy, mult; \ + y = (pEDGE)->y; \ + dy = (pEDGE)->celldy; \ + ylast = (pEDGE)->ybot; \ + if (ylast <= (CY1) || y >= (CY2) || dy == 0.0) { \ + break; \ + } \ + x = (pEDGE)->x; \ + dx = (pEDGE)->celldx; \ + if (ylast > (CY2)) { \ + ylast = (CY2); \ + xlast = (pEDGE)->xnexty; \ + } else { \ + xlast = (pEDGE)->xbot; \ + } \ + xnext = (pEDGE)->xnextx; \ + ynext = (pEDGE)->ynextx; \ + mult = ((pEDGE)->isTrailing) ? -1.0 : 1.0; \ + while (ynext <= ylast) { \ + INSERT_ACCUM(pACCUM, IMIN, IMAX, \ + x, y, xnext, ynext, \ + CX1, CX2, mult); \ + x = xnext; \ + y = ynext; \ + xnext += dx; \ + ynext += dy; \ + } \ + (pEDGE)->ynextx = ynext; \ + (pEDGE)->xnextx = xnext; \ + INSERT_ACCUM(pACCUM, IMIN, IMAX, \ + x, y, xlast, ylast, \ + CX1, CX2, mult); \ + (pEDGE)->x = xlast; \ + (pEDGE)->y = ylast; \ + (pEDGE)->xnexty = xlast + (pEDGE)->linedx; \ + } while(0) + +/* Main function to fill a single Parallelogram */ +static void +fillAAPgram(NativePrimitive *pPrim, SurfaceDataRasInfo *pRasInfo, + CompositeInfo *pCompInfo, jint color, unsigned char *pMask, + void *pDst, + jdouble x1, jdouble y1, + jdouble dx1, jdouble dy1, + jdouble dx2, jdouble dy2) +{ + jint cx1 = pRasInfo->bounds.x1; + jint cy1 = pRasInfo->bounds.y1; + jint cx2 = pRasInfo->bounds.x2; + jint cy2 = pRasInfo->bounds.y2; + jint width = cx2 - cx1; + EdgeInfo edges[4]; + jfloat localaccum[MASK_BUF_LEN + 1]; + jfloat *pAccum; + + if (!storePgram(edges + 0, edges + 2, + x1, y1, dx1, dy1, dx2, dy2, + cx1, cy1, cx2, cy2, + JNI_FALSE)) + { + return; + } + + pAccum = ((width > MASK_BUF_LEN) + ? malloc((width + 1) * sizeof(jfloat)) + : localaccum); + if (pAccum == NULL) { + return; + } + memset(pAccum, 0, (width+1) * sizeof(jfloat)); + + while (cy1 < cy2) { + jint lmin, lmax, rmin, rmax; + jint moff, x; + jdouble accum; + unsigned char lastcov; + + lmin = rmin = width + 2; + lmax = rmax = 0; + ACCUM_EDGE(&edges[0], pAccum, lmin, lmax, + cx1, cy1, cx2, cy1+1); + ACCUM_EDGE(&edges[1], pAccum, lmin, lmax, + cx1, cy1, cx2, cy1+1); + ACCUM_EDGE(&edges[2], pAccum, rmin, rmax, + cx1, cy1, cx2, cy1+1); + ACCUM_EDGE(&edges[3], pAccum, rmin, rmax, + cx1, cy1, cx2, cy1+1); + if (lmax > width) { + lmax = width; /* Extra col has data we do not need. */ + } + if (rmax > width) { + rmax = width; /* Extra col has data we do not need. */ + } + /* If ranges overlap, handle both in the first pass. */ + if (rmin <= lmax) { + lmax = rmax; + } + + x = lmin; + accum = 0.0; + moff = 0; + lastcov = 0; + while (x < lmax) { + accum += pAccum[x]; + pAccum[x] = 0.0f; + pMask[moff++] = lastcov = DblToMask(accum); + x++; + } + /* Check for a solid center section. */ + if (lastcov == 0xFF) { + jint endx; + void *pRow; + + /* First process the existing partial coverage data. */ + if (moff > 0) { + pRow = PtrCoord(pDst, x-moff, pRasInfo->pixelStride, 0, 0); + (*pPrim->funcs.maskfill)(pRow, + pMask, 0, 0, + moff, 1, + color, pRasInfo, + pPrim, pCompInfo); + moff = 0; + } + + /* Where does the center section end? */ + /* If there is no right AA edge in the accum buffer, then */ + /* the right edge was beyond the clip, so fill out to width */ + endx = (rmin < rmax) ? rmin : width; + if (x < endx) { + pRow = PtrCoord(pDst, x, pRasInfo->pixelStride, 0, 0); + (*pPrim->funcs.maskfill)(pRow, + NULL, 0, 0, + endx - x, 1, + color, pRasInfo, + pPrim, pCompInfo); + x = endx; + } + } else if (lastcov > 0 && rmin >= rmax) { + /* We are not at 0 coverage, but there is no right edge, */ + /* force a right edge so we process pixels out to width. */ + rmax = width; + } + /* The following loop will process the right AA edge and/or any */ + /* partial coverage center section not processed above. */ + while (x < rmax) { + accum += pAccum[x]; + pAccum[x] = 0.0f; + pMask[moff++] = DblToMask(accum); + x++; + } + if (moff > 0) { + void *pRow = PtrCoord(pDst, x-moff, pRasInfo->pixelStride, 0, 0); + (*pPrim->funcs.maskfill)(pRow, + pMask, 0, 0, + moff, 1, + color, pRasInfo, + pPrim, pCompInfo); + } + pDst = PtrAddBytes(pDst, pRasInfo->scanStride); + cy1++; + } + if (pAccum != localaccum) { + free(pAccum); + } +} + +/* + * Class: sun_java2d_loops_MaskFill + * Method: FillAAPgram + * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;Ljava/awt/Composite;DDDDDD)V + */ +JNIEXPORT void JNICALL +Java_sun_java2d_loops_MaskFill_FillAAPgram + (JNIEnv *env, jobject self, + jobject sg2d, jobject sData, jobject comp, + jdouble x0, jdouble y0, + jdouble dx1, jdouble dy1, + jdouble dx2, jdouble dy2) +{ + SurfaceDataOps *sdOps; + SurfaceDataRasInfo rasInfo; + NativePrimitive *pPrim; + CompositeInfo compInfo; + jint ix1, iy1, ix2, iy2; + + if ((dy1 == 0 && dx1 == 0) || (dy2 == 0 && dx2 == 0)) { + return; + } + + /* + * Sort parallelogram by y values, ensure that each delta vector + * has a non-negative y delta. + */ + SORT_PGRAM(x0, y0, dx1, dy1, dx2, dy2, ); + + PGRAM_MIN_MAX(ix1, ix2, x0, dx1, dx2, JNI_TRUE); + iy1 = (jint) floor(y0); + iy2 = (jint) ceil(y0 + dy1 + dy2); + + pPrim = GetNativePrim(env, self); + if (pPrim == NULL) { + return; + } + if (pPrim->pCompType->getCompInfo != NULL) { + (*pPrim->pCompType->getCompInfo)(env, &compInfo, comp); + } + + sdOps = SurfaceData_GetOps(env, sData); + if (sdOps == 0) { + return; + } + + GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds); + SurfaceData_IntersectBoundsXYXY(&rasInfo.bounds, ix1, iy1, ix2, iy2); + if (rasInfo.bounds.y2 <= rasInfo.bounds.y1 || + rasInfo.bounds.x2 <= rasInfo.bounds.x1) + { + return; + } + + if (sdOps->Lock(env, sdOps, &rasInfo, pPrim->dstflags) != SD_SUCCESS) { + return; + } + + ix1 = rasInfo.bounds.x1; + iy1 = rasInfo.bounds.y1; + ix2 = rasInfo.bounds.x2; + iy2 = rasInfo.bounds.y2; + if (ix2 > ix1 && iy2 > iy1) { + jint width = ix2 - ix1; + jint color = GrPrim_Sg2dGetEaRGB(env, sg2d); + unsigned char localmask[MASK_BUF_LEN]; + unsigned char *pMask = ((width > MASK_BUF_LEN) + ? malloc(width) + : localmask); + + sdOps->GetRasInfo(env, sdOps, &rasInfo); + if (rasInfo.rasBase != NULL && pMask != NULL) { + void *pDst = PtrCoord(rasInfo.rasBase, + ix1, rasInfo.pixelStride, + iy1, rasInfo.scanStride); + if (dy1 == 0 && dx2 == 0) { + if (dx1 < 0) { + // We sorted by Y above, but not by X + x0 += dx1; + dx1 = -dx1; + } + fillAARect(pPrim, &rasInfo, &compInfo, + color, pMask, pDst, + x0, y0, x0+dx1, y0+dy2); + } else if (dx1 == 0 && dy2 == 0) { + if (dx2 < 0) { + // We sorted by Y above, but not by X + x0 += dx2; + dx2 = -dx2; + } + fillAARect(pPrim, &rasInfo, &compInfo, + color, pMask, pDst, + x0, y0, x0+dx2, y0+dy1); + } else { + fillAAPgram(pPrim, &rasInfo, &compInfo, + color, pMask, pDst, + x0, y0, dx1, dy1, dx2, dy2); + } + } + SurfaceData_InvokeRelease(env, sdOps, &rasInfo); + if (pMask != NULL && pMask != localmask) { + free(pMask); + } + } + SurfaceData_InvokeUnlock(env, sdOps, &rasInfo); +} + +/* Main function to fill a double pair of (inner and outer) parallelograms */ +static void +drawAAPgram(NativePrimitive *pPrim, SurfaceDataRasInfo *pRasInfo, + CompositeInfo *pCompInfo, jint color, unsigned char *pMask, + void *pDst, + jdouble ox0, jdouble oy0, + jdouble dx1, jdouble dy1, + jdouble dx2, jdouble dy2, + jdouble ldx1, jdouble ldy1, + jdouble ldx2, jdouble ldy2) +{ + jint cx1 = pRasInfo->bounds.x1; + jint cy1 = pRasInfo->bounds.y1; + jint cx2 = pRasInfo->bounds.x2; + jint cy2 = pRasInfo->bounds.y2; + jint width = cx2 - cx1; + EdgeInfo edges[8]; + jfloat localaccum[MASK_BUF_LEN + 1]; + jfloat *pAccum; + + if (!storePgram(edges + 0, edges + 6, + ox0, oy0, + dx1 + ldx1, dy1 + ldy1, + dx2 + ldx2, dy2 + ldy2, + cx1, cy1, cx2, cy2, + JNI_FALSE)) + { + /* If outer pgram does not contribute, then inner cannot either. */ + return; + } + storePgram(edges + 2, edges + 4, + ox0 + ldx1 + ldx2, oy0 + ldy1 + ldy2, + dx1 - ldx1, dy1 - ldy1, + dx2 - ldx2, dy2 - ldy2, + cx1, cy1, cx2, cy2, + JNI_TRUE); + + pAccum = ((width > MASK_BUF_LEN) + ? malloc((width + 1) * sizeof(jfloat)) + : localaccum); + if (pAccum == NULL) { + return; + } + memset(pAccum, 0, (width+1) * sizeof(jfloat)); + + while (cy1 < cy2) { + jint lmin, lmax, rmin, rmax; + jint moff, x; + jdouble accum; + unsigned char lastcov; + + lmin = rmin = width + 2; + lmax = rmax = 0; + ACCUM_EDGE(&edges[0], pAccum, lmin, lmax, + cx1, cy1, cx2, cy1+1); + ACCUM_EDGE(&edges[1], pAccum, lmin, lmax, + cx1, cy1, cx2, cy1+1); + ACCUM_EDGE(&edges[2], pAccum, lmin, lmax, + cx1, cy1, cx2, cy1+1); + ACCUM_EDGE(&edges[3], pAccum, lmin, lmax, + cx1, cy1, cx2, cy1+1); + ACCUM_EDGE(&edges[4], pAccum, rmin, rmax, + cx1, cy1, cx2, cy1+1); + ACCUM_EDGE(&edges[5], pAccum, rmin, rmax, + cx1, cy1, cx2, cy1+1); + ACCUM_EDGE(&edges[6], pAccum, rmin, rmax, + cx1, cy1, cx2, cy1+1); + ACCUM_EDGE(&edges[7], pAccum, rmin, rmax, + cx1, cy1, cx2, cy1+1); + if (lmax > width) { + lmax = width; /* Extra col has data we do not need. */ + } + if (rmax > width) { + rmax = width; /* Extra col has data we do not need. */ + } + /* If ranges overlap, handle both in the first pass. */ + if (rmin <= lmax) { + lmax = rmax; + } + + x = lmin; + accum = 0.0; + moff = 0; + lastcov = 0; + while (x < lmax) { + accum += pAccum[x]; + pAccum[x] = 0.0f; + pMask[moff++] = lastcov = DblToMask(accum); + x++; + } + /* Check for an empty or solidcenter section. */ + if (lastcov == 0 || lastcov == 0xFF) { + jint endx; + void *pRow; + + /* First process the existing partial coverage data. */ + if (moff > 0) { + pRow = PtrCoord(pDst, x-moff, pRasInfo->pixelStride, 0, 0); + (*pPrim->funcs.maskfill)(pRow, + pMask, 0, 0, + moff, 1, + color, pRasInfo, + pPrim, pCompInfo); + moff = 0; + } + + /* Where does the center section end? */ + /* If there is no right AA edge in the accum buffer, then */ + /* the right edge was beyond the clip, so fill out to width */ + endx = (rmin < rmax) ? rmin : width; + if (x < endx) { + if (lastcov == 0xFF) { + pRow = PtrCoord(pDst, x, pRasInfo->pixelStride, 0, 0); + (*pPrim->funcs.maskfill)(pRow, + NULL, 0, 0, + endx - x, 1, + color, pRasInfo, + pPrim, pCompInfo); + } + x = endx; + } + } else if (rmin >= rmax) { + /* We are not at 0 coverage, but there is no right edge, */ + /* force a right edge so we process pixels out to width. */ + rmax = width; + } + /* The following loop will process the right AA edge and/or any */ + /* partial coverage center section not processed above. */ + while (x < rmax) { + accum += pAccum[x]; + pAccum[x] = 0.0f; + pMask[moff++] = lastcov = DblToMask(accum); + x++; + } + if (moff > 0) { + void *pRow = PtrCoord(pDst, x-moff, pRasInfo->pixelStride, 0, 0); + (*pPrim->funcs.maskfill)(pRow, + pMask, 0, 0, + moff, 1, + color, pRasInfo, + pPrim, pCompInfo); + } + if (lastcov == 0xFF && x < width) { + void *pRow = PtrCoord(pDst, x, pRasInfo->pixelStride, 0, 0); + (*pPrim->funcs.maskfill)(pRow, + NULL, 0, 0, + width - x, 1, + color, pRasInfo, + pPrim, pCompInfo); + } + pDst = PtrAddBytes(pDst, pRasInfo->scanStride); + cy1++; + } + if (pAccum != localaccum) { + free(pAccum); + } +} + +/* + * Class: sun_java2d_loops_MaskFill + * Method: DrawAAPgram + * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;Ljava/awt/Composite;DDDDDDDD)V + */ +JNIEXPORT void JNICALL +Java_sun_java2d_loops_MaskFill_DrawAAPgram + (JNIEnv *env, jobject self, + jobject sg2d, jobject sData, jobject comp, + jdouble x0, jdouble y0, + jdouble dx1, jdouble dy1, + jdouble dx2, jdouble dy2, + jdouble lw1, jdouble lw2) +{ + SurfaceDataOps *sdOps; + SurfaceDataRasInfo rasInfo; + NativePrimitive *pPrim; + CompositeInfo compInfo; + jint ix1, iy1, ix2, iy2; + jdouble ldx1, ldy1, ldx2, ldy2; + jdouble ox0, oy0; + + if ((dy1 == 0 && dx1 == 0) || (dy2 == 0 && dx2 == 0)) { + return; + } + + /* + * Sort parallelogram by y values, ensure that each delta vector + * has a non-negative y delta. + */ + SORT_PGRAM(x0, y0, dx1, dy1, dx2, dy2, + v = lw1; lw1 = lw2; lw2 = v;); + + // dx,dy for line width in the "1" and "2" directions. + ldx1 = dx1 * lw1; + ldy1 = dy1 * lw1; + ldx2 = dx2 * lw2; + ldy2 = dy2 * lw2; + + // calculate origin of the outer parallelogram + ox0 = x0 - (ldx1 + ldx2) / 2.0; + oy0 = y0 - (ldy1 + ldy2) / 2.0; + + if (lw1 >= 1.0 || lw2 >= 1.0) { + /* Only need to fill an outer pgram if the interior no longer + * has a hole in it (i.e. if either of the line width ratios + * were greater than or equal to 1.0). + */ + Java_sun_java2d_loops_MaskFill_FillAAPgram(env, self, + sg2d, sData, comp, + ox0, oy0, + dx1 + ldx1, dy1 + ldy1, + dx2 + ldx2, dy2 + ldy2); + return; + } + + PGRAM_MIN_MAX(ix1, ix2, ox0, dx1+ldx1, dx2+ldx2, JNI_TRUE); + iy1 = (jint) floor(oy0); + iy2 = (jint) ceil(oy0 + dy1 + ldy1 + dy2 + ldy2); + + pPrim = GetNativePrim(env, self); + if (pPrim == NULL) { + return; + } + if (pPrim->pCompType->getCompInfo != NULL) { + (*pPrim->pCompType->getCompInfo)(env, &compInfo, comp); + } + + sdOps = SurfaceData_GetOps(env, sData); + if (sdOps == 0) { + return; + } + + GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds); + SurfaceData_IntersectBoundsXYXY(&rasInfo.bounds, ix1, iy1, ix2, iy2); + if (rasInfo.bounds.y2 <= rasInfo.bounds.y1 || + rasInfo.bounds.x2 <= rasInfo.bounds.x1) + { + return; + } + + if (sdOps->Lock(env, sdOps, &rasInfo, pPrim->dstflags) != SD_SUCCESS) { + return; + } + + ix1 = rasInfo.bounds.x1; + iy1 = rasInfo.bounds.y1; + ix2 = rasInfo.bounds.x2; + iy2 = rasInfo.bounds.y2; + if (ix2 > ix1 && iy2 > iy1) { + jint width = ix2 - ix1; + jint color = GrPrim_Sg2dGetEaRGB(env, sg2d); + unsigned char localmask[MASK_BUF_LEN]; + unsigned char *pMask = ((width > MASK_BUF_LEN) + ? malloc(width) + : localmask); + + sdOps->GetRasInfo(env, sdOps, &rasInfo); + if (rasInfo.rasBase != NULL && pMask != NULL) { + void *pDst = PtrCoord(rasInfo.rasBase, + ix1, rasInfo.pixelStride, + iy1, rasInfo.scanStride); + /* + * NOTE: aligned rects could probably be drawn + * even faster with a little work here. + * if (dy1 == 0 && dx2 == 0) { + * drawAARect(pPrim, &rasInfo, &compInfo, + * color, pMask, pDst, + * ox0, oy0, ox0+dx1+ldx1, oy0+dy2+ldy2, ldx1, ldy2); + * } else if (dx1 == 0 && dy2 == 0) { + * drawAARect(pPrim, &rasInfo, &compInfo, + * color, pMask, pDst, + * ox0, oy0, ox0+dx2+ldx2, oy0+dy1+ldy1, ldx2, ldy1); + * } else { + */ + drawAAPgram(pPrim, &rasInfo, &compInfo, + color, pMask, pDst, + ox0, oy0, + dx1, dy1, dx2, dy2, + ldx1, ldy1, ldx2, ldy2); + /* + * } + */ + } + SurfaceData_InvokeRelease(env, sdOps, &rasInfo); + if (pMask != NULL && pMask != localmask) { + free(pMask); + } } SurfaceData_InvokeUnlock(env, sdOps, &rasInfo); } diff --git a/src/share/native/sun/java2d/loops/ParallelogramUtils.h b/src/share/native/sun/java2d/loops/ParallelogramUtils.h new file mode 100644 index 0000000000000000000000000000000000000000..3691abad25c49ec8e9dd62f57e97bfc4de39e7db --- /dev/null +++ b/src/share/native/sun/java2d/loops/ParallelogramUtils.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef ParallelogramUtils_h_Included +#define ParallelogramUtils_h_Included + +#ifdef __cplusplus +extern "C" { +#endif + +#define PGRAM_MIN_MAX(bmin, bmax, v0, dv1, dv2, AA) \ + do { \ + double vmin, vmax; \ + if (dv1 < 0) { \ + vmin = v0+dv1; \ + vmax = v0; \ + } else { \ + vmin = v0; \ + vmax = v0+dv1; \ + } \ + if (dv2 < 0) { \ + vmin += dv2; \ + } else { \ + vmax += dv2; \ + } \ + if (AA) { \ + bmin = (jint) floor(vmin); \ + bmax = (jint) ceil(vmax); \ + } else { \ + bmin = (jint) floor(vmin + 0.5); \ + bmax = (jint) floor(vmax + 0.5); \ + } \ + } while(0) + +#define PGRAM_INIT_X(starty, x, y, slope) \ + (DblToLong((x) + (slope) * ((starty)+0.5 - (y))) + LongOneHalf - 1) + +/* + * Sort parallelogram by y values, ensure that each delta vector + * has a non-negative y delta. + */ +#define SORT_PGRAM(x0, y0, dx1, dy1, dx2, dy2, OTHER_SWAP_CODE) \ + do { \ + if (dy1 < 0) { \ + x0 += dx1; y0 += dy1; \ + dx1 = -dx1; dy1 = -dy1; \ + } \ + if (dy2 < 0) { \ + x0 += dx2; y0 += dy2; \ + dx2 = -dx2; dy2 = -dy2; \ + } \ + /* Sort delta vectors so dxy1 is left of dxy2. */ \ + if (dx1 * dy2 > dx2 * dy1) { \ + double v; \ + v = dx1; dx1 = dx2; dx2 = v; \ + v = dy1; dy1 = dy2; dy2 = v; \ + OTHER_SWAP_CODE \ + } \ + } while(0) + +#endif /* ParallelogramUtils_h_Included */ diff --git a/src/share/native/sun/java2d/pipe/BufferedMaskBlit.c b/src/share/native/sun/java2d/pipe/BufferedMaskBlit.c index 1c5b99b250d52ad5ae9f379d1f4362a846408d5f..ccfeab5cafdb38e17dc675f27e4ce99e27ef009a 100644 --- a/src/share/native/sun/java2d/pipe/BufferedMaskBlit.c +++ b/src/share/native/sun/java2d/pipe/BufferedMaskBlit.c @@ -119,7 +119,8 @@ Java_sun_java2d_pipe_BufferedMaskBlit_enqueueTile PtrCoord(srcInfo.rasBase, srcInfo.bounds.x1, srcInfo.pixelStride, srcInfo.bounds.y1, srcInfo.scanStride); - unsigned char *pMask = + unsigned char *pMask, *pMaskAlloc; + pMask = pMaskAlloc = (*env)->GetPrimitiveArrayCritical(env, maskArray, 0); if (pMask == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, @@ -274,7 +275,7 @@ Java_sun_java2d_pipe_BufferedMaskBlit_enqueueTile bpos += width * height * sizeof(jint); (*env)->ReleasePrimitiveArrayCritical(env, maskArray, - pMask, JNI_ABORT); + pMaskAlloc, JNI_ABORT); } SurfaceData_InvokeRelease(env, srcOps, &srcInfo); } diff --git a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.c b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.c index 3128efe252e120789feaadfcfe75dd2a5a9082a8..73ec25671d1e39bfc18f1a5e000eed14123c751a 100644 --- a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.c +++ b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.c @@ -137,41 +137,43 @@ void getALSAVersion(char* buffer, int len) { file = fopen(ALSA_VERSION_PROC_FILE, "r"); ALSAVersionString[0] = 0; if (file) { - fgets(ALSAVersionString, ALSAVersionString_LENGTH, file); - // parse for version number - totalLen = strlen(ALSAVersionString); - inVersionString = FALSE; - len = 0; - curr = 0; - while (curr < totalLen) { - if (!inVersionString) { - // is this char the beginning of a version string ? - if (ALSAVersionString[curr] >= '0' - && ALSAVersionString[curr] <= '9') { - inVersionString = TRUE; + if (NULL != fgets(ALSAVersionString, ALSAVersionString_LENGTH, file)) { + // parse for version number + totalLen = strlen(ALSAVersionString); + inVersionString = FALSE; + len = 0; + curr = 0; + while (curr < totalLen) { + if (!inVersionString) { + // is this char the beginning of a version string ? + if (ALSAVersionString[curr] >= '0' + && ALSAVersionString[curr] <= '9') { + inVersionString = TRUE; + } } - } - if (inVersionString) { - // the version string ends with white space - if (ALSAVersionString[curr] <= 32) { - break; - } - if (curr != len) { - // copy this char to the beginning of the string - ALSAVersionString[len] = ALSAVersionString[curr]; + if (inVersionString) { + // the version string ends with white space + if (ALSAVersionString[curr] <= 32) { + break; + } + if (curr != len) { + // copy this char to the beginning of the string + ALSAVersionString[len] = ALSAVersionString[curr]; + } + len++; } - len++; + curr++; } - curr++; - } - // remove trailing dots - while ((len > 0) && (ALSAVersionString[len - 1] == '.')) { - len--; + // remove trailing dots + while ((len > 0) && (ALSAVersionString[len - 1] == '.')) { + len--; + } + // null terminate + ALSAVersionString[len] = 0; } - // null terminate - ALSAVersionString[len] = 0; + fclose(file); + hasGottenALSAVersion = TRUE; } - hasGottenALSAVersion = TRUE; } strncpy(buffer, ALSAVersionString, len); } diff --git a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiIn.c b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiIn.c index a2277bdb6a0b3535b3e18bc4d13693b9c48fd2b1..db4a30ca330a0a9114b85c6ce69fbfbab2a75b0a 100644 --- a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiIn.c +++ b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiIn.c @@ -32,6 +32,9 @@ #include #include "PlatformMidi.h" #include "PLATFORM_API_LinuxOS_ALSA_MidiUtils.h" +#if defined(i586) +#include +#endif /* * Helper methods @@ -73,9 +76,38 @@ char* MIDI_IN_GetErrorStr(INT32 err) { return (char*) getErrorStr(err); } - INT32 MIDI_IN_GetNumDevices() { +/* Workaround for 6842956: 32bit app on 64bit linux + * gets assertion failure trying to open midiIn ports. + * Untill the issue is fixed in ALSA + * (https://bugtrack.alsa-project.org/alsa-bug/view.php?id=4807) + * report no midi in devices in the configuration. + */ +#if defined(i586) + static int jre32onlinux64 = -1; + if (jre32onlinux64 < 0) { + jre32onlinux64 = 0; + /* The workaround may be disabled setting "JAVASOUND_ENABLE_MIDIIN" + * environment variable. + */ + if (getenv("JAVASOUND_ENABLE_MIDIIN") == NULL) { + struct utsname u; + jre32onlinux64 = 0; + if (uname(&u) == 0) { + if (strstr(u.machine, "64") != NULL) { + TRACE0("jre32 on linux64 detected - report no midiIn devices\n"); + jre32onlinux64 = 1; + } + } + } + } + if (jre32onlinux64) { + return 0; + } +#endif + TRACE0("MIDI_IN_GetNumDevices()\n"); + return getMidiDeviceCount(SND_RAWMIDI_STREAM_INPUT); } diff --git a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.c b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.c index 74af23ef0420f86c025d0ee9df0e90067834feb3..7d2ac11923442835a582038a4fd7e45de2a1893d 100644 --- a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.c +++ b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -372,7 +372,7 @@ INT32 openMidiDevice(snd_rawmidi_stream_t direction, INT32 deviceIndex, snd_rawmidi_t* native_handle; snd_midi_event_t* event_parser = NULL; int err; - UINT32 deviceID; + UINT32 deviceID = 0; char devicename[100]; #ifdef ALSA_MIDI_USE_PLUGHW int usePlugHw = 1; diff --git a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCM.c b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCM.c index 58ca8abfcc2980a01998e3d2551d1cccc3fd2974..fb2ba3c5da36a940d8d7a7e741bdfac65b44cf85 100644 --- a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCM.c +++ b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCM.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -127,7 +127,7 @@ void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* cre int ret; int sampleSizeInBytes, significantBits, isSigned, isBigEndian, enc; int origSampleSizeInBytes, origSignificantBits; - int channels, minChannels, maxChannels; + unsigned int channels, minChannels, maxChannels; int rate, bitIndex; for (bitIndex = 0; bitIndex <= MAX_BIT_INDEX; bitIndex++) handledBits[bitIndex] = FALSE; @@ -152,7 +152,6 @@ void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* cre } } snd_pcm_hw_params_get_format_mask(hwParams, formatMask); -#ifdef ALSA_PCM_NEW_HW_PARAMS_API if (ret == 0) { ret = snd_pcm_hw_params_get_channels_min(hwParams, &minChannels); if (ret != 0) { @@ -165,13 +164,6 @@ void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* cre ERROR1("snd_pcm_hw_params_get_channels_max returned error %d\n", ret); } } -#else - minChannels = snd_pcm_hw_params_get_channels_min(hwParams); - maxChannels = snd_pcm_hw_params_get_channels_max(hwParams); - if (minChannels > maxChannels) { - ERROR2("MinChannels=%d, maxChannels=%d\n", minChannels, maxChannels); - } -#endif // since we queried the hw: device, for many soundcards, it will only // report the maximum number of channels (which is the only way to talk @@ -222,7 +214,7 @@ void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* cre } else { for (channels = minChannels; channels <= maxChannels; channels++) { DAUDIO_AddAudioFormat(creator, significantBits, - (channels < 0)?-1:(sampleSizeInBytes * channels), + sampleSizeInBytes * channels, channels, rate, enc, isSigned, isBigEndian); } @@ -254,7 +246,7 @@ typedef struct tag_AlsaPcmInfo { snd_pcm_sw_params_t* swParams; int bufferSizeInBytes; int frameSize; // storage size in Bytes - int periods; + unsigned int periods; snd_pcm_uframes_t periodSize; #ifdef GET_POSITION_METHOD2 // to be used exclusively by getBytePosition! @@ -305,8 +297,8 @@ int setHWParams(AlsaPcmInfo* info, int channels, int bufferSizeInFrames, snd_pcm_format_t format) { - unsigned int rrate; - int ret, dir, periods, periodTime; + unsigned int rrate, periodTime, periods; + int ret, dir; snd_pcm_uframes_t alsaBufferSizeInFrames = (snd_pcm_uframes_t) bufferSizeInFrames; /* choose all parameters */ @@ -335,12 +327,8 @@ int setHWParams(AlsaPcmInfo* info, } /* set the stream rate */ rrate = (int) (sampleRate + 0.5f); -#ifdef ALSA_PCM_NEW_HW_PARAMS_API dir = 0; ret = snd_pcm_hw_params_set_rate_near(info->handle, info->hwParams, &rrate, &dir); -#else - ret = snd_pcm_hw_params_set_rate_near(info->handle, info->hwParams, rrate, 0); -#endif if (ret < 0) { ERROR2("Rate %dHz not available for playback: %s\n", (int) (sampleRate+0.5f), snd_strerror(ret)); return FALSE; @@ -350,12 +338,7 @@ int setHWParams(AlsaPcmInfo* info, return FALSE; } /* set the buffer time */ -#ifdef ALSA_PCM_NEW_HW_PARAMS_API - ret = snd_pcm_hw_params_set_buffer_size_near(info->handle, info->hwParams, &alsaBufferSizeInFrames); -#else - ret = snd_pcm_hw_params_set_buffer_size_near(info->handle, info->hwParams, alsaBufferSizeInFrames); -#endif if (ret < 0) { ERROR2("Unable to set buffer size to %d frames: %s\n", (int) alsaBufferSizeInFrames, snd_strerror(ret)); @@ -366,12 +349,7 @@ int setHWParams(AlsaPcmInfo* info, if (bufferSizeInFrames > 1024) { dir = 0; periodTime = DEFAULT_PERIOD_TIME; -#ifdef ALSA_PCM_NEW_HW_PARAMS_API ret = snd_pcm_hw_params_set_period_time_near(info->handle, info->hwParams, &periodTime, &dir); -#else - periodTime = snd_pcm_hw_params_set_period_time_near(info->handle, info->hwParams, periodTime, &dir); - ret = periodTime; -#endif if (ret < 0) { ERROR2("Unable to set period time to %d: %s\n", DEFAULT_PERIOD_TIME, snd_strerror(ret)); return FALSE; @@ -380,12 +358,7 @@ int setHWParams(AlsaPcmInfo* info, /* set the period count for very small buffer sizes to 2 */ dir = 0; periods = 2; -#ifdef ALSA_PCM_NEW_HW_PARAMS_API ret = snd_pcm_hw_params_set_periods_near(info->handle, info->hwParams, &periods, &dir); -#else - periods = snd_pcm_hw_params_set_periods_near(info->handle, info->hwParams, periods, &dir); - ret = periods; -#endif if (ret < 0) { ERROR2("Unable to set period count to %d: %s\n", /*periods*/ 2, snd_strerror(ret)); return FALSE; @@ -421,12 +394,6 @@ int setSWParams(AlsaPcmInfo* info) { ERROR1("Unable to set avail min for playback: %s\n", snd_strerror(ret)); return FALSE; } - /* align all transfers to 1 sample */ - ret = snd_pcm_sw_params_set_xfer_align(info->handle, info->swParams, 1); - if (ret < 0) { - ERROR1("Unable to set transfer align: %s\n", snd_strerror(ret)); - return FALSE; - } /* write the parameters to the playback device */ ret = snd_pcm_sw_params(info->handle, info->swParams); if (ret < 0) { @@ -448,7 +415,6 @@ void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource, int ret = 0; AlsaPcmInfo* info = NULL; /* snd_pcm_uframes_t is 64 bit on 64-bit systems */ - snd_pcm_uframes_t alsaPeriodSize = 0; snd_pcm_uframes_t alsaBufferSizeInFrames = 0; @@ -484,21 +450,13 @@ void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource, bufferSizeInBytes / frameSize, format)) { info->frameSize = frameSize; -#ifdef ALSA_PCM_NEW_HW_PARAMS_API - ret = snd_pcm_hw_params_get_period_size(info->hwParams, &alsaPeriodSize, &dir); - info->periodSize = (int) alsaPeriodSize; + ret = snd_pcm_hw_params_get_period_size(info->hwParams, &info->periodSize, &dir); if (ret < 0) { ERROR1("ERROR: snd_pcm_hw_params_get_period: %s\n", snd_strerror(ret)); } snd_pcm_hw_params_get_periods(info->hwParams, &(info->periods), &dir); snd_pcm_hw_params_get_buffer_size(info->hwParams, &alsaBufferSizeInFrames); info->bufferSizeInBytes = (int) alsaBufferSizeInFrames * frameSize; -#else - info->periodSize = snd_pcm_hw_params_get_period_size(info->hwParams, &dir); - info->periods = snd_pcm_hw_params_get_periods(info->hwParams, &dir); - info->bufferSizeInBytes = snd_pcm_hw_params_get_buffer_size(info->hwParams) * frameSize; - ret = 0; -#endif TRACE3(" DAUDIO_Open: period size = %d frames, periods = %d. Buffer size: %d bytes.\n", (int) info->periodSize, info->periods, info->bufferSizeInBytes); } diff --git a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.h b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.h index c8d920f8de6b61a115a7faefa6c18e3230d390bb..ca911d2f486d918cd983eef7ea06690cbdd82383 100644 --- a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.h +++ b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ */ // define this with a later version of ALSA than 0.9.0rc3 +// (starting from 1.0.0 it became default behaviour) #define ALSA_PCM_NEW_HW_PARAMS_API #include #include "Utilities.h" diff --git a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_Ports.c b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_Ports.c index 465ecadf0f92b1de9052189706d9db49be0d62f6..0db0e6c4b53ae1f994a8c9a96d10e9d3595312f5 100644 --- a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_Ports.c +++ b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_Ports.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -380,7 +380,7 @@ void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) { void* controls[10]; int numControls; char* portName; - int isPlayback; + int isPlayback = 0; int isMono; int isStereo; char* type; diff --git a/src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.c b/src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.c index 1832401e4fbce430ad078923a776420c70edef4c..63addde831cf11b6784ac6cde39c07430b84d643 100644 --- a/src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.c +++ b/src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.c @@ -191,7 +191,7 @@ Java_sun_awt_X11_GtkFileDialogPeer_run(JNIEnv * env, jobject jpeer, fp_gdk_threads_enter(); - const char *title = (*env)->GetStringUTFChars(env, jtitle, 0); + const char *title = jtitle == NULL? "": (*env)->GetStringUTFChars(env, jtitle, 0); if (mode == 1) { /* Save action */ @@ -212,7 +212,9 @@ Java_sun_awt_X11_GtkFileDialogPeer_run(JNIEnv * env, jobject jpeer, } } - (*env)->ReleaseStringUTFChars(env, jtitle, title); + if (jtitle != NULL) { + (*env)->ReleaseStringUTFChars(env, jtitle, title); + } /* Set the directory */ if (jdir != NULL) { diff --git a/src/solaris/native/sun/java2d/loops/vis_IntArgbPre_Mask.c b/src/solaris/native/sun/java2d/loops/vis_IntArgbPre_Mask.c index 7eb84eb1e5f4b356ea21daf447e4b6f664c6017d..2b142c46c4836f97b3f9d42a3dada57383c12d7b 100644 --- a/src/solaris/native/sun/java2d/loops/vis_IntArgbPre_Mask.c +++ b/src/solaris/native/sun/java2d/loops/vis_IntArgbPre_Mask.c @@ -517,13 +517,15 @@ void ADD_SUFF(IntArgbPreSrcMaskFill)(void *rasBase, ADD_SUFF(AnyIntSetRect)(pRasInfo, 0, 0, width, height, fgColor, pPrim, pCompInfo); #else + void *pBase = pRasInfo->rasBase; + pRasInfo->rasBase = rasBase; if (cnstA != 0xff) { fgColor = (cnstA << 24) | (cnstR << 16) | (cnstG << 8) | cnstB; } ADD_SUFF(AnyIntSetRect)(pRasInfo, - pRasInfo->bounds.x1, pRasInfo->bounds.y1, - pRasInfo->bounds.x2, pRasInfo->bounds.y2, + 0, 0, width, height, fgColor, pPrim, pCompInfo); + pRasInfo->rasBase = pBase; #endif return; } @@ -582,11 +584,13 @@ void ADD_SUFF(FourByteAbgrPreSrcMaskFill)(void *rasBase, } if (pMask == NULL) { + void *pBase = pRasInfo->rasBase; + pRasInfo->rasBase = rasBase; fgColor = (cnstR << 24) | (cnstG << 16) | (cnstB << 8) | cnstA; ADD_SUFF(Any4ByteSetRect)(pRasInfo, - pRasInfo->bounds.x1, pRasInfo->bounds.y1, - pRasInfo->bounds.x2, pRasInfo->bounds.y2, + 0, 0, width, height, fgColor, pPrim, pCompInfo); + pRasInfo->rasBase = pBase; return; } diff --git a/src/solaris/native/sun/java2d/loops/vis_SrcMaskFill.c b/src/solaris/native/sun/java2d/loops/vis_SrcMaskFill.c index f5bf5c46e490f353827346d0e5bc618acbfb153a..170ab458d807abd716c24e7d05726aa92f5a974a 100644 --- a/src/solaris/native/sun/java2d/loops/vis_SrcMaskFill.c +++ b/src/solaris/native/sun/java2d/loops/vis_SrcMaskFill.c @@ -150,10 +150,12 @@ void ADD_SUFF(IntArgbSrcMaskFill)(void *rasBase, } if (pMask == NULL) { + void *pBase = pRasInfo->rasBase; + pRasInfo->rasBase = rasBase; ADD_SUFF(AnyIntSetRect)(pRasInfo, - pRasInfo->bounds.x1, pRasInfo->bounds.y1, - pRasInfo->bounds.x2, pRasInfo->bounds.y2, + 0, 0, width, height, fgColor, pPrim, pCompInfo); + pRasInfo->rasBase = pBase; return; } @@ -214,15 +216,17 @@ void ADD_SUFF(FourByteAbgrSrcMaskFill)(void *rasBase, cnstB = (fgColor ) & 0xff; if (pMask == NULL) { + void *pBase = pRasInfo->rasBase; + pRasInfo->rasBase = rasBase; if (cnstA == 0) { fgColor = 0; } else { fgColor = (fgColor << 8) | cnstA; } ADD_SUFF(Any4ByteSetRect)(pRasInfo, - pRasInfo->bounds.x1, pRasInfo->bounds.y1, - pRasInfo->bounds.x2, pRasInfo->bounds.y2, + 0, 0, width, height, fgColor, pPrim, pCompInfo); + pRasInfo->rasBase = pBase; return; } @@ -390,10 +394,12 @@ void ADD_SUFF(IntRgbSrcMaskFill)(void *rasBase, if (cnstA == 0) fgColor = 0; if (pMask == NULL) { + void *pBase = pRasInfo->rasBase; + pRasInfo->rasBase = rasBase; ADD_SUFF(AnyIntSetRect)(pRasInfo, - pRasInfo->bounds.x1, pRasInfo->bounds.y1, - pRasInfo->bounds.x2, pRasInfo->bounds.y2, + 0, 0, width, height, fgColor, pPrim, pCompInfo); + pRasInfo->rasBase = pBase; return; } @@ -458,10 +464,12 @@ void ADD_SUFF(IntBgrSrcMaskFill)(void *rasBase, } if (pMask == NULL) { + void *pBase = pRasInfo->rasBase; + pRasInfo->rasBase = rasBase; ADD_SUFF(AnyIntSetRect)(pRasInfo, - pRasInfo->bounds.x1, pRasInfo->bounds.y1, - pRasInfo->bounds.x2, pRasInfo->bounds.y2, + 0, 0, width, height, fgColor, pPrim, pCompInfo); + pRasInfo->rasBase = pBase; return; } @@ -526,10 +534,12 @@ void ADD_SUFF(ThreeByteBgrSrcMaskFill)(void *rasBase, } if (pMask == NULL) { + void *pBase = pRasInfo->rasBase; + pRasInfo->rasBase = rasBase; ADD_SUFF(Any3ByteSetRect)(pRasInfo, - pRasInfo->bounds.x1, pRasInfo->bounds.y1, - pRasInfo->bounds.x2, pRasInfo->bounds.y2, + 0, 0, width, height, fgColor, pPrim, pCompInfo); + pRasInfo->rasBase = pBase; return; } diff --git a/src/solaris/native/sun/xawt/XToolkit.c b/src/solaris/native/sun/xawt/XToolkit.c index 72024178041856852434e74adf7b8ee4ee2c8b73..4ea63143c701d91f1b8952f062e0d0e9a18de687 100644 --- a/src/solaris/native/sun/xawt/XToolkit.c +++ b/src/solaris/native/sun/xawt/XToolkit.c @@ -187,7 +187,9 @@ Java_java_awt_Component_initIDs "()Ljava/awt/Point;"); keyclass = (*env)->FindClass(env, "java/awt/event/KeyEvent"); - DASSERT (keyclass != NULL); + if (JNU_IsNull(env, keyclass)) { + return; + } componentIDs.isProxyActive = (*env)->GetFieldID(env, keyclass, "isProxyActive", @@ -715,8 +717,10 @@ Window get_xawt_root_shell(JNIEnv *env) { if (xawt_root_shell == None){ if (classXRootWindow == NULL){ jclass cls_tmp = (*env)->FindClass(env, "sun/awt/X11/XRootWindow"); - classXRootWindow = (jclass)(*env)->NewGlobalRef(env, cls_tmp); - (*env)->DeleteLocalRef(env, cls_tmp); + if (!JNU_IsNull(env, cls_tmp)) { + classXRootWindow = (jclass)(*env)->NewGlobalRef(env, cls_tmp); + (*env)->DeleteLocalRef(env, cls_tmp); + } } if( classXRootWindow != NULL) { methodGetXRootWindow = (*env)->GetStaticMethodID(env, classXRootWindow, "getXRootWindow", "()J"); diff --git a/src/windows/classes/sun/awt/windows/WComponentPeer.java b/src/windows/classes/sun/awt/windows/WComponentPeer.java index c4ba68e35d3a6c75208a6455bf177abe4c34fd65..01eb239961b3626f9b802fdc4e965188d1205015 100644 --- a/src/windows/classes/sun/awt/windows/WComponentPeer.java +++ b/src/windows/classes/sun/awt/windows/WComponentPeer.java @@ -999,6 +999,8 @@ public abstract class WComponentPeer extends WObjectPeer public void setBoundsOperation(int operation) { } + private volatile boolean isAccelCapable = true; + /** * Returns whether this component is capable of being hw accelerated. * More specifically, whether rendering to this component or a @@ -1009,11 +1011,22 @@ public abstract class WComponentPeer extends WObjectPeer * {@link GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSLUCENT * PERPIXEL_TRANSLUCENT}. * + * Another condition is if Xor paint mode was detected when rendering + * to an on-screen accelerated surface associated with this peer. + * in this case both on- and off-screen acceleration for this peer is + * disabled. + * * @return {@code true} if this component is capable of being hw * accelerated, {@code false} otherwise * @see GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSLUCENT */ public boolean isAccelCapable() { + if (!isAccelCapable || + !isContainingTopLevelAccelCapable((Component)target)) + { + return false; + } + boolean isTranslucent = SunToolkit.isContainingTopLevelTranslucent((Component)target); // D3D/OGL and translucent windows interacted poorly in Windows XP; @@ -1021,6 +1034,14 @@ public abstract class WComponentPeer extends WObjectPeer return !isTranslucent || Win32GraphicsEnvironment.isVistaOS(); } + /** + * Disables acceleration for this peer. + */ + public void disableAcceleration() { + isAccelCapable = false; + } + + native void setRectangularShape(int lox, int loy, int hix, int hiy, Region region); diff --git a/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java b/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java index 553d84156b222265ca6a32e06526f923599b015b..bc7dfd8631a4bd9e94a36f6dfe166ea4f797d408 100644 --- a/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java +++ b/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java @@ -437,6 +437,10 @@ public class D3DSurfaceData extends SurfaceData implements AccelSurface { protected int getElem(final int x, final int y, final SurfaceData sData) { + if (sData.isSurfaceLost()) { + return 0; + } + int retPixel; D3DRenderQueue rq = D3DRenderQueue.getInstance(); rq.lock(); @@ -456,6 +460,10 @@ public class D3DSurfaceData extends SurfaceData implements AccelSurface { protected void setElem(final int x, final int y, final int pixel, final SurfaceData sData) { + if (sData.isSurfaceLost()) { + return; + } + D3DRenderQueue rq = D3DRenderQueue.getInstance(); rq.lock(); try { @@ -512,15 +520,32 @@ public class D3DSurfaceData extends SurfaceData implements AccelSurface { sg2d.surfaceData.getTransparency() == Transparency.OPAQUE; } + /** + * If acceleration should no longer be used for this surface. + * This implementation flags to the manager that it should no + * longer attempt to re-create a D3DSurface. + */ + void disableAccelerationForSurface() { + if (offscreenImage != null) { + SurfaceManager sm = SurfaceManager.getManager(offscreenImage); + if (sm instanceof D3DVolatileSurfaceManager) { + setSurfaceLost(true); + ((D3DVolatileSurfaceManager)sm).setAccelerationEnabled(false); + } + } + } + public void validatePipe(SunGraphics2D sg2d) { TextPipe textpipe; boolean validated = false; // REMIND: the D3D pipeline doesn't support XOR!, more - // fixes will be needed below + // fixes will be needed below. For now we disable D3D rendering + // for the surface which had any XOR rendering done to. if (sg2d.compositeState >= sg2d.COMP_XOR) { super.validatePipe(sg2d); sg2d.imagepipe = d3dImagePipe; + disableAccelerationForSurface(); return; } @@ -894,8 +919,26 @@ public class D3DSurfaceData extends SurfaceData implements AccelSurface { return peer.getTarget(); } + @Override + void disableAccelerationForSurface() { + // for on-screen surfaces we need to make sure a backup GDI surface is + // is used until a new one is set (which may happen during a resize). We + // don't want the screen update maanger to replace the surface right way + // because it causes repainting issues in Swing, so we invalidate it, + // this will prevent SUM from issuing a replaceSurfaceData call. + setSurfaceLost(true); + invalidate(); + flush(); + peer.disableAcceleration(); + ScreenUpdateManager.getInstance().dropScreenSurface(this); + } + @Override void restoreSurface() { + if (!peer.isAccelCapable()) { + throw new InvalidPipeException("Onscreen acceleration " + + "disabled for this surface"); + } Window fsw = graphicsDevice.getFullScreenWindow(); if (fsw != null && fsw != peer.getTarget()) { throw new InvalidPipeException("Can't restore onscreen surface"+ diff --git a/src/windows/classes/sun/java2d/opengl/WGLVolatileSurfaceManager.java b/src/windows/classes/sun/java2d/opengl/WGLVolatileSurfaceManager.java index ba655bf00ba40c50327d0ff22f938606c54a6c7a..7c4fde1b640f1545d9b18674d9ecba45dd308a29 100644 --- a/src/windows/classes/sun/java2d/opengl/WGLVolatileSurfaceManager.java +++ b/src/windows/classes/sun/java2d/opengl/WGLVolatileSurfaceManager.java @@ -133,7 +133,9 @@ public class WGLVolatileSurfaceManager @Override protected boolean isConfigValid(GraphicsConfiguration gc) { - return ((gc == null) || (gc == vImg.getGraphicsConfig())); + return ((gc == null) || + ((gc instanceof WGLGraphicsConfig) && + (gc == vImg.getGraphicsConfig()))); } @Override diff --git a/src/windows/lib/tzmappings b/src/windows/lib/tzmappings index bbc3ca09ce23c0baebc929c26bbd0ddc05a628ee..7f6f0d36052fc4ab7f514482cb944c1205a1d391 100644 --- a/src/windows/lib/tzmappings +++ b/src/windows/lib/tzmappings @@ -188,5 +188,6 @@ UTC-02:920,920::GMT-0200: UTC-11:921,921::GMT-1100: Ulaanbaatar Standard Time:922,922::Asia/Ulaanbaatar: Venezuela Standard Time:923,923::America/Caracas: -Western Brazilian Standard Time:924,924:BR:America/Rio_Branco: -Armenian Standard Time:925,925:AM:Asia/Yerevan: +Magadan Standard Time:924,924::Asia/Magadan: +Western Brazilian Standard Time:925,925:BR:America/Rio_Branco: +Armenian Standard Time:926,926:AM:Asia/Yerevan: diff --git a/src/windows/native/sun/windows/Devices.h b/src/windows/native/sun/windows/Devices.h index e8324ce4c6ca1afe443f83f77c4ab413a26a982d..748ded20a3fc67d6250f5febb186048fd0c4f629 100644 --- a/src/windows/native/sun/windows/Devices.h +++ b/src/windows/native/sun/windows/Devices.h @@ -54,7 +54,7 @@ static BOOL UpdateInstance(JNIEnv *env); InstanceAccess& operator=(const InstanceAccess&); InstanceAccess* operator&(); }; -friend InstanceAccess; +friend class InstanceAccess; private: Devices(int numElements); diff --git a/src/windows/native/sun/windows/awt.h b/src/windows/native/sun/windows/awt.h index e93dcb195cf981756ebb711d58c0e1ef7838892e..0ae6511c2368fc6269d308751b4e05d0cb0f3c72 100644 --- a/src/windows/native/sun/windows/awt.h +++ b/src/windows/native/sun/windows/awt.h @@ -173,7 +173,7 @@ extern JavaVM *jvm; // Platform encoding is Unicode (UTF-16), re-define JNU_ functions // to proper JNI functions. -#define JNU_NewStringPlatform(env, x) env->NewString(reinterpret_cast(x), static_cast(_tcslen(x))) +#define JNU_NewStringPlatform(env, x) env->NewString(reinterpret_cast(x), static_cast(_tcslen(x))) #define JNU_GetStringPlatformChars(env, x, y) reinterpret_cast(env->GetStringChars(x, y)) #define JNU_ReleaseStringPlatformChars(env, x, y) env->ReleaseStringChars(x, reinterpret_cast(y)) diff --git a/src/windows/native/sun/windows/awt_Debug.cpp b/src/windows/native/sun/windows/awt_Debug.cpp index 3d6c424dbf2ec20a3db80411146ac8c2831900de..42e099bb59985e58fdf15c23e51071a78f65167d 100644 --- a/src/windows/native/sun/windows/awt_Debug.cpp +++ b/src/windows/native/sun/windows/awt_Debug.cpp @@ -47,12 +47,21 @@ void * operator new(size_t size, const char * filename, int linenumber) { return ptr; } +void * operator new[](size_t size, const char * filename, int linenumber) { + void * ptr = DMem_AllocateBlock(size, filename, linenumber); + if (ptr == NULL) { + throw std::bad_alloc(); + } + + return ptr; +} + #if _MSC_VER >= 1200 void operator delete(void *ptr, const char*, int) { DASSERTMSG(FALSE, "This version of 'delete' should never get called!!!"); } #endif -void operator delete(void *ptr) { +void operator delete(void *ptr) throw() { DMem_FreeBlock(ptr); } diff --git a/src/windows/native/sun/windows/awt_Debug.h b/src/windows/native/sun/windows/awt_Debug.h index 9fc4ab6b7d3214b2f3625f31375639a5a2725fbd..729e652621a2c4aa1593ca7a9a5a9515e2ce5090 100644 --- a/src/windows/native/sun/windows/awt_Debug.h +++ b/src/windows/native/sun/windows/awt_Debug.h @@ -48,11 +48,14 @@ }; extern void * operator new(size_t size, const char * filename, int linenumber); + extern void * operator new[](size_t size, const char * filename, int linenumber); + #if _MSC_VER >= 1200 /* VC 6.0 is more strict about enforcing matching placement new & delete */ extern void operator delete(void *ptr, const char*, int); #endif - extern void operator delete(void *ptr); + + extern void operator delete(void *ptr) throw(); extern void DumpClipRectangle(const char * file, int line, int argc, const char * fmt, va_list arglist); extern void DumpUpdateRectangle(const char * file, int line, int argc, const char * fmt, va_list arglist); diff --git a/src/windows/native/sun/windows/awt_DesktopProperties.cpp b/src/windows/native/sun/windows/awt_DesktopProperties.cpp index cf69d1384706df51410667fd89b3a07172e5d9e5..8d13a97249a090a69f79cb1572df08c0c7fe2f27 100644 --- a/src/windows/native/sun/windows/awt_DesktopProperties.cpp +++ b/src/windows/native/sun/windows/awt_DesktopProperties.cpp @@ -650,7 +650,7 @@ UINT AwtDesktopProperties::GetIntegerParameter(UINT spi) { } void AwtDesktopProperties::SetStringProperty(LPCTSTR propName, LPTSTR value) { - jstring key = JNU_NewStringPlatform(GetEnv(), const_cast(propName)); + jstring key = JNU_NewStringPlatform(GetEnv(), propName); GetEnv()->CallVoidMethod(self, AwtDesktopProperties::setStringPropertyID, key, JNU_NewStringPlatform(GetEnv(), value)); @@ -658,7 +658,7 @@ void AwtDesktopProperties::SetStringProperty(LPCTSTR propName, LPTSTR value) { } void AwtDesktopProperties::SetIntegerProperty(LPCTSTR propName, int value) { - jstring key = JNU_NewStringPlatform(GetEnv(), const_cast(propName)); + jstring key = JNU_NewStringPlatform(GetEnv(), propName); GetEnv()->CallVoidMethod(self, AwtDesktopProperties::setIntegerPropertyID, key, (jint)value); @@ -666,7 +666,7 @@ void AwtDesktopProperties::SetIntegerProperty(LPCTSTR propName, int value) { } void AwtDesktopProperties::SetBooleanProperty(LPCTSTR propName, BOOL value) { - jstring key = JNU_NewStringPlatform(GetEnv(), const_cast(propName)); + jstring key = JNU_NewStringPlatform(GetEnv(), propName); GetEnv()->CallVoidMethod(self, AwtDesktopProperties::setBooleanPropertyID, key, value ? JNI_TRUE : JNI_FALSE); @@ -674,7 +674,7 @@ void AwtDesktopProperties::SetBooleanProperty(LPCTSTR propName, BOOL value) { } void AwtDesktopProperties::SetColorProperty(LPCTSTR propName, DWORD value) { - jstring key = JNU_NewStringPlatform(GetEnv(), const_cast(propName)); + jstring key = JNU_NewStringPlatform(GetEnv(), propName); GetEnv()->CallVoidMethod(self, AwtDesktopProperties::setColorPropertyID, key, GetRValue(value), GetGValue(value), @@ -726,7 +726,7 @@ void AwtDesktopProperties::SetFontProperty(HDC dc, int fontID, style |= java_awt_Font_ITALIC; } - jstring key = JNU_NewStringPlatform(GetEnv(), const_cast(propName)); + jstring key = JNU_NewStringPlatform(GetEnv(), propName); GetEnv()->CallVoidMethod(self, AwtDesktopProperties::setFontPropertyID, key, fontName, style, pointSize); @@ -744,7 +744,7 @@ void AwtDesktopProperties::SetFontProperty(LPCTSTR propName, const LOGFONT & fon jint pointSize; jint style; - fontName = JNU_NewStringPlatform(GetEnv(), const_cast(font.lfFaceName)); + fontName = JNU_NewStringPlatform(GetEnv(), font.lfFaceName); #if 0 HDC hdc; @@ -767,7 +767,7 @@ void AwtDesktopProperties::SetFontProperty(LPCTSTR propName, const LOGFONT & fon style |= java_awt_Font_ITALIC; } - jstring key = JNU_NewStringPlatform(GetEnv(), const_cast(propName)); + jstring key = JNU_NewStringPlatform(GetEnv(), propName); GetEnv()->CallVoidMethod(self, AwtDesktopProperties::setFontPropertyID, key, fontName, style, pointSize); @@ -776,8 +776,8 @@ void AwtDesktopProperties::SetFontProperty(LPCTSTR propName, const LOGFONT & fon } void AwtDesktopProperties::SetSoundProperty(LPCTSTR propName, LPCTSTR winEventName) { - jstring key = JNU_NewStringPlatform(GetEnv(), const_cast(propName)); - jstring event = JNU_NewStringPlatform(GetEnv(), const_cast(winEventName)); + jstring key = JNU_NewStringPlatform(GetEnv(), propName); + jstring event = JNU_NewStringPlatform(GetEnv(), winEventName); GetEnv()->CallVoidMethod(self, AwtDesktopProperties::setSoundPropertyID, key, event); diff --git a/src/windows/native/sun/windows/awt_Dialog.cpp b/src/windows/native/sun/windows/awt_Dialog.cpp index 6174750a420e0dd52d5c90718d3f30e7c8da8711..3de8495698975a98de4270290f65c006989fe883 100644 --- a/src/windows/native/sun/windows/awt_Dialog.cpp +++ b/src/windows/native/sun/windows/awt_Dialog.cpp @@ -230,7 +230,7 @@ LRESULT CALLBACK AwtDialog::ModalFilterProc(int code, if (::IsIconic(hWnd)) { ::ShowWindow(hWnd, SW_RESTORE); } - PopupAllDialogs(blocker, TRUE, ::GetForegroundWindow(), FALSE); + PopupBlockers(blocker, TRUE, ::GetForegroundWindow(), FALSE); // return 1 to prevent the system from allowing the operation return 1; } @@ -256,7 +256,7 @@ LRESULT CALLBACK AwtDialog::MouseHookProc(int nCode, HWND blocker = AwtWindow::GetModalBlocker(AwtComponent::GetTopLevelParentForWindow(hWnd)); if (::IsWindow(blocker)) { BOOL onTaskbar = !(::WindowFromPoint(mhs->pt) == hWnd); - PopupAllDialogs(hWnd, FALSE, ::GetForegroundWindow(), onTaskbar); + PopupBlockers(blocker, FALSE, ::GetForegroundWindow(), onTaskbar); // return a nonzero value to prevent the system from passing // the message to the target window procedure return 1; @@ -268,60 +268,60 @@ LRESULT CALLBACK AwtDialog::MouseHookProc(int nCode, } /* - * The function goes through the heirarchy of the blocker dialogs and - * popups all the dialogs. Note that the function starts from the top - * blocker dialog and goes down to the dialog which is the bottom dialog. - * Using another traversal may cause to the flickering issue as a bottom - * dialog will cover a top dialog for some period of time. + * The function goes through the hierarchy of the blockers and + * popups all the blockers. Note that the function starts from the top + * blocker and goes down to the blocker which is the bottom one. + * Using another traversal algorithm (bottom->top) may cause to flickering + * as the bottom blocker will cover the top blocker for a while. */ -void AwtDialog::PopupAllDialogs(HWND dialog, BOOL isModalHook, HWND prevFGWindow, BOOL onTaskbar) +void AwtDialog::PopupBlockers(HWND blocker, BOOL isModalHook, HWND prevFGWindow, BOOL onTaskbar) { - HWND blocker = AwtWindow::GetModalBlocker(dialog); - BOOL isBlocked = ::IsWindow(blocker); - if (isBlocked) { - PopupAllDialogs(blocker, isModalHook, prevFGWindow, onTaskbar); + HWND nextBlocker = AwtWindow::GetModalBlocker(blocker); + BOOL nextBlockerExists = ::IsWindow(nextBlocker); + if (nextBlockerExists) { + PopupBlockers(nextBlocker, isModalHook, prevFGWindow, onTaskbar); } - PopupOneDialog(dialog, blocker, isModalHook, prevFGWindow, onTaskbar); + PopupBlocker(blocker, nextBlocker, isModalHook, prevFGWindow, onTaskbar); } /* - * The function popups the dialog, it distinguishes non-blocked dialogs - * and activates the dialogs (sets as foreground window). If the dialog is - * blocked, then it changes the Z-order of the dialog. + * The function popups the blocker, for a non-blocked blocker we need + * to activate the blocker but if a blocker is blocked, then we need + * to change z-order of the blocker placing the blocker under the next blocker. */ -void AwtDialog::PopupOneDialog(HWND dialog, HWND blocker, BOOL isModalHook, HWND prevFGWindow, BOOL onTaskbar) +void AwtDialog::PopupBlocker(HWND blocker, HWND nextBlocker, BOOL isModalHook, HWND prevFGWindow, BOOL onTaskbar) { - if (dialog == AwtToolkit::GetInstance().GetHWnd()) { + if (blocker == AwtToolkit::GetInstance().GetHWnd()) { return; } // fix for 6494032 - if (isModalHook && !::IsWindowVisible(dialog)) { - ::ShowWindow(dialog, SW_SHOWNA); + if (isModalHook && !::IsWindowVisible(blocker)) { + ::ShowWindow(blocker, SW_SHOWNA); } - BOOL isBlocked = ::IsWindow(blocker); + BOOL nextBlockerExists = ::IsWindow(nextBlocker); UINT flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE; - if (isBlocked) { + if (nextBlockerExists) { // Fix for 6829546: if blocker is a top-most window, but window isn't, then // calling ::SetWindowPos(dialog, blocker, ...) makes window top-most as well - BOOL isBlockerTopmost = (::GetWindowLong(blocker, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0; - BOOL isDialogTopmost = (::GetWindowLong(dialog, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0; - if (!isBlockerTopmost || isDialogTopmost) { - ::SetWindowPos(dialog, blocker, 0, 0, 0, 0, flags); + BOOL topmostNextBlocker = (::GetWindowLong(nextBlocker, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0; + BOOL topmostBlocker = (::GetWindowLong(blocker, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0; + if (!topmostNextBlocker || topmostBlocker) { + ::SetWindowPos(blocker, nextBlocker, 0, 0, 0, 0, flags); } else { - ::SetWindowPos(dialog, HWND_TOP, 0, 0, 0, 0, flags); + ::SetWindowPos(blocker, HWND_TOP, 0, 0, 0, 0, flags); } } else { - ::SetWindowPos(dialog, HWND_TOP, 0, 0, 0, 0, flags); + ::SetWindowPos(blocker, HWND_TOP, 0, 0, 0, 0, flags); // no beep/flash if the mouse was clicked in the taskbar menu // or the dialog is currently inactive - if (!isModalHook && !onTaskbar && (dialog == prevFGWindow)) { - AnimateModalBlocker(dialog); + if (!isModalHook && !onTaskbar && (blocker == prevFGWindow)) { + AnimateModalBlocker(blocker); } - ::BringWindowToTop(dialog); - ::SetForegroundWindow(dialog); + ::BringWindowToTop(blocker); + ::SetForegroundWindow(blocker); } } diff --git a/src/windows/native/sun/windows/awt_Dialog.h b/src/windows/native/sun/windows/awt_Dialog.h index 5aa99dfcec318e40c22cf8e9dc94043510dde28e..15918a6fd887e5dfffb5bd3c5b33d3ff27a25ffd 100644 --- a/src/windows/native/sun/windows/awt_Dialog.h +++ b/src/windows/native/sun/windows/awt_Dialog.h @@ -113,8 +113,8 @@ private: */ static void ModalPerformActivation(HWND hWnd); - static void PopupAllDialogs(HWND dialog, BOOL isModalHook, HWND prevFGWindow, BOOL onTaskbar); - static void PopupOneDialog(HWND dialog, HWND blocker, BOOL isModalHook, HWND prevFGWindow, BOOL onTaskbar); + static void PopupBlockers(HWND blocker, BOOL isModalHook, HWND prevFGWindow, BOOL onTaskbar); + static void PopupBlocker(HWND blocker, HWND nextBlocker, BOOL isModalHook, HWND prevFGWindow, BOOL onTaskbar); public: diff --git a/src/windows/native/sun/windows/awt_TextArea.h b/src/windows/native/sun/windows/awt_TextArea.h index 27b7b004b97345558881e29e69944d07bd178555..19a44e7681b08d4e6efeff40815c3ea2294abb85 100644 --- a/src/windows/native/sun/windows/awt_TextArea.h +++ b/src/windows/native/sun/windows/awt_TextArea.h @@ -41,9 +41,6 @@ class AwtTextArea : public AwtTextComponent { - // inner classes - class OleCallback; - public: /* java.awt.TextArea fields ids */ @@ -89,36 +86,11 @@ public: static void _ReplaceText(void *param); protected: - INLINE static OleCallback& GetOleCallback() { return sm_oleCallback; } - void EditSetSel(CHARRANGE &cr); - void EditGetSel(CHARRANGE &cr); - LONG EditGetCharFromPos(POINT& pt); - private: - // RichEdit 1.0 control generates EN_CHANGE notifications not only - // on text changes, but also on any character formatting change. - // This flag is true when the latter case is detected. - BOOL m_bIgnoreEnChange; - - // RichEdit 1.0 control undoes a character formatting change - // if it is the latest. We don't create our own undo buffer, - // but just prohibit undo in case if the latest operation - // is a formatting change. - BOOL m_bCanUndo; - - HWND m_hEditCtrl; - static WNDPROC sm_pDefWindowProc; - - LONG m_lHDeltaAccum; - LONG m_lVDeltaAccum; - - - static OleCallback sm_oleCallback; /***************************************************************** * Inner class OleCallback declaration. */ - - class AwtTextArea::OleCallback : public IRichEditOleCallback { + class OleCallback : public IRichEditOleCallback { public: OleCallback(); @@ -143,7 +115,32 @@ protected: CHARRANGE FAR * pchrg, HMENU FAR * phmenu); private: ULONG m_refs; // Reference count - }; + };//OleCallback class + + INLINE static OleCallback& GetOleCallback() { return sm_oleCallback; } + void EditSetSel(CHARRANGE &cr); + void EditGetSel(CHARRANGE &cr); + LONG EditGetCharFromPos(POINT& pt); + private: + // RichEdit 1.0 control generates EN_CHANGE notifications not only + // on text changes, but also on any character formatting change. + // This flag is true when the latter case is detected. + BOOL m_bIgnoreEnChange; + + // RichEdit 1.0 control undoes a character formatting change + // if it is the latest. We don't create our own undo buffer, + // but just prohibit undo in case if the latest operation + // is a formatting change. + BOOL m_bCanUndo; + + HWND m_hEditCtrl; + static WNDPROC sm_pDefWindowProc; + + LONG m_lHDeltaAccum; + LONG m_lVDeltaAccum; + + + static OleCallback sm_oleCallback; }; diff --git a/src/windows/native/sun/windows/awt_Toolkit.h b/src/windows/native/sun/windows/awt_Toolkit.h index f1bfd119f14ff1ddaebbba2e7ffbf5ded3b756df..3ebd465caca2bee26d6f9fb7f3e202cb00917591 100644 --- a/src/windows/native/sun/windows/awt_Toolkit.h +++ b/src/windows/native/sun/windows/awt_Toolkit.h @@ -110,7 +110,7 @@ class CriticalSection { private: const CriticalSection& critSec; }; - friend Lock; + friend class Lock; private: CRITICAL_SECTION rep; diff --git a/test/com/sun/awt/Translucency/WindowOpacity.java b/test/com/sun/awt/Translucency/WindowOpacity.java index bf4e74dd48fe25832bf921cab4af73af0904e0b8..a5d80265d6070ebf40e8b447e1812cb2c341348b 100644 --- a/test/com/sun/awt/Translucency/WindowOpacity.java +++ b/test/com/sun/awt/Translucency/WindowOpacity.java @@ -64,6 +64,7 @@ public class WindowOpacity boolean passed; Frame f = new Frame("Opacity test"); + f.setUndecorated(true); passed = false; try { diff --git a/test/java/awt/FontClass/FontPrivilege.java b/test/java/awt/FontClass/FontPrivilege.java index d633f4d3fec7dd5355bf720e0c474f68da682db3..24fd5116c8cbcef17f723fb98726ba4d13e7b1da 100644 --- a/test/java/awt/FontClass/FontPrivilege.java +++ b/test/java/awt/FontClass/FontPrivilege.java @@ -25,7 +25,7 @@ * @test * @bug 5010310 6319835 6904882 6968373 * @summary test fonts can be created in the presence of a security manager - * @run main/othervm/secure=java.lang.SecurityManager FontPrivilege + * @run main FontPrivilege */ import java.awt.Font; @@ -33,6 +33,8 @@ import java.awt.Font; public class FontPrivilege { public static void main(String[] args) throws Exception { + System.setSecurityManager(new SecurityManager()); + new Font("Helvetica", Font.PLAIN, 12).getFamily(); new Font("foo bar", Font.PLAIN, 12).getFamily(); } diff --git a/test/java/awt/Graphics2D/DrawString/LCDTextSrcEa.java b/test/java/awt/Graphics2D/DrawString/LCDTextSrcEa.java new file mode 100644 index 0000000000000000000000000000000000000000..74c228eab67fdac7e9773b4b6248c72b2ec9074d --- /dev/null +++ b/test/java/awt/Graphics2D/DrawString/LCDTextSrcEa.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +/** + * @test + * @bug 6996867 + * @summary Render as LCD Text in SrcEa composite mode. + */ + +import java.awt.*; +import java.awt.event.*; +import java.awt.image.*; + +public class LCDTextSrcEa extends Component { + + static int SZ=150; + BufferedImage target = + new BufferedImage(SZ, SZ, BufferedImage.TYPE_INT_RGB); + + public static void main(String args[]) { + Frame f = new Frame("LCD Text SrcEa Test"); + f.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + System.exit(0); + } + }); + LCDTextSrcEa td = new LCDTextSrcEa(); + f.add("Center", td); + f.pack(); + f.setVisible(true); + } + + public Dimension getPreferredSize() { + return new Dimension(SZ,SZ); + } + + public void paint(Graphics gx) { + + Graphics2D g2d = (Graphics2D) target.getGraphics(); + g2d.setColor(Color.white); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, 0.01f)); + g2d.setRenderingHint( + RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VBGR); + g2d.setRenderingHint( + RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + g2d.setColor(Color.black); + g2d.drawString("Some sample text.", 10, 20); + gx.drawImage(target, 0, 0, null); + boolean nongrey = false; + //Test BI: should be some non-greyscale color + for (int px=0;px> 16; + int g = (rgb & 0x00ff00) >> 8; + int b = (rgb & 0x0000ff); + if (r != g || r !=b || g != b) { + nongrey=true; + break; + } + } + } + if (!nongrey) { + throw new RuntimeException("No LCD text found"); + } + } +} diff --git a/test/java/awt/Graphics2D/RenderClipTest/6766342.tests b/test/java/awt/Graphics2D/RenderClipTest/6766342.tests new file mode 100644 index 0000000000000000000000000000000000000000..17cf06850d6fc23cd49f5be566634e61cb8c60ef --- /dev/null +++ b/test/java/awt/Graphics2D/RenderClipTest/6766342.tests @@ -0,0 +1,3 @@ +Filled AA Pure Rect(5, 29.4, 10, 10) +Stroked AA Pure Rect(5, 4.4, 10, 10) +Stroked AA Line(20, 20, -10, 20) diff --git a/test/java/awt/Graphics2D/RenderClipTest/RenderClipTest.java b/test/java/awt/Graphics2D/RenderClipTest/RenderClipTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e920c4486715d65cd349a820d533d98f15d92b39 --- /dev/null +++ b/test/java/awt/Graphics2D/RenderClipTest/RenderClipTest.java @@ -0,0 +1,1634 @@ +/* + * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +/* + * @test + * @bug 6766342 + * @summary Tests clipping invariance for AA rectangle and line primitives + * @run main RenderClipTest -strict -readfile 6766342.tests + * @run main RenderClipTest -rectsuite -count 10 + */ + +import java.awt.*; +import java.awt.geom.*; +import java.awt.image.*; +import java.awt.event.*; +import java.util.Vector; +import java.io.*; + +public class RenderClipTest { + public static double randDblCoord() { + return Math.random()*60 - 10; + } + + public static float randFltCoord() { + return (float) randDblCoord(); + } + + public static int randIntCoord() { + return (int) Math.round(randDblCoord()); + } + + public static int randInt(int n) { + return ((int) (Math.random() * (n*4))) >> 2; + } + + static int numtests; + static int numerrors; + static int numfillfailures; + static int numstrokefailures; + static int maxerr; + + static boolean useAA; + static boolean strokePure; + static boolean testFill; + static boolean testDraw; + static boolean silent; + static boolean verbose; + static boolean strict; + static boolean showErrors; + static float lw; + static double rot; + + static BufferedImage imgref; + static BufferedImage imgtst; + + static Graphics2D grefclear; + static Graphics2D gtstclear; + static Graphics2D grefrender; + static Graphics2D gtstrender; + + public static abstract class AnnotatedRenderOp { + public static AnnotatedRenderOp parse(String str) { + AnnotatedRenderOp ar; + if (((ar = Cubic.tryparse(str)) != null) || + ((ar = Quad.tryparse(str)) != null) || + ((ar = Poly.tryparse(str)) != null) || + ((ar = Path.tryparse(str)) != null) || + ((ar = Rect.tryparse(str)) != null) || + ((ar = Line.tryparse(str)) != null) || + ((ar = RectMethod.tryparse(str)) != null) || + ((ar = LineMethod.tryparse(str)) != null)) + { + return ar; + } + System.err.println("Unable to parse shape: "+str); + return null; + } + + public abstract void randomize(); + + public abstract void fill(Graphics2D g2d); + + public abstract void draw(Graphics2D g2d); + } + + public static abstract class AnnotatedShapeOp extends AnnotatedRenderOp { + public abstract Shape getShape(); + + public void fill(Graphics2D g2d) { + g2d.fill(getShape()); + } + + public void draw(Graphics2D g2d) { + g2d.draw(getShape()); + } + } + + public static void usage(String err) { + if (err != null) { + System.err.println(err); + } + System.err.println("usage: java RenderClipTest "+ + "[-read[file F]] [-rectsuite] [-fill] [-draw]"); + System.err.println(" "+ + "[-aa] [-pure] [-lw N] [-rot N]"); + System.err.println(" "+ + "[-rectmethod] [-linemethod] [-rect] [-line]"); + System.err.println(" "+ + "[-cubic] [-quad] [-poly] [-path]"); + System.err.println(" "+ + "[-silent] [-verbose] [-showerr] [-count N]"); + System.err.println(" "+ + "[-strict] [-usage]"); + System.err.println(" -read Read test data from stdin"); + System.err.println(" -readfile F Read test data from file F"); + System.err.println(" -rectsuite Run a suite of rect/line tests"); + System.err.println(" -fill Test g.fill*(...)"); + System.err.println(" -draw Test g.draw*(...)"); + System.err.println(" -aa Use antialiased rendering"); + System.err.println(" -pure Use STROKE_PURE hint"); + System.err.println(" -lw N Test line widths of N "+ + "(default 1.0)"); + System.err.println(" -rot N Test rotation by N degrees "+ + "(default 0.0)"); + System.err.println(" -rectmethod Test fillRect/drawRect methods"); + System.err.println(" -linemethod Test drawLine method"); + System.err.println(" -rect Test Rectangle2D shapes"); + System.err.println(" -line Test Line2D shapes"); + System.err.println(" -cubic Test CubicCurve2D shapes"); + System.err.println(" -quad Test QuadCurve2D shapes"); + System.err.println(" -poly Test Polygon shapes"); + System.err.println(" -path Test GeneralPath shapes"); + System.err.println(" -silent Do not print out error curves"); + System.err.println(" -verbose Print out progress info"); + System.err.println(" -showerr Display errors on screen"); + System.err.println(" -count N N tests per shape, then exit "+ + "(default 1000)"); + System.err.println(" -strict All failures are important"); + System.err.println(" -usage Print this help, then exit"); + System.exit((err != null) ? -1 : 0); + } + + public static void main(String argv[]) { + boolean readTests = false; + String readFile = null; + boolean rectsuite = false; + int count = 1000; + lw = 1.0f; + rot = 0.0; + Vector testOps = new Vector(); + for (int i = 0; i < argv.length; i++) { + String arg = argv[i].toLowerCase(); + if (arg.equals("-aa")) { + useAA = true; + } else if (arg.equals("-pure")) { + strokePure = true; + } else if (arg.equals("-fill")) { + testFill = true; + } else if (arg.equals("-draw")) { + testDraw = true; + } else if (arg.equals("-lw")) { + if (i+1 >= argv.length) { + usage("Missing argument: "+argv[i]); + } + lw = Float.parseFloat(argv[++i]); + } else if (arg.equals("-rot")) { + if (i+1 >= argv.length) { + usage("Missing argument: "+argv[i]); + } + rot = Double.parseDouble(argv[++i]); + } else if (arg.equals("-cubic")) { + testOps.add(new Cubic()); + } else if (arg.equals("-quad")) { + testOps.add(new Quad()); + } else if (arg.equals("-poly")) { + testOps.add(new Poly()); + } else if (arg.equals("-path")) { + testOps.add(new Path()); + } else if (arg.equals("-rect")) { + testOps.add(new Rect()); + } else if (arg.equals("-line")) { + testOps.add(new Line()); + } else if (arg.equals("-rectmethod")) { + testOps.add(new RectMethod()); + } else if (arg.equals("-linemethod")) { + testOps.add(new LineMethod()); + } else if (arg.equals("-verbose")) { + verbose = true; + } else if (arg.equals("-strict")) { + strict = true; + } else if (arg.equals("-silent")) { + silent = true; + } else if (arg.equals("-showerr")) { + showErrors = true; + } else if (arg.equals("-readfile")) { + if (i+1 >= argv.length) { + usage("Missing argument: "+argv[i]); + } + readTests = true; + readFile = argv[++i]; + } else if (arg.equals("-read")) { + readTests = true; + readFile = null; + } else if (arg.equals("-rectsuite")) { + rectsuite = true; + } else if (arg.equals("-count")) { + if (i+1 >= argv.length) { + usage("Missing argument: "+argv[i]); + } + count = Integer.parseInt(argv[++i]); + } else if (arg.equals("-usage")) { + usage(null); + } else { + usage("Unknown argument: "+argv[i]); + } + } + if (readTests) { + if (rectsuite || testDraw || testFill || + useAA || strokePure || + lw != 1.0f || rot != 0.0 || + testOps.size() > 0) + { + usage("Should not specify test types with -read options"); + } + } else if (rectsuite) { + if (testDraw || testFill || + useAA || strokePure || + lw != 1.0f || rot != 0.0 || + testOps.size() > 0) + { + usage("Should not specify test types with -rectsuite option"); + } + } else { + if (!testDraw && !testFill) { + usage("No work: Must specify one or both of "+ + "-fill or -draw"); + } + if (testOps.size() == 0) { + usage("No work: Must specify one or more of "+ + "-rect[method], -line[method], "+ + "-cubic, -quad, -poly, or -path"); + } + } + initImages(); + if (readTests) { + try { + InputStream is; + if (readFile == null) { + is = System.in; + } else { + File f = + new File(System.getProperty("test.src", "."), + readFile); + is = new FileInputStream(f); + } + parseAndRun(is); + } catch (IOException e) { + throw new RuntimeException(e); + } + } else if (rectsuite) { + runRectSuite(count); + } else { + initGCs(); + for (int k = 0; k < testOps.size(); k++) { + AnnotatedRenderOp ar = testOps.get(k); + runRandomTests(ar, count); + } + disposeGCs(); + } + grefclear.dispose(); + gtstclear.dispose(); + grefclear = gtstclear = null; + reportStatistics(); + } + + public static int reportStatistics() { + String connector = ""; + if (numfillfailures > 0) { + System.out.print(numfillfailures+" fills "); + connector = "and "; + } + if (numstrokefailures > 0) { + System.out.print(connector+numstrokefailures+" strokes "); + } + int totalfailures = numfillfailures + numstrokefailures; + if (totalfailures == 0) { + System.out.print("0 "); + } + System.out.println("out of "+numtests+" tests failed..."); + int critical = numerrors; + if (strict) { + critical += totalfailures; + } + if (critical > 0) { + throw new RuntimeException(critical+" tests had critical errors"); + } + System.out.println("No tests had critical errors"); + return (numerrors+totalfailures); + } + + public static void runRectSuite(int count) { + AnnotatedRenderOp ops[] = { + new Rect(), + new RectMethod(), + new Line(), + new LineMethod(), + }; + // Sometimes different fill algorithms are chosen for + // thin and wide line modes, make sure we test both... + float filllinewidths[] = { 0.0f, 2.0f }; + float drawlinewidths[] = { 0.0f, 0.5f, 1.0f, + 2.0f, 2.5f, + 5.0f, 5.3f }; + double rotations[] = { 0.0, 15.0, 90.0, + 135.0, 180.0, + 200.0, 270.0, + 300.0}; + for (AnnotatedRenderOp ar: ops) { + for (double r: rotations) { + rot = r; + for (int i = 0; i < 8; i++) { + float linewidths[]; + if ((i & 1) == 0) { + if ((ar instanceof Line) || + (ar instanceof LineMethod)) + { + continue; + } + testFill = true; + testDraw = false; + linewidths = filllinewidths; + } else { + testFill = false; + testDraw = true; + linewidths = drawlinewidths; + } + useAA = ((i & 2) != 0); + strokePure = ((i & 4) != 0); + for (float w : linewidths) { + lw = w; + runSuiteTests(ar, count); + } + } + } + } + } + + public static void runSuiteTests(AnnotatedRenderOp ar, int count) { + if (verbose) { + System.out.print("Running "); + System.out.print(testFill ? "Fill " : "Draw "); + System.out.print(BaseName(ar)); + if (useAA) { + System.out.print(" AA"); + } + if (strokePure) { + System.out.print(" Pure"); + } + if (lw != 1.0f) { + System.out.print(" lw="+lw); + } + if (rot != 0.0f) { + System.out.print(" rot="+rot); + } + System.out.println(); + } + initGCs(); + runRandomTests(ar, count); + disposeGCs(); + } + + public static String BaseName(AnnotatedRenderOp ar) { + String s = ar.toString(); + int leftparen = s.indexOf('('); + if (leftparen >= 0) { + s = s.substring(0, leftparen); + } + return s; + } + + public static void runRandomTests(AnnotatedRenderOp ar, int count) { + for (int i = 0; i < count; i++) { + ar.randomize(); + if (testDraw) { + test(ar, false); + } + if (testFill) { + test(ar, true); + } + } + } + + public static void initImages() { + imgref = new BufferedImage(40, 40, BufferedImage.TYPE_INT_RGB); + imgtst = new BufferedImage(40, 40, BufferedImage.TYPE_INT_RGB); + grefclear = imgref.createGraphics(); + gtstclear = imgtst.createGraphics(); + grefclear.setColor(Color.white); + gtstclear.setColor(Color.white); + } + + public static void initGCs() { + grefrender = imgref.createGraphics(); + gtstrender = imgtst.createGraphics(); + gtstrender.clipRect(10, 10, 20, 20); + grefrender.setColor(Color.blue); + gtstrender.setColor(Color.blue); + if (lw != 1.0f) { + BasicStroke bs = new BasicStroke(lw); + grefrender.setStroke(bs); + gtstrender.setStroke(bs); + } + if (rot != 0.0) { + double rotrad = Math.toRadians(rot); + grefrender.rotate(rotrad, 20, 20); + gtstrender.rotate(rotrad, 20, 20); + } + if (strokePure) { + grefrender.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, + RenderingHints.VALUE_STROKE_PURE); + gtstrender.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, + RenderingHints.VALUE_STROKE_PURE); + } + if (useAA) { + grefrender.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + gtstrender.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + maxerr = 1; + } + } + + public static void disposeGCs() { + grefrender.dispose(); + gtstrender.dispose(); + grefrender = gtstrender = null; + } + + public static void parseAndRun(InputStream in) throws IOException { + BufferedReader br = new BufferedReader(new InputStreamReader(in)); + String str; + while ((str = br.readLine()) != null) { + if (str.startsWith("Stroked ") || str.startsWith("Filled ")) { + parseTest(str); + continue; + } + if (str.startsWith("Running ")) { + continue; + } + if (str.startsWith("Failed: ")) { + continue; + } + if (str.indexOf(" out of ") > 0 && + str.indexOf(" tests failed...") > 0) + { + continue; + } + if (str.indexOf(" tests had critical errors") > 0) { + continue; + } + System.err.println("Unparseable line: "+str); + } + } + + public static void parseTest(String origstr) { + String str = origstr; + boolean isfill = false; + useAA = strokePure = false; + lw = 1.0f; + rot = 0.0; + if (str.startsWith("Stroked ")) { + str = str.substring(8); + isfill = false; + } else if (str.startsWith("Filled ")) { + str = str.substring(7); + isfill = true; + } else { + System.err.println("Unparseable test line: "+origstr); + } + if (str.startsWith("AA ")) { + str = str.substring(3); + useAA = true; + } + if (str.startsWith("Pure ")) { + str = str.substring(5); + strokePure = true; + } + if (str.startsWith("Lw=")) { + int index = str.indexOf(' ', 3); + if (index > 0) { + lw = Float.parseFloat(str.substring(3, index)); + str = str.substring(index+1); + } + } + if (str.startsWith("Rot=")) { + int index = str.indexOf(' ', 4); + if (index > 0) { + rot = Double.parseDouble(str.substring(4, index)); + str = str.substring(index+1); + } + } + AnnotatedRenderOp ar = AnnotatedRenderOp.parse(str); + if (ar != null) { + initGCs(); + test(ar, isfill); + disposeGCs(); + } else { + System.err.println("Unparseable test line: "+origstr); + } + } + + public static void test(AnnotatedRenderOp ar, boolean isfill) { + grefclear.fillRect(0, 0, 40, 40); + gtstclear.fillRect(0, 0, 40, 40); + if (isfill) { + ar.fill(grefrender); + ar.fill(gtstrender); + } else { + ar.draw(grefrender); + ar.draw(gtstrender); + } + check(imgref, imgtst, ar, isfill); + } + + public static int[] getData(BufferedImage img) { + Raster r = img.getRaster(); + DataBufferInt dbi = (DataBufferInt) r.getDataBuffer(); + return dbi.getData(); + } + + public static int getScan(BufferedImage img) { + Raster r = img.getRaster(); + SinglePixelPackedSampleModel sppsm = + (SinglePixelPackedSampleModel) r.getSampleModel(); + return sppsm.getScanlineStride(); + } + + public static int getOffset(BufferedImage img) { + Raster r = img.getRaster(); + SinglePixelPackedSampleModel sppsm = + (SinglePixelPackedSampleModel) r.getSampleModel(); + return sppsm.getOffset(-r.getSampleModelTranslateX(), + -r.getSampleModelTranslateY()); + } + + final static int opaque = 0xff000000; + final static int whitergb = Color.white.getRGB(); + + public static final int maxdiff(int rgb1, int rgb2) { + int maxd = 0; + for (int i = 0; i < 32; i += 8) { + int c1 = (rgb1 >> i) & 0xff; + int c2 = (rgb2 >> i) & 0xff; + int d = Math.abs(c1-c2); + if (maxd < d) { + maxd = d; + } + } + return maxd; + } + + public static void check(BufferedImage imgref, BufferedImage imgtst, + AnnotatedRenderOp ar, boolean wasfill) + { + numtests++; + int dataref[] = getData(imgref); + int datatst[] = getData(imgtst); + int scanref = getScan(imgref); + int scantst = getScan(imgtst); + int offref = getOffset(imgref); + int offtst = getOffset(imgtst); + + // We want to check for errors outside the clip at a higher + // priority than errors involving different pixels touched + // inside the clip. + + // Check above clip + if (check(ar, wasfill, + null, 0, 0, + datatst, scantst, offtst, + 0, 0, 40, 10)) + { + return; + } + // Check below clip + if (check(ar, wasfill, + null, 0, 0, + datatst, scantst, offtst, + 0, 30, 40, 40)) + { + return; + } + // Check left of clip + if (check(ar, wasfill, + null, 0, 0, + datatst, scantst, offtst, + 0, 10, 10, 30)) + { + return; + } + // Check right of clip + if (check(ar, wasfill, + null, 0, 0, + datatst, scantst, offtst, + 30, 10, 40, 30)) + { + return; + } + // Check inside clip + check(ar, wasfill, + dataref, scanref, offref, + datatst, scantst, offtst, + 10, 10, 30, 30); + } + + public static boolean check(AnnotatedRenderOp ar, boolean wasfill, + int dataref[], int scanref, int offref, + int datatst[], int scantst, int offtst, + int x0, int y0, int x1, int y1) + { + offref += scanref * y0; + offtst += scantst * y0; + for (int y = y0; y < y1; y++) { + for (int x = x0; x < x1; x++) { + boolean failed; + String reason; + int rgbref; + int rgbtst; + + rgbtst = datatst[offtst+x] | opaque; + if (dataref == null) { + /* Outside of clip, must be white, no error tolerance */ + rgbref = whitergb; + failed = (rgbtst != rgbref); + reason = "stray pixel rendered outside of clip"; + } else { + /* Inside of clip, check for maxerr delta in components */ + rgbref = dataref[offref+x] | opaque; + failed = (rgbref != rgbtst && + maxdiff(rgbref, rgbtst) > maxerr); + reason = "different pixel rendered inside clip"; + } + if (failed) { + if (dataref == null) { + numerrors++; + } + if (wasfill) { + numfillfailures++; + } else { + numstrokefailures++; + } + if (!silent) { + System.out.println("Failed: "+reason+" at "+x+", "+y+ + " ["+Integer.toHexString(rgbref)+ + " != "+Integer.toHexString(rgbtst)+ + "]"); + System.out.print(wasfill ? "Filled " : "Stroked "); + if (useAA) System.out.print("AA "); + if (strokePure) System.out.print("Pure "); + if (lw != 1) System.out.print("Lw="+lw+" "); + if (rot != 0) System.out.print("Rot="+rot+" "); + System.out.println(ar); + } + if (showErrors) { + show(imgref, imgtst); + } + return true; + } + } + offref += scanref; + offtst += scantst; + } + return false; + } + + static ErrorWindow errw; + + public static void show(BufferedImage imgref, BufferedImage imgtst) { + ErrorWindow errw = new ErrorWindow(); + errw.setImages(imgref, imgtst); + errw.setVisible(true); + errw.waitForHide(); + errw.dispose(); + } + + public static class Cubic extends AnnotatedShapeOp { + public static Cubic tryparse(String str) { + str = str.trim(); + if (!str.startsWith("Cubic(")) { + return null; + } + str = str.substring(6); + double coords[] = new double[8]; + boolean foundparen = false; + for (int i = 0; i < coords.length; i++) { + int index = str.indexOf(","); + if (index < 0) { + if (i < coords.length-1) { + return null; + } + index = str.indexOf(")"); + if (index < 0) { + return null; + } + foundparen = true; + } + String num = str.substring(0, index); + try { + coords[i] = Double.parseDouble(num); + } catch (NumberFormatException nfe) { + return null; + } + str = str.substring(index+1); + } + if (!foundparen || str.length() > 0) { + return null; + } + Cubic c = new Cubic(); + c.cubic.setCurve(coords[0], coords[1], + coords[2], coords[3], + coords[4], coords[5], + coords[6], coords[7]); + return c; + } + + private CubicCurve2D cubic = new CubicCurve2D.Double(); + + public void randomize() { + cubic.setCurve(randDblCoord(), randDblCoord(), + randDblCoord(), randDblCoord(), + randDblCoord(), randDblCoord(), + randDblCoord(), randDblCoord()); + } + + public Shape getShape() { + return cubic; + } + + public String toString() { + return ("Cubic("+ + cubic.getX1()+", "+ + cubic.getY1()+", "+ + cubic.getCtrlX1()+", "+ + cubic.getCtrlY1()+", "+ + cubic.getCtrlX2()+", "+ + cubic.getCtrlY2()+", "+ + cubic.getX2()+", "+ + cubic.getY2() + +")"); + } + } + + public static class Quad extends AnnotatedShapeOp { + public static Quad tryparse(String str) { + str = str.trim(); + if (!str.startsWith("Quad(")) { + return null; + } + str = str.substring(5); + double coords[] = new double[6]; + boolean foundparen = false; + for (int i = 0; i < coords.length; i++) { + int index = str.indexOf(","); + if (index < 0) { + if (i < coords.length-1) { + return null; + } + index = str.indexOf(")"); + if (index < 0) { + return null; + } + foundparen = true; + } + String num = str.substring(0, index); + try { + coords[i] = Double.parseDouble(num); + } catch (NumberFormatException nfe) { + return null; + } + str = str.substring(index+1); + } + if (!foundparen || str.length() > 0) { + return null; + } + Quad c = new Quad(); + c.quad.setCurve(coords[0], coords[1], + coords[2], coords[3], + coords[4], coords[5]); + return c; + } + + private QuadCurve2D quad = new QuadCurve2D.Double(); + + public void randomize() { + quad.setCurve(randDblCoord(), randDblCoord(), + randDblCoord(), randDblCoord(), + randDblCoord(), randDblCoord()); + } + + public Shape getShape() { + return quad; + } + + public String toString() { + return ("Quad("+ + quad.getX1()+", "+ + quad.getY1()+", "+ + quad.getCtrlX()+", "+ + quad.getCtrlY()+", "+ + quad.getX2()+", "+ + quad.getY2() + +")"); + } + } + + public static class Poly extends AnnotatedShapeOp { + public static Poly tryparse(String str) { + str = str.trim(); + if (!str.startsWith("Poly(")) { + return null; + } + str = str.substring(5); + Polygon p = new Polygon(); + while (true) { + int x, y; + str = str.trim(); + if (str.startsWith(")")) { + str = str.substring(1); + break; + } + if (p.npoints > 0) { + if (str.startsWith(",")) { + str = str.substring(2).trim(); + } else { + return null; + } + } + if (str.startsWith("[")) { + str = str.substring(1); + } else { + return null; + } + int index = str.indexOf(","); + if (index < 0) { + return null; + } + String num = str.substring(0, index); + try { + x = Integer.parseInt(num); + } catch (NumberFormatException nfe) { + return null; + } + str = str.substring(index+1); + index = str.indexOf("]"); + if (index < 0) { + return null; + } + num = str.substring(0, index).trim(); + try { + y = Integer.parseInt(num); + } catch (NumberFormatException nfe) { + return null; + } + str = str.substring(index+1); + p.addPoint(x, y); + } + if (str.length() > 0) { + return null; + } + if (p.npoints < 3) { + return null; + } + return new Poly(p); + } + + private Polygon poly; + + public Poly() { + this.poly = new Polygon(); + } + + private Poly(Polygon p) { + this.poly = p; + } + + public void randomize() { + poly.reset(); + poly.addPoint(randIntCoord(), randIntCoord()); + poly.addPoint(randIntCoord(), randIntCoord()); + poly.addPoint(randIntCoord(), randIntCoord()); + poly.addPoint(randIntCoord(), randIntCoord()); + poly.addPoint(randIntCoord(), randIntCoord()); + } + + public Shape getShape() { + return poly; + } + + public String toString() { + StringBuffer sb = new StringBuffer(100); + sb.append("Poly("); + for (int i = 0; i < poly.npoints; i++) { + if (i != 0) { + sb.append(", "); + } + sb.append("["); + sb.append(poly.xpoints[i]); + sb.append(", "); + sb.append(poly.ypoints[i]); + sb.append("]"); + } + sb.append(")"); + return sb.toString(); + } + } + + public static class Path extends AnnotatedShapeOp { + public static Path tryparse(String str) { + str = str.trim(); + if (!str.startsWith("Path(")) { + return null; + } + str = str.substring(5); + GeneralPath gp = new GeneralPath(); + float coords[] = new float[6]; + int numsegs = 0; + while (true) { + int type; + int n; + str = str.trim(); + if (str.startsWith(")")) { + str = str.substring(1); + break; + } + if (str.startsWith("M[")) { + type = PathIterator.SEG_MOVETO; + n = 2; + } else if (str.startsWith("L[")) { + type = PathIterator.SEG_LINETO; + n = 2; + } else if (str.startsWith("Q[")) { + type = PathIterator.SEG_QUADTO; + n = 4; + } else if (str.startsWith("C[")) { + type = PathIterator.SEG_CUBICTO; + n = 6; + } else if (str.startsWith("E[")) { + type = PathIterator.SEG_CLOSE; + n = 0; + } else { + return null; + } + str = str.substring(2); + if (n == 0) { + if (str.startsWith("]")) { + str = str.substring(1); + } else { + return null; + } + } + for (int i = 0; i < n; i++) { + int index; + if (i < n-1) { + index = str.indexOf(","); + } else { + index = str.indexOf("]"); + } + if (index < 0) { + return null; + } + String num = str.substring(0, index); + try { + coords[i] = Float.parseFloat(num); + } catch (NumberFormatException nfe) { + return null; + } + str = str.substring(index+1).trim(); + } + switch (type) { + case PathIterator.SEG_MOVETO: + gp.moveTo(coords[0], coords[1]); + break; + case PathIterator.SEG_LINETO: + gp.lineTo(coords[0], coords[1]); + break; + case PathIterator.SEG_QUADTO: + gp.quadTo(coords[0], coords[1], + coords[2], coords[3]); + break; + case PathIterator.SEG_CUBICTO: + gp.curveTo(coords[0], coords[1], + coords[2], coords[3], + coords[4], coords[5]); + break; + case PathIterator.SEG_CLOSE: + gp.closePath(); + break; + } + numsegs++; + } + if (str.length() > 0) { + return null; + } + if (numsegs < 2) { + return null; + } + return new Path(gp); + } + + private GeneralPath path; + + public Path() { + this.path = new GeneralPath(); + } + + private Path(GeneralPath gp) { + this.path = gp; + } + + public void randomize() { + path.reset(); + path.moveTo(randFltCoord(), randFltCoord()); + for (int i = randInt(5)+3; i > 0; --i) { + switch(randInt(5)) { + case 0: + path.moveTo(randFltCoord(), randFltCoord()); + break; + case 1: + path.lineTo(randFltCoord(), randFltCoord()); + break; + case 2: + path.quadTo(randFltCoord(), randFltCoord(), + randFltCoord(), randFltCoord()); + break; + case 3: + path.curveTo(randFltCoord(), randFltCoord(), + randFltCoord(), randFltCoord(), + randFltCoord(), randFltCoord()); + break; + case 4: + path.closePath(); + break; + } + } + } + + public Shape getShape() { + return path; + } + + public String toString() { + StringBuffer sb = new StringBuffer(100); + sb.append("Path("); + PathIterator pi = path.getPathIterator(null); + float coords[] = new float[6]; + boolean first = true; + while (!pi.isDone()) { + int n; + char c; + switch(pi.currentSegment(coords)) { + case PathIterator.SEG_MOVETO: + c = 'M'; + n = 2; + break; + case PathIterator.SEG_LINETO: + c = 'L'; + n = 2; + break; + case PathIterator.SEG_QUADTO: + c = 'Q'; + n = 4; + break; + case PathIterator.SEG_CUBICTO: + c = 'C'; + n = 6; + break; + case PathIterator.SEG_CLOSE: + c = 'E'; + n = 0; + break; + default: + throw new InternalError("Unknown segment!"); + } + sb.append(c); + sb.append("["); + for (int i = 0; i < n; i++) { + if (i != 0) { + sb.append(","); + } + sb.append(coords[i]); + } + sb.append("]"); + pi.next(); + } + sb.append(")"); + return sb.toString(); + } + } + + public static class Rect extends AnnotatedShapeOp { + public static Rect tryparse(String str) { + str = str.trim(); + if (!str.startsWith("Rect(")) { + return null; + } + str = str.substring(5); + double coords[] = new double[4]; + boolean foundparen = false; + for (int i = 0; i < coords.length; i++) { + int index = str.indexOf(","); + if (index < 0) { + if (i < coords.length-1) { + return null; + } + index = str.indexOf(")"); + if (index < 0) { + return null; + } + foundparen = true; + } + String num = str.substring(0, index); + try { + coords[i] = Double.parseDouble(num); + } catch (NumberFormatException nfe) { + return null; + } + str = str.substring(index+1); + } + if (!foundparen || str.length() > 0) { + return null; + } + Rect r = new Rect(); + r.rect.setRect(coords[0], coords[1], + coords[2], coords[3]); + return r; + } + + private Rectangle2D rect = new Rectangle2D.Double(); + + public void randomize() { + rect.setRect(randDblCoord(), randDblCoord(), + randDblCoord(), randDblCoord()); + } + + public Shape getShape() { + return rect; + } + + public String toString() { + return ("Rect("+ + rect.getX()+", "+ + rect.getY()+", "+ + rect.getWidth()+", "+ + rect.getHeight() + +")"); + } + } + + public static class Line extends AnnotatedShapeOp { + public static Line tryparse(String str) { + str = str.trim(); + if (!str.startsWith("Line(")) { + return null; + } + str = str.substring(5); + double coords[] = new double[4]; + boolean foundparen = false; + for (int i = 0; i < coords.length; i++) { + int index = str.indexOf(","); + if (index < 0) { + if (i < coords.length-1) { + return null; + } + index = str.indexOf(")"); + if (index < 0) { + return null; + } + foundparen = true; + } + String num = str.substring(0, index); + try { + coords[i] = Double.parseDouble(num); + } catch (NumberFormatException nfe) { + return null; + } + str = str.substring(index+1); + } + if (!foundparen || str.length() > 0) { + return null; + } + Line l = new Line(); + l.line.setLine(coords[0], coords[1], + coords[2], coords[3]); + return l; + } + + private Line2D line = new Line2D.Double(); + + public void randomize() { + line.setLine(randDblCoord(), randDblCoord(), + randDblCoord(), randDblCoord()); + } + + public Shape getShape() { + return line; + } + + public String toString() { + return ("Line("+ + line.getX1()+", "+ + line.getY1()+", "+ + line.getX2()+", "+ + line.getY2() + +")"); + } + } + + public static class RectMethod extends AnnotatedRenderOp { + public static RectMethod tryparse(String str) { + str = str.trim(); + if (!str.startsWith("RectMethod(")) { + return null; + } + str = str.substring(11); + int coords[] = new int[4]; + boolean foundparen = false; + for (int i = 0; i < coords.length; i++) { + int index = str.indexOf(","); + if (index < 0) { + if (i < coords.length-1) { + return null; + } + index = str.indexOf(")"); + if (index < 0) { + return null; + } + foundparen = true; + } + String num = str.substring(0, index).trim(); + try { + coords[i] = Integer.parseInt(num); + } catch (NumberFormatException nfe) { + return null; + } + str = str.substring(index+1); + } + if (!foundparen || str.length() > 0) { + return null; + } + RectMethod rm = new RectMethod(); + rm.rect.setBounds(coords[0], coords[1], + coords[2], coords[3]); + return rm; + } + + private Rectangle rect = new Rectangle(); + + public void randomize() { + rect.setBounds(randIntCoord(), randIntCoord(), + randIntCoord(), randIntCoord()); + } + + public void fill(Graphics2D g2d) { + g2d.fillRect(rect.x, rect.y, rect.width, rect.height); + } + + public void draw(Graphics2D g2d) { + g2d.drawRect(rect.x, rect.y, rect.width, rect.height); + } + + public String toString() { + return ("RectMethod("+ + rect.x+", "+ + rect.y+", "+ + rect.width+", "+ + rect.height + +")"); + } + } + + public static class LineMethod extends AnnotatedRenderOp { + public static LineMethod tryparse(String str) { + str = str.trim(); + if (!str.startsWith("LineMethod(")) { + return null; + } + str = str.substring(11); + int coords[] = new int[4]; + boolean foundparen = false; + for (int i = 0; i < coords.length; i++) { + int index = str.indexOf(","); + if (index < 0) { + if (i < coords.length-1) { + return null; + } + index = str.indexOf(")"); + if (index < 0) { + return null; + } + foundparen = true; + } + String num = str.substring(0, index).trim(); + try { + coords[i] = Integer.parseInt(num); + } catch (NumberFormatException nfe) { + return null; + } + str = str.substring(index+1); + } + if (!foundparen || str.length() > 0) { + return null; + } + LineMethod lm = new LineMethod(); + lm.line = coords; + return lm; + } + + private int line[] = new int[4]; + + public void randomize() { + line[0] = randIntCoord(); + line[1] = randIntCoord(); + line[2] = randIntCoord(); + line[3] = randIntCoord(); + } + + public void fill(Graphics2D g2d) { + } + + public void draw(Graphics2D g2d) { + g2d.drawLine(line[0], line[1], line[2], line[3]); + } + + public String toString() { + return ("LineMethod("+ + line[0]+", "+ + line[1]+", "+ + line[2]+", "+ + line[3] + +")"); + } + } + + public static class ErrorWindow extends Frame { + ImageCanvas unclipped; + ImageCanvas reference; + ImageCanvas actual; + ImageCanvas diff; + + public ErrorWindow() { + super("Error Comparison Window"); + + unclipped = new ImageCanvas(); + reference = new ImageCanvas(); + actual = new ImageCanvas(); + diff = new ImageCanvas(); + + setLayout(new SmartGridLayout(0, 2, 5, 5)); + addImagePanel(unclipped, "Unclipped rendering"); + addImagePanel(reference, "Clipped reference"); + addImagePanel(actual, "Actual clipped"); + addImagePanel(diff, "Difference"); + + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + setVisible(false); + } + }); + } + + public void addImagePanel(ImageCanvas ic, String label) { + add(ic); + add(new Label(label)); + } + + public void setImages(BufferedImage imgref, BufferedImage imgtst) { + unclipped.setImage(imgref); + reference.setReference(imgref); + actual.setImage(imgtst); + diff.setDiff(reference.getImage(), imgtst); + invalidate(); + pack(); + repaint(); + } + + public void setVisible(boolean vis) { + super.setVisible(vis); + synchronized (this) { + notifyAll(); + } + } + + public synchronized void waitForHide() { + while (isShowing()) { + try { + wait(); + } catch (InterruptedException e) { + System.exit(2); + } + } + } + } + + public static class SmartGridLayout implements LayoutManager { + int rows; + int cols; + int hgap; + int vgap; + + public SmartGridLayout(int r, int c, int h, int v) { + this.rows = r; + this.cols = c; + this.hgap = h; + this.vgap = v; + } + + public void addLayoutComponent(String name, Component comp) { + } + + public void removeLayoutComponent(Component comp) { + } + + public int[][] getGridSizes(Container parent, boolean min) { + int ncomponents = parent.getComponentCount(); + int nrows = rows; + int ncols = cols; + + if (nrows > 0) { + ncols = (ncomponents + nrows - 1) / nrows; + } else { + nrows = (ncomponents + ncols - 1) / ncols; + } + int widths[] = new int[ncols+1]; + int heights[] = new int[nrows+1]; + int x = 0; + int y = 0; + for (int i = 0 ; i < ncomponents ; i++) { + Component comp = parent.getComponent(i); + Dimension d = (min + ? comp.getMinimumSize() + : comp.getPreferredSize()); + if (widths[x] < d.width) { + widths[x] = d.width; + } + if (heights[y] < d.height) { + heights[y] = d.height; + } + x++; + if (x >= ncols) { + x = 0; + y++; + } + } + for (int i = 0; i < ncols; i++) { + widths[ncols] += widths[i]; + } + for (int i = 0; i < nrows; i++) { + heights[nrows] += heights[i]; + } + return new int[][] { widths, heights }; + } + + public Dimension getSize(Container parent, boolean min) { + int sizes[][] = getGridSizes(parent, min); + int widths[] = sizes[0]; + int heights[] = sizes[1]; + int nrows = heights.length-1; + int ncols = widths.length-1; + int w = widths[ncols]; + int h = heights[nrows]; + Insets insets = parent.getInsets(); + return new Dimension(insets.left+insets.right + w+(ncols+1)*hgap, + insets.top+insets.bottom + h+(nrows+1)*vgap); + } + + public Dimension preferredLayoutSize(Container parent) { + return getSize(parent, false); + } + + public Dimension minimumLayoutSize(Container parent) { + return getSize(parent, true); + } + + public void layoutContainer(Container parent) { + int pref[][] = getGridSizes(parent, false); + int min[][] = getGridSizes(parent, true); + int minwidths[] = min[0]; + int minheights[] = min[1]; + int prefwidths[] = pref[0]; + int prefheights[] = pref[1]; + int nrows = minheights.length - 1; + int ncols = minwidths.length - 1; + Insets insets = parent.getInsets(); + int w = parent.getWidth() - insets.left - insets.right; + int h = parent.getHeight() - insets.top - insets.bottom; + w = w - (ncols+1)*hgap; + h = h - (nrows+1)*vgap; + int widths[] = calculateSizes(w, ncols, minwidths, prefwidths); + int heights[] = calculateSizes(h, nrows, minheights, prefheights); + int ncomponents = parent.getComponentCount(); + int x = insets.left + hgap; + int y = insets.top + vgap; + int r = 0; + int c = 0; + for (int i = 0; i < ncomponents; i++) { + parent.getComponent(i).setBounds(x, y, widths[c], heights[r]); + x += widths[c++] + hgap; + if (c >= ncols) { + c = 0; + x = insets.left + hgap; + y += heights[r++] + vgap; + if (r >= nrows) { + // just in case + break; + } + } + } + } + + public static int[] calculateSizes(int total, int num, + int minsizes[], int prefsizes[]) + { + if (total <= minsizes[num]) { + return minsizes; + } + if (total >= prefsizes[num]) { + return prefsizes; + } + int sizes[] = new int[total]; + int prevhappy = 0; + int nhappy = 0; + int happysize = 0; + do { + int addsize = (total - happysize) / (num - nhappy); + happysize = 0; + for (int i = 0; i < num; i++) { + if (sizes[i] >= prefsizes[i] || + minsizes[i] + addsize > prefsizes[i]) + { + happysize += (sizes[i] = prefsizes[i]); + nhappy++; + } else { + sizes[i] = minsizes[i] + addsize; + } + } + } while (nhappy < num && nhappy > prevhappy); + return sizes; + } + } + + public static class ImageCanvas extends Canvas { + BufferedImage image; + + public void setImage(BufferedImage img) { + this.image = img; + } + + public BufferedImage getImage() { + return image; + } + + public void checkImage(int w, int h) { + if (image == null || + image.getWidth() < w || + image.getHeight() < h) + { + image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); + } + } + + public void setReference(BufferedImage img) { + checkImage(img.getWidth(), img.getHeight()); + Graphics g = image.createGraphics(); + g.drawImage(img, 0, 0, null); + g.setColor(Color.white); + g.fillRect(0, 0, 30, 10); + g.fillRect(30, 0, 10, 30); + g.fillRect(10, 30, 30, 10); + g.fillRect(0, 10, 10, 30); + g.dispose(); + } + + public void setDiff(BufferedImage imgref, BufferedImage imgtst) { + int w = Math.max(imgref.getWidth(), imgtst.getWidth()); + int h = Math.max(imgref.getHeight(), imgtst.getHeight()); + checkImage(w, h); + Graphics g = image.createGraphics(); + g.drawImage(imgref, 0, 0, null); + g.setXORMode(Color.white); + g.drawImage(imgtst, 0, 0, null); + g.setPaintMode(); + g.setColor(new Color(1f, 1f, 0f, 0.25f)); + g.fillRect(10, 10, 20, 20); + g.setColor(new Color(1f, 0f, 0f, 0.25f)); + g.fillRect(0, 0, 30, 10); + g.fillRect(30, 0, 10, 30); + g.fillRect(10, 30, 30, 10); + g.fillRect(0, 10, 10, 30); + g.dispose(); + } + + public Dimension getPreferredSize() { + if (image == null) { + return new Dimension(); + } else { + return new Dimension(image.getWidth(), image.getHeight()); + } + } + + public void paint(Graphics g) { + g.drawImage(image, 0, 0, null); + } + } +} diff --git a/test/java/awt/Insets/WindowWithWarningTest/WindowWithWarningTest.html b/test/java/awt/Insets/WindowWithWarningTest/WindowWithWarningTest.html deleted file mode 100644 index ad6fa609d4ff62e51ba3c0fc375d09186096d98f..0000000000000000000000000000000000000000 --- a/test/java/awt/Insets/WindowWithWarningTest/WindowWithWarningTest.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - WindowWithWarningTest - -
-  This test will run automatically.
-  
- - - - - diff --git a/test/java/awt/Insets/WindowWithWarningTest/WindowWithWarningTest.java b/test/java/awt/Insets/WindowWithWarningTest/WindowWithWarningTest.java deleted file mode 100644 index ab9ea6950a67b636a34c7c0c66a4b745f837756b..0000000000000000000000000000000000000000 --- a/test/java/awt/Insets/WindowWithWarningTest/WindowWithWarningTest.java +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (c) 2006, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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. - */ - - -/* - test - @bug 6391770 - @summary Content of the Window should be laid out in the area left after WarningWindow was added. - @author yuri nesterenko: area= - @run applet WindowWithWarningTest.html -*/ - -// Note there is no @ in front of test above. This is so that the -// harness will not mistake this file as a test file. It should -// only see the html file as a test file. (the harness runs all -// valid test files, so it would run this test twice if this file -// were valid as well as the html file.) -// Also, note the area= after Your Name in the author tag. Here, you -// should put which functional area the test falls in. See the -// AWT-core home page -> test areas and/or -> AWT team for a list of -// areas. -// Note also the 'AutomaticAppletTest.html' in the run tag. This should -// be changed to the name of the test. - - -/** - * WindowWithWarningTest.java - * - * summary: - */ - -import java.applet.Applet; -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; - -//Automated tests should run as applet tests if possible because they -// get their environments cleaned up, including AWT threads, any -// test created threads, and any system resources used by the test -// such as file descriptors. (This is normally not a problem as -// main tests usually run in a separate VM, however on some platforms -// such as the Mac, separate VMs are not possible and non-applet -// tests will cause problems). Also, you don't have to worry about -// synchronisation stuff in Applet tests they way you do in main -// tests... - - -public class WindowWithWarningTest extends Applet -{ - //Declare things used in the test, like buttons and labels here - boolean buttonClicked = false; - public static final int MAX_COUNT = 100; - - public void init() - { - //Create instructions for the user here, as well as set up - // the environment -- set the layout manager, add buttons, - // etc. - - this.setLayout (new BorderLayout ()); - - String[] instructions = - { - "This is an AUTOMATIC test", - "simply wait until it is done" - }; - //Sysout.createDialog( ); - //Sysout.printInstructions( instructions ); - - }//End init() - public void start () - { - //Get things going. Request focus, set size, et cetera - System.setSecurityManager( new SecurityManager() { - // deny AWTPermission("showWindowWithoutWarningBanner") - public boolean checkTopLevelWindow(Object window) { - return false; - } - }); - JFrame frame = new JFrame("Window Test"); - frame.setBounds(50, 50, 200, 200); - frame.show(); - - JWindow window = new JWindow( frame ); - JButton jbutton1 = new JButton( "First" ); - jbutton1.addMouseListener( new MouseAdapter() { - public void mousePressed( MouseEvent me ) { - buttonClicked = true; - } - }); - JButton jbutton2 = new JButton( "Second" ); - window.setLocation( 300, 300 ); - - window.add("North", jbutton1); - window.add("South", jbutton2); - - window.pack(); - window.show(); - //wait for frame to show: - getLocation( frame ); - window.toFront(); - - Dimension size0 = window.getSize(); - Dimension size1 = null; - try { - Robot robot = new Robot(); - - robot.delay(500); - window.pack(); - robot.delay(500); - window.pack(); - // size1 must be the same as size0 - size1 = window.getSize(); - robot.delay(500); - Point pt = jbutton1.getLocationOnScreen(); - robot.mouseMove((int) jbutton1.getLocationOnScreen().x + jbutton1.getWidth() / 2, - (int) jbutton1.getLocationOnScreen().y + jbutton1.getHeight() / 2); - robot.delay(500); - robot.mousePress(MouseEvent.BUTTON1_MASK); - robot.delay(100); - robot.mouseRelease(MouseEvent.BUTTON1_MASK); - robot.delay(2000); - }catch(Exception e) { - throw new RuntimeException( "Exception "+e ); - } - if( !size0.equals(size1) ) { - throw new RuntimeException( "Wrong Window size after multiple pack()s"); - } - if( !buttonClicked ) { - throw new RuntimeException( "Button was not clicked"); - } - window.dispose(); - frame.dispose(); - - System.out.println("Test Passed."); - }// start() - public static Point getLocation( Component co ) throws RuntimeException { - Point pt = null; - boolean bFound = false; - int count = 0; - while( !bFound ) { - try { - pt = co.getLocationOnScreen(); - bFound = true; - }catch( Exception ex ) { - bFound = false; - count++; - } - if( !bFound && count > MAX_COUNT ) { - throw new RuntimeException("don't see a component to get location"); - } - } - return pt; - } - - -}// class AutomaticAppletTest - - -/**************************************************** - Standard Test Machinery - DO NOT modify anything below -- it's a standard - chunk of code whose purpose is to make user - interaction uniform, and thereby make it simpler - to read and understand someone else's test. - ****************************************************/ - -/** - This is part of the standard test machinery. - It creates a dialog (with the instructions), and is the interface - for sending text messages to the user. - To print the instructions, send an array of strings to Sysout.createDialog - WithInstructions method. Put one line of instructions per array entry. - To display a message for the tester to see, simply call Sysout.println - with the string to be displayed. - This mimics System.out.println but works within the test harness as well - as standalone. - */ - -class Sysout -{ - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog -{ - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - show(); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - System.out.println(messageIn); - } - -}// TestDialog class diff --git a/test/java/awt/PrintJob/Text/StringWidth.java b/test/java/awt/PrintJob/Text/StringWidth.java index b8760aa942cf7e2b4ea565848b7a58fee9c6f737..4c2250a21dd1ca71afad40d4ac28e99427787a41 100644 --- a/test/java/awt/PrintJob/Text/StringWidth.java +++ b/test/java/awt/PrintJob/Text/StringWidth.java @@ -60,7 +60,6 @@ public class StringWidth extends Frame { pg.dispose(); pj.end(); setVisible(false); - System.exit(0); } public static void main(String[] args) { diff --git a/test/java/awt/image/IncorrectSampleMaskTest.java b/test/java/awt/image/IncorrectSampleMaskTest.java new file mode 100644 index 0000000000000000000000000000000000000000..bfd88cc660772d8273e7b81e8b2fceeb55a5d373 --- /dev/null +++ b/test/java/awt/image/IncorrectSampleMaskTest.java @@ -0,0 +1,113 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6782574 + * @summary Test verifies that incorrect sample masks are correctly handled + * by the constructor of the SinglePixelPackedSampleModel class + * and do not cause internal error in the medialib glue code. + * + * @run main IncorrectSampleMaskTest + */ + +import java.awt.geom.AffineTransform; +import java.awt.image.AffineTransformOp; +import java.awt.image.BufferedImageOp; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferInt; +import java.awt.image.DataBufferUShort; +import java.awt.image.Raster; +import java.awt.image.RasterOp; +import java.awt.image.WritableRaster; +import java.awt.image.SinglePixelPackedSampleModel; + +public class IncorrectSampleMaskTest { + public static void main(String[] args) { + int[] dataTypes = new int[] { + DataBuffer.TYPE_BYTE, + DataBuffer.TYPE_USHORT, + DataBuffer.TYPE_INT }; + + for (int type : dataTypes) { + doTest(type); + } + } + + private static final int w = 100; + private static final int h = 100; + + private static AffineTransform at = + AffineTransform.getScaleInstance(0.5, 0.5); + + private static RasterOp op = + new AffineTransformOp(at, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + + private static void doTest(int dataType) { + int maxSize = DataBuffer.getDataTypeSize(dataType); + System.out.println("Type size: " + maxSize); + + int theMask = (int)(1L << (maxSize + 2)) - 1; + System.out.printf("theMask=%x\n", theMask); + + SinglePixelPackedSampleModel sm = + new SinglePixelPackedSampleModel(dataType, w, h, + new int[] { theMask }); + + + int[] sampleSize = sm.getSampleSize(); + for (int s : sampleSize) { + if (s > maxSize) { + throw new RuntimeException("Test failed: sample size is too big:" + s); + } + } + + System.out.println("Test medialib..."); + DataBuffer buf = createDataBuffer(dataType); + + WritableRaster wr = Raster.createWritableRaster(sm, buf, null); + + op.filter(wr, null); + System.out.println("Test PASSED."); + } + + private static DataBuffer createDataBuffer(int type) { + switch (type) { + case DataBuffer.TYPE_BYTE: { + byte[] buf = new byte[w * h]; + return new DataBufferByte(buf, buf.length); + } + case DataBuffer.TYPE_USHORT: { + short[] buf = new short[w * h]; + return new DataBufferUShort(buf, buf.length); + } + case DataBuffer.TYPE_INT: { + int[] buf = new int[w * h]; + return new DataBufferInt(buf, buf.length); + } + default : + throw new RuntimeException("Unsupported data type."); + } + } +} diff --git a/test/java/text/Format/DateFormat/ISO8601ZoneTest.java b/test/java/text/Format/DateFormat/ISO8601ZoneTest.java index 2179948a849c2c0373d89163a9a1c060546a75d9..2a5c24125855398be4c64ae3c052ebbcc33bac19 100644 --- a/test/java/text/Format/DateFormat/ISO8601ZoneTest.java +++ b/test/java/text/Format/DateFormat/ISO8601ZoneTest.java @@ -60,48 +60,51 @@ public class ISO8601ZoneTest { "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", }; + // badData[][0] - format + // badData[][1] - (bad) text to be parsed + // badData[][2] - subtext at the end of which a parse error is detected static final String[][] badData = { - { "X", "1" }, - { "X", "+1" }, - { "X", "-2" }, - { "X", "-24" }, - { "X", "+24" }, - - { "XX", "9" }, - { "XX", "23" }, - { "XX", "234" }, - { "XX", "3456" }, - { "XX", "23456" }, - { "XX", "+1" }, - { "XX", "-12" }, - { "XX", "+123" }, - { "XX", "-12:34" }, - { "XX", "+12:34" }, - { "XX", "-2423" }, - { "XX", "+2423" }, - { "XX", "-1260" }, - { "XX", "+1260" }, - - { "XXX", "9" }, - { "XXX", "23" }, - { "XXX", "234" }, - { "XXX", "3456" }, - { "XXX", "23456" }, - { "XXX", "2:34" }, - { "XXX", "12:4" }, - { "XXX", "12:34" }, - { "XXX", "-1" }, - { "XXX", "+1" }, - { "XXX", "-12" }, - { "XXX", "+12" }, - { "XXX", "-123" }, - { "XXX", "+123" }, - { "XXX", "-1234" }, - { "XXX", "+1234" }, - { "XXX", "+24:23" }, - { "XXX", "+12:60" }, - { "XXX", "+1:23" }, - { "XXX", "+12:3" }, + { "X", "1", "1" }, + { "X", "+1", "+1" }, + { "X", "-2", "-2" }, + { "X", "-24", "-2" }, + { "X", "+24", "+2" }, + + { "XX", "9", "9" }, + { "XX", "23", "2" }, + { "XX", "234", "2" }, + { "XX", "3456", "3" }, + { "XX", "23456", "2" }, + { "XX", "+1", "+1" }, + { "XX", "-12", "-12" }, + { "XX", "+123", "+123" }, + { "XX", "-12:34", "-12" }, + { "XX", "+12:34", "+12" }, + { "XX", "-2423", "-2" }, + { "XX", "+2423", "+2" }, + { "XX", "-1260", "-126" }, + { "XX", "+1260", "+126" }, + + { "XXX", "9", "9" }, + { "XXX", "23", "2" }, + { "XXX", "234", "2" }, + { "XXX", "3456", "3" }, + { "XXX", "23456", "2" }, + { "XXX", "2:34", "2" }, + { "XXX", "12:4", "1" }, + { "XXX", "12:34", "1" }, + { "XXX", "-1", "-1" }, + { "XXX", "+1", "+1" }, + { "XXX", "-12", "-12" }, + { "XXX", "+12", "+12" }, + { "XXX", "-123", "-12" }, + { "XXX", "+123", "+12" }, + { "XXX", "-1234", "-12" }, + { "XXX", "+1234", "+12" }, + { "XXX", "+24:23", "+2" }, + { "XXX", "+12:60", "+12:6" }, + { "XXX", "+1:23", "+1" }, + { "XXX", "+12:3", "+12:3" }, }; static String[] badFormats = { @@ -110,6 +113,8 @@ public class ISO8601ZoneTest { public static void main(String[] args) throws Exception { TimeZone tz = TimeZone.getDefault(); + Locale loc = Locale.getDefault(); + Locale.setDefault(Locale.US); try { for (int i = 0; i < formatData.length; i++) { @@ -128,7 +133,7 @@ public class ISO8601ZoneTest { } for (String[] d : badData) { - badDataParsing(d[0], d[1]); + badDataParsing(d[0], d[1], d[2].length()); } for (String fmt : badFormats) { @@ -136,6 +141,7 @@ public class ISO8601ZoneTest { } } finally { TimeZone.setDefault(tz); + Locale.setDefault(loc); } } @@ -188,15 +194,24 @@ public class ISO8601ZoneTest { } - static void badDataParsing(String fmt, String text) { + static void badDataParsing(String fmt, String text, int expectedErrorIndex) { + SimpleDateFormat sdf = new SimpleDateFormat(fmt); try { - SimpleDateFormat sdf = new SimpleDateFormat(fmt); sdf.parse(text); throw new RuntimeException("didn't throw an exception: fmt=" + fmt + ", text=" + text); } catch (ParseException e) { // OK } + + ParsePosition pos = new ParsePosition(0); + Date d = sdf.parse(text, pos); + int errorIndex = pos.getErrorIndex(); + if (d != null || errorIndex != expectedErrorIndex) { + throw new RuntimeException("Bad error index=" + errorIndex + + ", expected=" + expectedErrorIndex + + ", fmt=" + fmt + ", text=" + text); + } } static void badFormat(String fmt) { diff --git a/test/java/text/Format/MessageFormat/Bug7003643.java b/test/java/text/Format/MessageFormat/Bug7003643.java new file mode 100644 index 0000000000000000000000000000000000000000..aeb722cac17203193811133c8b0ece4dc7d19528 --- /dev/null +++ b/test/java/text/Format/MessageFormat/Bug7003643.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +/* + * @test + * @bug 7003643 + * @summary Make sure MessageFormat.toPattern produces correct quoting. (SPI part is tested in PluggableLocale tests.) + */ + +import java.text.*; +import java.util.*; + +public class Bug7003643 { + private static final int N = 5; + + private static final String[] elements = { + "'{'", "'{", "{", "''", "}", "a", "'", + }; + + public static void main(String[] args) { + Random rand = new Random(); + int count = 0; + int max = (int) (Math.pow((double)elements.length, (double)N)/0.52); + while (count < max) { + // Create a random pattern. If the produced pattern is + // valid, then proceed with the round-trip testing. + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < N; i++) { + sb.append(elements[rand.nextInt(elements.length)]); + } + String pattern = sb.toString(); + MessageFormat mf = null; + try { + mf = new MessageFormat(pattern); + } catch (IllegalArgumentException e) { + // bad pattern data + } + if (mf == null) { + continue; + } + count++; + String res1 = MessageFormat.format(pattern, 123); + String toPattern = mf.toPattern(); + String res2 = MessageFormat.format(toPattern, 123); + if (!res1.equals(res2)) { + String s = String.format("Failed%n pattern=\"%s\" => result=\"%s\"%n" + + " toPattern()=\"%s\" => result=\"%s\"%n", + pattern, res1, toPattern, res2); + throw new RuntimeException(s); + } + } + } +} diff --git a/test/java/util/Locale/LocaleTest.java b/test/java/util/Locale/LocaleTest.java index af00c6bba6cd83df197aca1a7cd62a77fb3252be..0c21a8ef3544b870269a16349a482425dafb5e80 100644 --- a/test/java/util/Locale/LocaleTest.java +++ b/test/java/util/Locale/LocaleTest.java @@ -24,7 +24,8 @@ * @test * @bug 4052404 4052440 4084688 4092475 4101316 4105828 4107014 4107953 4110613 * 4118587 4118595 4122371 4126371 4126880 4135316 4135752 4139504 4139940 4143951 - * 4147315 4147317 4147552 4335196 4778440 5010672 6475525 6544471 6627549 6786276 + * 4147315 4147317 4147552 4335196 4778440 4940539 5010672 6475525 6544471 6627549 + * 6786276 * @summary test Locales */ /* @@ -895,17 +896,28 @@ test commented out pending API-change approval } /** - * @bug 4147317 - * java.util.Locale.getISO3Language() works wrong for non ISO-3166 codes. - * Should throw an exception for unknown locales + * @bug 4147317 4940539 + * java.util.Locale.getISO3Language() works wrong for non ISO-639 codes. + * Should throw an exception for unknown locales, except they have three + * letter language codes. */ public void Test4147317() { - // Try with codes that are the wrong length but happen to match text - // at a valid offset in the mapping table + // Try a three letter language code, and check whether it is + // returned as is. Locale locale = new Locale("aaa", "CCC"); + String result = locale.getISO3Language(); + if (!result.equals("aaa")) { + errln("ERROR: getISO3Language() returns: " + result + + " for locale '" + locale + "' rather than returning it as is" ); + } + + // Try an invalid two letter language code, and check whether it + // throws a MissingResourceException. + locale = new Locale("zz", "CCC"); + try { - String result = locale.getISO3Language(); + result = locale.getISO3Language(); errln("ERROR: getISO3Language() returns: " + result + " for locale '" + locale + "' rather than exception" ); diff --git a/test/java/util/PluggableLocale/DateFormatProviderTest.java b/test/java/util/PluggableLocale/DateFormatProviderTest.java index 6112b6836a437472d97d0f8844631730315e8479..6d5ecd23f3a2e340e48bfa8b4812f30e69a5e02f 100644 --- a/test/java/util/PluggableLocale/DateFormatProviderTest.java +++ b/test/java/util/PluggableLocale/DateFormatProviderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,7 @@ public class DateFormatProviderTest extends ProviderTest { availableLocalesTest(); objectValidityTest(); extendedVariantTest(); + messageFormatTest(); } void availableLocalesTest() { @@ -118,4 +119,48 @@ public class DateFormatProviderTest extends ProviderTest { } } } + + + private static final String[] TYPES = { + "date", + "time" + }; + private static final String[] MODIFIERS = { + "", + "short", + "medium", // Same as DEFAULT + "long", + "full" + }; + + void messageFormatTest() { + for (Locale target : providerloc) { + for (String type : TYPES) { + for (String modifier : MODIFIERS) { + String pattern, expected; + if (modifier.equals("")) { + pattern = String.format("%s={0,%s}", type, type); + } else { + pattern = String.format("%s={0,%s,%s}", type, type, modifier); + } + if (modifier.equals("medium")) { + // medium is default. + expected = String.format("%s={0,%s}", type, type); + } else { + expected = pattern; + } + MessageFormat mf = new MessageFormat(pattern, target); + Format[] fmts = mf.getFormats(); + if (fmts[0] instanceof SimpleDateFormat) { + continue; + } + String toPattern = mf.toPattern(); + if (!toPattern.equals(expected)) { + throw new RuntimeException("messageFormatTest: got '" + toPattern + + "', expected '" + expected + "'"); + } + } + } + } + } } diff --git a/test/java/util/PluggableLocale/DateFormatProviderTest.sh b/test/java/util/PluggableLocale/DateFormatProviderTest.sh index 0d7ad953fe209af41be14765e50cf35a94cf5954..228a2484a100b09bd22da771dad20e0add0f10d9 100644 --- a/test/java/util/PluggableLocale/DateFormatProviderTest.sh +++ b/test/java/util/PluggableLocale/DateFormatProviderTest.sh @@ -1,5 +1,5 @@ # -# Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,6 @@ #!/bin/sh # # @test -# @bug 4052440 +# @bug 4052440 7003643 # @summary DateFormatProvider tests # @run shell ExecTest.sh foo DateFormatProviderTest true diff --git a/test/java/util/PluggableLocale/NumberFormatProviderTest.java b/test/java/util/PluggableLocale/NumberFormatProviderTest.java index 93540bf1764da7281305d1b3702098b2181200b4..a7ebfb794975b15b3e95d350911244e9ebde2be0 100644 --- a/test/java/util/PluggableLocale/NumberFormatProviderTest.java +++ b/test/java/util/PluggableLocale/NumberFormatProviderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,8 @@ import java.util.*; import sun.util.*; import sun.util.resources.*; +import com.foo.FooNumberFormat; + public class NumberFormatProviderTest extends ProviderTest { com.foo.NumberFormatProviderImpl nfp = new com.foo.NumberFormatProviderImpl(); @@ -43,6 +45,7 @@ public class NumberFormatProviderTest extends ProviderTest { NumberFormatProviderTest() { availableLocalesTest(); objectValidityTest(); + messageFormatTest(); } void availableLocalesTest() { @@ -72,14 +75,10 @@ public class NumberFormatProviderTest extends ProviderTest { } // result object - String resultCur = - ((DecimalFormat)NumberFormat.getCurrencyInstance(target)).toPattern(); - String resultInt = - ((DecimalFormat)NumberFormat.getIntegerInstance(target)).toPattern(); - String resultNum = - ((DecimalFormat)NumberFormat.getNumberInstance(target)).toPattern(); - String resultPer = - ((DecimalFormat)NumberFormat.getPercentInstance(target)).toPattern(); + String resultCur = getPattern(NumberFormat.getCurrencyInstance(target)); + String resultInt = getPattern(NumberFormat.getIntegerInstance(target)); + String resultNum = getPattern(NumberFormat.getNumberInstance(target)); + String resultPer = getPattern(NumberFormat.getPercentInstance(target)); // provider's object (if any) String providersCur = null; @@ -87,21 +86,21 @@ public class NumberFormatProviderTest extends ProviderTest { String providersNum = null; String providersPer = null; if (providerloc.contains(target)) { - DecimalFormat dfCur = (DecimalFormat)nfp.getCurrencyInstance(target); + NumberFormat dfCur = nfp.getCurrencyInstance(target); if (dfCur != null) { - providersCur = dfCur.toPattern(); + providersCur = getPattern(dfCur); } - DecimalFormat dfInt = (DecimalFormat)nfp.getIntegerInstance(target); + NumberFormat dfInt = nfp.getIntegerInstance(target); if (dfInt != null) { - providersInt = dfInt.toPattern(); + providersInt = getPattern(dfInt); } - DecimalFormat dfNum = (DecimalFormat)nfp.getNumberInstance(target); + NumberFormat dfNum = nfp.getNumberInstance(target); if (dfNum != null) { - providersNum = dfNum.toPattern(); + providersNum = getPattern(dfNum); } - DecimalFormat dfPer = (DecimalFormat)nfp.getPercentInstance(target); + NumberFormat dfPer = nfp.getPercentInstance(target); if (dfPer != null) { - providersPer = dfPer.toPattern(); + providersPer = getPattern(dfPer); } } @@ -174,4 +173,35 @@ public class NumberFormatProviderTest extends ProviderTest { } } } + + private static String getPattern(NumberFormat nf) { + if (nf instanceof DecimalFormat) { + return ((DecimalFormat)nf).toPattern(); + } + if (nf instanceof FooNumberFormat) { + return ((FooNumberFormat)nf).toPattern(); + } + return null; + } + + private static final String[] NUMBER_PATTERNS = { + "num={0,number}", + "num={0,number,currency}", + "num={0,number,percent}", + "num={0,number,integer}" + }; + + void messageFormatTest() { + for (Locale target : providerloc) { + for (String pattern : NUMBER_PATTERNS) { + MessageFormat mf = new MessageFormat(pattern, target); + String toPattern = mf.toPattern(); + if (!pattern.equals(toPattern)) { + throw new RuntimeException("MessageFormat.toPattern: got '" + + toPattern + + "', expected '" + pattern + "'"); + } + } + } + } } diff --git a/test/java/util/PluggableLocale/NumberFormatProviderTest.sh b/test/java/util/PluggableLocale/NumberFormatProviderTest.sh index 7967da9f070d1f4a9bd66a7bee05e8cc983a7c4f..7f4e902a91451bb0bf5daca113600d355109f14b 100644 --- a/test/java/util/PluggableLocale/NumberFormatProviderTest.sh +++ b/test/java/util/PluggableLocale/NumberFormatProviderTest.sh @@ -1,5 +1,5 @@ # -# Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,6 @@ #!/bin/sh # # @test -# @bug 4052440 +# @bug 4052440 7003643 # @summary NumberFormatProvider tests # @run shell ExecTest.sh foo NumberFormatProviderTest true diff --git a/test/java/util/PluggableLocale/fooprovider.jar b/test/java/util/PluggableLocale/fooprovider.jar index 29ea53fcca62228087b1f864009aa21447af46c2..c1b5723f9b95dad064ed0393dd878cd7d82f3c51 100644 Binary files a/test/java/util/PluggableLocale/fooprovider.jar and b/test/java/util/PluggableLocale/fooprovider.jar differ diff --git a/test/java/util/PluggableLocale/providersrc/DateFormatProviderImpl.java b/test/java/util/PluggableLocale/providersrc/DateFormatProviderImpl.java index 25e7b1769462d8df3c650854e588339e94797bb5..55bc8d5ae73f3d1c8cb9a7b40b7acc078c71ef51 100644 --- a/test/java/util/PluggableLocale/providersrc/DateFormatProviderImpl.java +++ b/test/java/util/PluggableLocale/providersrc/DateFormatProviderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ public class DateFormatProviderImpl extends DateFormatProvider { static String[] datePattern = { "yyyy'\u5e74'M'\u6708'd'\u65e5'", // full date pattern - "yyyy/MM/dd", // long date pattern + "yyyy/MMM/dd", // long date pattern "yyyy/MM/dd", // medium date pattern "yy/MM/dd" // short date pattern }; @@ -68,7 +68,7 @@ public class DateFormatProviderImpl extends DateFormatProvider { public DateFormat getDateInstance(int style, Locale locale) { for (int i = 0; i < avail.length; i ++) { if (Utils.supportsLocale(avail[i], locale)) { - return new SimpleDateFormat(datePattern[style]+dialect[i], locale); + return new FooDateFormat(datePattern[style]+dialect[i], locale); } } throw new IllegalArgumentException("locale is not supported: "+locale); @@ -77,7 +77,7 @@ public class DateFormatProviderImpl extends DateFormatProvider { public DateFormat getTimeInstance(int style, Locale locale) { for (int i = 0; i < avail.length; i ++) { if (Utils.supportsLocale(avail[i], locale)) { - return new SimpleDateFormat(timePattern[style]+dialect[i], locale); + return new FooDateFormat(timePattern[style]+dialect[i], locale); } } throw new IllegalArgumentException("locale is not supported: "+locale); @@ -86,7 +86,7 @@ public class DateFormatProviderImpl extends DateFormatProvider { public DateFormat getDateTimeInstance(int dateStyle, int timeStyle, Locale locale) { for (int i = 0; i < avail.length; i ++) { if (Utils.supportsLocale(avail[i], locale)) { - return new SimpleDateFormat( + return new FooDateFormat( datePattern[dateStyle]+" "+timePattern[timeStyle]+dialect[i], locale); } } diff --git a/test/java/util/PluggableLocale/providersrc/FooDateFormat.java b/test/java/util/PluggableLocale/providersrc/FooDateFormat.java new file mode 100644 index 0000000000000000000000000000000000000000..80d4ce2010fb6555b8ea6042f3a7b0dcd094d11f --- /dev/null +++ b/test/java/util/PluggableLocale/providersrc/FooDateFormat.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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 com.foo; + +import java.text.*; +import java.util.*; + +/** + * FooDateFormat provides SimpleDateFormat methods required for the SPI testing. + */ +public class FooDateFormat extends DateFormat { + private SimpleDateFormat sdf; + + public FooDateFormat(String pattern, Locale loc) { + sdf = new SimpleDateFormat(pattern, loc); + } + + @Override + public StringBuffer format(Date date, + StringBuffer toAppendTo, + FieldPosition fieldPosition) { + return sdf.format(date, toAppendTo, fieldPosition); + } + + @Override + public Date parse(String source, ParsePosition pos) { + return sdf.parse(source, pos); + } + + @Override + public boolean equals(Object other) { + return other instanceof FooDateFormat + && sdf.equals(((FooDateFormat)other).sdf); + } + + @Override + public int hashCode() { + return sdf.hashCode(); + } +} diff --git a/test/java/util/PluggableLocale/providersrc/FooNumberFormat.java b/test/java/util/PluggableLocale/providersrc/FooNumberFormat.java new file mode 100644 index 0000000000000000000000000000000000000000..d13bd7362fed3bb046ae3053479d971d1ec3f076 --- /dev/null +++ b/test/java/util/PluggableLocale/providersrc/FooNumberFormat.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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 com.foo; + +import java.text.*; + +/** + * FooNumberFormat provides DecimalFormat methods required for the SPI testing. + */ +public class FooNumberFormat extends NumberFormat { + private DecimalFormat df; + + public FooNumberFormat(String pattern, DecimalFormatSymbols dfs) { + df = new DecimalFormat(pattern, dfs); + } + + @Override + public StringBuffer format(double number, + StringBuffer toAppendTo, + FieldPosition pos) { + return df.format(number, toAppendTo, pos); + } + + @Override + public StringBuffer format(long number, + StringBuffer toAppendTo, + FieldPosition pos) { + return df.format(number, toAppendTo, pos); + } + + @Override + public Number parse(String source, ParsePosition parsePosition) { + return df.parse(source, parsePosition); + } + + @Override + public boolean equals(Object other) { + return other instanceof FooNumberFormat + && df.equals(((FooNumberFormat)other).df); + } + + @Override + public int hashCode() { + return df.hashCode(); + } + + // DecimalFormat specific methods required for testing + + public String toPattern() { + return df.toPattern(); + } + + public DecimalFormatSymbols getDecimalFormatSymbols() { + return df.getDecimalFormatSymbols(); + } + + public void setDecimalSeparatorAlwaysShown(boolean newValue) { + df.setDecimalSeparatorAlwaysShown(newValue); + } +} diff --git a/test/java/util/PluggableLocale/providersrc/Makefile b/test/java/util/PluggableLocale/providersrc/Makefile index a85ea065e981950aa2e5b8a3f872657f4f23beaa..8d2fa9cab808568a238929fef8847c7bc926c73b 100644 --- a/test/java/util/PluggableLocale/providersrc/Makefile +++ b/test/java/util/PluggableLocale/providersrc/Makefile @@ -28,6 +28,8 @@ FOOFILES_JAVA = \ DateFormatSymbolsProviderImpl.java \ DecimalFormatSymbolsProviderImpl.java \ NumberFormatProviderImpl.java \ + FooDateFormat.java \ + FooNumberFormat.java \ Utils.java BARFILES_JAVA = \ diff --git a/test/java/util/PluggableLocale/providersrc/NumberFormatProviderImpl.java b/test/java/util/PluggableLocale/providersrc/NumberFormatProviderImpl.java index 164de5e1db634982482a24c2e1f9697e4fd49d73..9aa677cf89bcaf004b3c1fd9c4a12c536a4d3d9a 100644 --- a/test/java/util/PluggableLocale/providersrc/NumberFormatProviderImpl.java +++ b/test/java/util/PluggableLocale/providersrc/NumberFormatProviderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,13 +49,15 @@ public class NumberFormatProviderImpl extends NumberFormatProvider { static String[] patterns = { "#,##0.###{0};-#,##0.###{1}", // decimal pattern + "#{0};(#){1}", // integer pattern "\u00A4#,##0{0};-\u00A4#,##0{1}", // currency pattern "#,##0%{0}" // percent pattern }; // Constants used by factory methods to specify a style of format. static final int NUMBERSTYLE = 0; - static final int CURRENCYSTYLE = 1; - static final int PERCENTSTYLE = 2; + static final int INTEGERSTYLE = 1; + static final int CURRENCYSTYLE = 2; + static final int PERCENTSTYLE = 3; public Locale[] getAvailableLocales() { return avail; @@ -68,10 +70,10 @@ public class NumberFormatProviderImpl extends NumberFormatProvider { MessageFormat.format(patterns[CURRENCYSTYLE], dialect[i], dialect[i]); - DecimalFormat df = new DecimalFormat(pattern, + FooNumberFormat nf = new FooNumberFormat(pattern, DecimalFormatSymbols.getInstance(locale)); - adjustForCurrencyDefaultFractionDigits(df); - return df; + adjustForCurrencyDefaultFractionDigits(nf); + return nf; } } throw new IllegalArgumentException("locale is not supported: "+locale); @@ -81,15 +83,15 @@ public class NumberFormatProviderImpl extends NumberFormatProvider { for (int i = 0; i < avail.length; i ++) { if (Utils.supportsLocale(avail[i], locale)) { String pattern = - MessageFormat.format(patterns[NUMBERSTYLE], + MessageFormat.format(patterns[INTEGERSTYLE], dialect[i], dialect[i]); - DecimalFormat df = new DecimalFormat(pattern, + FooNumberFormat nf = new FooNumberFormat(pattern, DecimalFormatSymbols.getInstance(locale)); - df.setMaximumFractionDigits(0); - df.setDecimalSeparatorAlwaysShown(false); - df.setParseIntegerOnly(true); - return df; + nf.setMaximumFractionDigits(0); + nf.setDecimalSeparatorAlwaysShown(false); + nf.setParseIntegerOnly(true); + return nf; } } throw new IllegalArgumentException("locale is not supported: "+locale); @@ -102,7 +104,7 @@ public class NumberFormatProviderImpl extends NumberFormatProvider { MessageFormat.format(patterns[NUMBERSTYLE], dialect[i], dialect[i]); - return new DecimalFormat(pattern, + return new FooNumberFormat(pattern, DecimalFormatSymbols.getInstance(locale)); } } @@ -115,7 +117,7 @@ public class NumberFormatProviderImpl extends NumberFormatProvider { String pattern = MessageFormat.format(patterns[PERCENTSTYLE], dialect[i]); - return new DecimalFormat(pattern, + return new FooNumberFormat(pattern, DecimalFormatSymbols.getInstance(locale)); } } @@ -126,8 +128,8 @@ public class NumberFormatProviderImpl extends NumberFormatProvider { * Adjusts the minimum and maximum fraction digits to values that * are reasonable for the currency's default fraction digits. */ - void adjustForCurrencyDefaultFractionDigits(DecimalFormat df) { - DecimalFormatSymbols dfs = df.getDecimalFormatSymbols(); + void adjustForCurrencyDefaultFractionDigits(FooNumberFormat nf) { + DecimalFormatSymbols dfs = nf.getDecimalFormatSymbols(); Currency currency = dfs.getCurrency(); if (currency == null) { try { @@ -138,15 +140,15 @@ public class NumberFormatProviderImpl extends NumberFormatProvider { if (currency != null) { int digits = currency.getDefaultFractionDigits(); if (digits != -1) { - int oldMinDigits = df.getMinimumFractionDigits(); + int oldMinDigits = nf.getMinimumFractionDigits(); // Common patterns are "#.##", "#.00", "#". // Try to adjust all of them in a reasonable way. - if (oldMinDigits == df.getMaximumFractionDigits()) { - df.setMinimumFractionDigits(digits); - df.setMaximumFractionDigits(digits); + if (oldMinDigits == nf.getMaximumFractionDigits()) { + nf.setMinimumFractionDigits(digits); + nf.setMaximumFractionDigits(digits); } else { - df.setMinimumFractionDigits(Math.min(digits, oldMinDigits)); - df.setMaximumFractionDigits(digits); + nf.setMinimumFractionDigits(Math.min(digits, oldMinDigits)); + nf.setMaximumFractionDigits(digits); } } } diff --git a/test/javax/swing/JFileChooser/4847375/bug4847375.java b/test/javax/swing/JFileChooser/4847375/bug4847375.java new file mode 100644 index 0000000000000000000000000000000000000000..8a9af80b672fe93699ba40034e4febee42cbf8c6 --- /dev/null +++ b/test/javax/swing/JFileChooser/4847375/bug4847375.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +/* + * @test + * @bug 4847375 + * @summary JFileChooser Create New Folder button is disabled incorrectly + * @author Pavel Porvatov + */ + +import sun.awt.OSInfo; +import sun.awt.shell.ShellFolder; + +import javax.swing.*; +import java.awt.*; +import java.lang.reflect.Method; + +public class bug4847375 { + private final String newFolderToolTipText; + + private final String lookAndFeel; + + public static void main(String[] args) throws Exception { + if (OSInfo.getOSType() != OSInfo.OSType.WINDOWS) { + System.out.println("The test is suitable only for Windows OS. Skipped."); + + return; + } + + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + new bug4847375("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + + new bug4847375("javax.swing.plaf.metal.MetalLookAndFeel"); + } + }); + } + + private static Object[][] DIRECTORIES = new Object[][]{ + {"getDesktop", Boolean.TRUE}, + {"getDrives", Boolean.FALSE}, // My computer + {"getRecent", Boolean.TRUE}, + {"getNetwork", Boolean.FALSE}, + {"getPersonal", Boolean.TRUE}, + }; + + private bug4847375(String lookAndFeel) { + this.lookAndFeel = lookAndFeel; + + try { + UIManager.setLookAndFeel(lookAndFeel); + } catch (Exception e) { + fail("Cannot set LookAndFeel", e); + } + + JFileChooser fileChooser = new JFileChooser(); + + // Find button NewFolder + newFolderToolTipText = UIManager.getString("FileChooser.newFolderToolTipText", fileChooser.getLocale()); + + if (newFolderToolTipText == null || newFolderToolTipText.length() == 0) { + fail("Cannot find NewFolderButton in FileChooser (tooltip doesn't exist)"); + + return; + } + + JButton newFolderButton = findNewFolderButton(fileChooser); + + if (newFolderButton == null) { + fail("Cannot find NewFolderButton in FileChooser"); + + return; + } + + for (Object[] objects : DIRECTORIES) { + String getterName = (String) objects[0]; + Boolean enabledNewFolder = (Boolean) objects[1]; + + fileChooser.setCurrentDirectory(getWin32Folder(getterName)); + + if (newFolderButton.isEnabled() != enabledNewFolder) { + fail("Enabled state of NewFolderButton should be " + enabledNewFolder + + " for Win32ShellFolderManager2." + getterName + "()"); + } + } + } + + private JButton findNewFolderButton(Container container) { + JButton result = null; + + for (int i = 0; i < container.getComponentCount(); i++) { + Component c = container.getComponent(i); + + if (c instanceof JButton && newFolderToolTipText.equals(((JButton) c).getToolTipText())) { + if (result != null) { + fail("Two or more NewFolderButton found in FileChooser"); + } + + result = (JButton) c; + } + + if (c instanceof Container) { + JButton button = findNewFolderButton((Container) c); + + if (result == null) { + result = button; + } else { + if (button != null) { + fail("Two or more NewFolderButton found in FileChooser"); + } + } + } + } + + return result; + } + + private ShellFolder getWin32Folder(String getterName) { + try { + Class win32ShellFolderManager2 = Class.forName("sun.awt.shell.Win32ShellFolderManager2"); + + Method method = win32ShellFolderManager2.getDeclaredMethod(getterName); + method.setAccessible(true); + + return (ShellFolder) method.invoke(null); + } catch (Exception e) { + fail("Cannot call '" + getterName + "' in the Win32ShellFolderManager2 class", e); + + return null; + } + } + + private void fail(String s) { + throw new RuntimeException("Test failed: " + s); + } + + private void fail(String s, Throwable e) { + throw new RuntimeException("Test failed for LookAndFeel " + lookAndFeel + ": " + s, e); + } +} diff --git a/test/javax/swing/JScrollBar/6542335/bug6542335.java b/test/javax/swing/JScrollBar/6542335/bug6542335.java index 33e95d8ecac74a6c9c3963b5fc6f1566ef8e5c9b..d4ed4736e346a2f440632d5be534d37169619d3e 100644 --- a/test/javax/swing/JScrollBar/6542335/bug6542335.java +++ b/test/javax/swing/JScrollBar/6542335/bug6542335.java @@ -40,11 +40,13 @@ public class bug6542335 { private static MyScrollBarUI ui; public static void main(String[] args) throws Exception { - Robot robot = new Robot(); + final Robot robot = new Robot(); robot.setAutoDelay(10); SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); + final Rectangle[] thumbBounds = new Rectangle[1]; + SwingUtilities.invokeAndWait(new Runnable() { public void run() { final JFrame frame = new JFrame("bug6542335"); @@ -63,25 +65,39 @@ public class bug6542335 { rangeModel.setValue(50); sb.setModel(rangeModel); - frame.add(sb); + frame.add(sb, BorderLayout.NORTH); frame.setSize(200, 100); frame.setVisible(true); + + thumbBounds[0] = new Rectangle(ui.getThumbBounds()); } }); - Rectangle thumbBounds = new Rectangle(ui.getThumbBounds()); - toolkit.realSync(); - Point l = sb.getLocationOnScreen(); - robot.mouseMove(l.x + (int) (0.75 * sb.getWidth()), l.y + sb.getHeight()/2); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.mouseRelease(InputEvent.BUTTON1_MASK); + + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + Point l = sb.getLocationOnScreen(); + + robot.mouseMove(l.x + (int) (0.75 * sb.getWidth()), l.y + sb.getHeight() / 2); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + } + }); + toolkit.realSync(); - if (!thumbBounds.equals(ui.getThumbBounds())) { - throw new RuntimeException("Test failed"); - } + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + Rectangle newThumbBounds = ui.getThumbBounds(); + + if (!thumbBounds[0].equals(newThumbBounds)) { + throw new RuntimeException("Test failed.\nOld bounds: " + thumbBounds[0] + + "\nNew bounds: " + newThumbBounds); + } + } + }); } static class MyScrollBarUI extends BasicScrollBarUI { diff --git a/test/javax/swing/JSpinner/6532833/bug6532833.java b/test/javax/swing/JSpinner/6532833/bug6532833.java new file mode 100644 index 0000000000000000000000000000000000000000..184fe69d96d345d557e91137aa7ca63207317db5 --- /dev/null +++ b/test/javax/swing/JSpinner/6532833/bug6532833.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +/* @test + @bug 6532833 + @summary PIT: Metal LAF - The right side border is not shown for the Spinner after the removing the buttons + @author Pavel Porvatov +*/ + +import javax.swing.*; +import java.awt.*; + +public class bug6532833 { + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + JSpinner[] spinners = new JSpinner[2]; + + for (int i = 0; i < spinners.length; i++) { + JSpinner spinner = new JSpinner(); + + spinner.setValue(2010); + + Component arrowUp = spinner.getComponent(0); + Component arrowDown = spinner.getComponent(1); + + LayoutManager layout = spinner.getLayout(); + + layout.removeLayoutComponent(arrowUp); + layout.removeLayoutComponent(arrowDown); + + if (i == 1) { + spinner.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); + } + + spinners[i] = spinner; + } + + // Do layout of spinners components + JFrame frame = new JFrame(); + + for (JSpinner spinner : spinners) { + frame.getContentPane().add(spinner); + } + + frame.pack(); + + for (JSpinner spinner : spinners) { + Insets insets = spinner.getInsets(); + + if (spinner.getWidth() != insets.left + insets.right + spinner.getEditor().getWidth()) { + throw new RuntimeException("Spinner editor width is invalid"); + } + } + + frame.dispose(); + } + }); + } +} diff --git a/test/javax/swing/SwingWorker/6480289/bug6480289.java b/test/javax/swing/SwingWorker/6480289/bug6480289.java deleted file mode 100644 index 9ff34969a31f5a036dd6952c7c8081a8742c5c9e..0000000000000000000000000000000000000000 --- a/test/javax/swing/SwingWorker/6480289/bug6480289.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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. - */ - -/* @test - * - * @bug 6480289 - * @author Igor Kushnirskiy - * @summary tests if consequent workers are executed on the same thread and that VM can exit. - */ - -import java.util.*; -import javax.swing.SwingWorker; - -public class bug6480289 { - private static final int ITERATIONS = 5; - private static final Map threadMap = - Collections.synchronizedMap(new HashMap()); - public static void main(String[] args) throws Exception { - - for (int i = 0; i < ITERATIONS; i++) { - if (i != 0) { - Thread.sleep(1000 * 5); - } - SwingWorker worker = - new SwingWorker() { - @Override - protected Void doInBackground() { - Integer value = threadMap.get(Thread.currentThread()); - value = Integer.valueOf( - ((value == null) ? 0 : value.intValue()) - + 1); - threadMap.put(Thread.currentThread(), value); - return null; - } - }; - worker.execute(); - } - if (threadMap.keySet().size() != 1) { - throw new RuntimeException("failed. More than one thread."); - } - } -}