This commit is contained in:
Lana Steuck 2009-11-18 17:16:27 -08:00
commit f3baefc4fb
23 changed files with 298 additions and 55 deletions

@ -65,7 +65,7 @@ import javax.print.attribute.PrintServiceAttribute;
* PrinterStateReason PrinterStateReason} objects to an existing * PrinterStateReason PrinterStateReason} objects to an existing
* PrinterStateReasons object and remove them again. However, like class * PrinterStateReasons object and remove them again. However, like class
* {@link java.util.HashMap java.util.HashMap}, class PrinterStateReasons is * {@link java.util.HashMap java.util.HashMap}, class PrinterStateReasons is
* bot multiple thread safe. If a PrinterStateReasons object will be used by * not multiple thread safe. If a PrinterStateReasons object will be used by
* multiple threads, be sure to synchronize its operations (e.g., using a * multiple threads, be sure to synchronize its operations (e.g., using a
* synchronized map view obtained from class {@link java.util.Collections * synchronized map view obtained from class {@link java.util.Collections
* java.util.Collections}). * java.util.Collections}).

@ -320,21 +320,6 @@ public abstract class Font2D {
lastFontStrike = new SoftReference(strike); lastFontStrike = new SoftReference(strike);
StrikeCache.refStrike(strike); StrikeCache.refStrike(strike);
return strike; return strike;
} else {
/* We have found a cleared reference that has not yet
* been removed by the disposer.
* If we make this reference unreachable by removing it
* from the map,or overwriting it with a new reference to
* a new strike, then it is possible it may never be
* enqueued for disposal. That is the implication of
* the docs for java.lang.ref. So on finding a cleared
* reference, we need to dispose the native resources,
* if they haven't already been freed.
* The reference object needs to have a reference to
* the disposer instance for this to occur.
*/
((StrikeCache.DisposableStrike)strikeRef)
.getDisposer().dispose();
} }
} }
/* When we create a new FontStrike instance, we *must* /* When we create a new FontStrike instance, we *must*

@ -171,7 +171,7 @@ public final class FontDesignMetrics extends FontMetrics {
* out we can clear the keys from the table. * out we can clear the keys from the table.
*/ */
private static class KeyReference extends SoftReference private static class KeyReference extends SoftReference
implements DisposerRecord { implements DisposerRecord, Disposer.PollDisposable {
static ReferenceQueue queue = Disposer.getQueue(); static ReferenceQueue queue = Disposer.getQueue();

@ -25,6 +25,7 @@
package sun.font; package sun.font;
import sun.java2d.Disposer;
import sun.java2d.DisposerRecord; import sun.java2d.DisposerRecord;
/* /*
@ -49,7 +50,8 @@ import sun.java2d.DisposerRecord;
* entries would be removed much more promptly than we need. * entries would be removed much more promptly than we need.
*/ */
class FontStrikeDisposer implements DisposerRecord { class FontStrikeDisposer
implements DisposerRecord, Disposer.PollDisposable {
Font2D font2D; Font2D font2D;
FontStrikeDesc desc; FontStrikeDesc desc;

@ -254,9 +254,20 @@ public final class StrikeCache {
// because they may be accessed on that thread at the time of the // because they may be accessed on that thread at the time of the
// disposal (for example, when the accel. cache is invalidated) // disposal (for example, when the accel. cache is invalidated)
// REMIND: this look a bit heavyweight, but should be ok // Whilst this is a bit heavyweight, in most applications
// because strike disposal is a relatively infrequent operation, // strike disposal is a relatively infrequent operation, so it
// more worrisome is the necessity of getting a GC here. // doesn't matter. But in some tests that use vast numbers
// of strikes, the switching back and forth is measurable.
// So the "pollRemove" call is added to batch up the work.
// If we are polling we know we've already been called back
// and can directly dispose the record.
// Also worrisome is the necessity of getting a GC here.
if (Disposer.pollingQueue) {
doDispose(disposer);
return;
}
RenderQueue rq = null; RenderQueue rq = null;
GraphicsEnvironment ge = GraphicsEnvironment ge =
GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsEnvironment.getLocalGraphicsEnvironment();
@ -277,6 +288,7 @@ public final class StrikeCache {
rq.flushAndInvokeNow(new Runnable() { rq.flushAndInvokeNow(new Runnable() {
public void run() { public void run() {
doDispose(disposer); doDispose(disposer);
Disposer.pollRemove();
} }
}); });
} finally { } finally {

@ -29,6 +29,7 @@ import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue; import java.lang.ref.ReferenceQueue;
import java.lang.ref.PhantomReference; import java.lang.ref.PhantomReference;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Hashtable; import java.util.Hashtable;
/** /**
@ -146,6 +147,7 @@ public class Disposer implements Runnable {
rec.dispose(); rec.dispose();
obj = null; obj = null;
rec = null; rec = null;
clearDeferredRecords();
} catch (Exception e) { } catch (Exception e) {
System.out.println("Exception while removing reference: " + e); System.out.println("Exception while removing reference: " + e);
e.printStackTrace(); e.printStackTrace();
@ -153,6 +155,85 @@ public class Disposer implements Runnable {
} }
} }
/*
* This is a marker interface that, if implemented, means it
* doesn't acquire any special locks, and is safe to
* be disposed in the poll loop on whatever thread
* which happens to be the Toolkit thread, is in use.
*/
public static interface PollDisposable {
};
private static ArrayList<DisposerRecord> deferredRecords = null;
private static void clearDeferredRecords() {
if (deferredRecords == null || deferredRecords.isEmpty()) {
return;
}
for (int i=0;i<deferredRecords.size(); i++) {
try {
DisposerRecord rec = deferredRecords.get(i);
rec.dispose();
} catch (Exception e) {
System.out.println("Exception while disposing deferred rec.");
e.printStackTrace();
}
}
deferredRecords.clear();
}
/*
* Set to indicate the queue is presently being polled.
*/
public static volatile boolean pollingQueue = false;
/*
* The pollRemove() method is called back from a dispose method
* that is running on the toolkit thread and wants to
* dispose any pending refs that are safe to be disposed
* on that thread.
*/
public static void pollRemove() {
/* This should never be called recursively, so this check
* is just a safeguard against the unexpected.
*/
if (pollingQueue) {
return;
}
Object obj;
pollingQueue = true;
int freed = 0;
int deferred = 0;
try {
while ((obj = queue.poll()) != null
&& freed < 10000 && deferred < 100) {
freed++;
((Reference)obj).clear();
DisposerRecord rec = (DisposerRecord)records.remove(obj);
if (rec instanceof PollDisposable) {
rec.dispose();
obj = null;
rec = null;
} else {
if (rec == null) { // shouldn't happen, but just in case.
continue;
}
deferred++;
if (deferredRecords == null) {
deferredRecords = new ArrayList<DisposerRecord>(5);
}
deferredRecords.add(rec);
}
}
} catch (Exception e) {
System.out.println("Exception while removing reference: " + e);
e.printStackTrace();
} finally {
pollingQueue = false;
}
}
private static native void initIDs(); private static native void initIDs();
/* /*

@ -257,7 +257,6 @@ public final class SunGraphics2D
font = defaultFont; font = defaultFont;
} }
loops = sd.getRenderLoops(this);
setDevClip(sd.getBounds()); setDevClip(sd.getBounds());
invalidatePipe(); invalidatePipe();
} }
@ -367,6 +366,7 @@ public final class SunGraphics2D
shapepipe = invalidpipe; shapepipe = invalidpipe;
textpipe = invalidpipe; textpipe = invalidpipe;
imagepipe = invalidpipe; imagepipe = invalidpipe;
loops = null;
} }
public void validatePipe() { public void validatePipe() {

@ -69,6 +69,7 @@ import sun.java2d.pipe.DrawImagePipe;
import sun.java2d.pipe.DrawImage; import sun.java2d.pipe.DrawImage;
import sun.awt.SunHints; import sun.awt.SunHints;
import sun.awt.image.SurfaceManager; import sun.awt.image.SurfaceManager;
import sun.java2d.pipe.LoopBasedPipe;
/** /**
* This class provides various pieces of information relevant to a * This class provides various pieces of information relevant to a
@ -506,7 +507,6 @@ public abstract class SurfaceData
sg2d.textpipe = solidTextRenderer; sg2d.textpipe = solidTextRenderer;
} }
sg2d.shapepipe = colorPrimitives; sg2d.shapepipe = colorPrimitives;
sg2d.loops = getRenderLoops(sg2d);
// assert(sg2d.surfaceData == this); // assert(sg2d.surfaceData == this);
} }
} else if (sg2d.compositeState == sg2d.COMP_CUSTOM) { } else if (sg2d.compositeState == sg2d.COMP_CUSTOM) {
@ -603,9 +603,18 @@ public abstract class SurfaceData
sg2d.textpipe = getTextPipe(sg2d, false /* AA==OFF */); sg2d.textpipe = getTextPipe(sg2d, false /* AA==OFF */);
sg2d.shapepipe = colorPrimitives; sg2d.shapepipe = colorPrimitives;
sg2d.loops = getRenderLoops(sg2d);
// assert(sg2d.surfaceData == this); // assert(sg2d.surfaceData == this);
} }
// check for loops
if (sg2d.textpipe instanceof LoopBasedPipe ||
sg2d.shapepipe instanceof LoopBasedPipe ||
sg2d.fillpipe instanceof LoopBasedPipe ||
sg2d.drawpipe instanceof LoopBasedPipe ||
sg2d.imagepipe instanceof LoopBasedPipe)
{
sg2d.loops = getRenderLoops(sg2d);
}
} }
/* Return the text pipe to be used based on the graphics AA hint setting, /* Return the text pipe to be used based on the graphics AA hint setting,

@ -34,8 +34,9 @@ import sun.font.GlyphList;
* a solid source colour to an opaque destination. * a solid source colour to an opaque destination.
*/ */
public class AATextRenderer extends GlyphListLoopPipe { public class AATextRenderer extends GlyphListLoopPipe
implements LoopBasedPipe
{
protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) { protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) {
sg2d.loops.drawGlyphListAALoop.DrawGlyphListAA(sg2d, sg2d.surfaceData, sg2d.loops.drawGlyphListAALoop.DrawGlyphListAA(sg2d, sg2d.surfaceData,
gl); gl);

@ -36,8 +36,9 @@ import sun.font.GlyphList;
* the installed loop may not match the glyphvector. * the installed loop may not match the glyphvector.
*/ */
public abstract class GlyphListLoopPipe extends GlyphListPipe { public abstract class GlyphListLoopPipe extends GlyphListPipe
implements LoopBasedPipe
{
protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl, protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl,
int aaHint) { int aaHint) {
switch (aaHint) { switch (aaHint) {

@ -0,0 +1,37 @@
/*
* 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 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.
*/
package sun.java2d.pipe;
/**
* This is a marker interface used by Pipes that need RenderLoops.
* RenderLoops are validated in SurfaceData when a pipe is recognised to
* implement this interface.
*
* @author Mario Torre <neugens@aicas.com>
*/
public interface LoopBasedPipe {
}

@ -46,7 +46,8 @@ import sun.awt.SunHints;
public class LoopPipe public class LoopPipe
implements PixelDrawPipe, implements PixelDrawPipe,
PixelFillPipe, PixelFillPipe,
ShapeDrawPipe ShapeDrawPipe,
LoopBasedPipe
{ {
final static RenderingEngine RenderEngine = RenderingEngine.getInstance(); final static RenderingEngine RenderEngine = RenderingEngine.getInstance();

@ -35,8 +35,9 @@ import sun.font.GlyphList;
* a solid source colour to an opaque destination. * a solid source colour to an opaque destination.
*/ */
public class SolidTextRenderer extends GlyphListLoopPipe { public class SolidTextRenderer extends GlyphListLoopPipe
implements LoopBasedPipe
{
protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) { protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) {
sg2d.loops.drawGlyphListLoop.DrawGlyphList(sg2d, sg2d.surfaceData, gl); sg2d.loops.drawGlyphListLoop.DrawGlyphList(sg2d, sg2d.surfaceData, gl);
} }

@ -65,7 +65,9 @@ public abstract class SpanShapeRenderer implements ShapeDrawPipe {
} }
} }
public static class Simple extends SpanShapeRenderer { public static class Simple extends SpanShapeRenderer
implements LoopBasedPipe
{
public Object startSequence(SunGraphics2D sg, Shape s, public Object startSequence(SunGraphics2D sg, Shape s,
Rectangle devR, int[] bbox) { Rectangle devR, int[] bbox) {
return sg; return sg;

@ -775,10 +775,12 @@ public class Renderer extends LineSink {
// Free sorting arrays if larger than maximum size // Free sorting arrays if larger than maximum size
private void crossingListFinished() { private void crossingListFinished() {
if (crossings.length > DEFAULT_CROSSINGS_SIZE) { if (crossings != null && crossings.length > DEFAULT_CROSSINGS_SIZE) {
crossings = new int[DEFAULT_CROSSINGS_SIZE]; crossings = new int[DEFAULT_CROSSINGS_SIZE];
} }
if (crossingIndices.length > DEFAULT_INDICES_SIZE) { if (crossingIndices != null &&
crossingIndices.length > DEFAULT_INDICES_SIZE)
{
crossingIndices = new int[DEFAULT_INDICES_SIZE]; crossingIndices = new int[DEFAULT_INDICES_SIZE];
} }
} }

@ -1437,6 +1437,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_initJPEGImageReader
JNU_ThrowByName( env, JNU_ThrowByName( env,
"java/lang/OutOfMemoryError", "java/lang/OutOfMemoryError",
"Initializing Reader"); "Initializing Reader");
free(cinfo);
return 0; return 0;
} }
@ -1473,6 +1474,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_initJPEGImageReader
JNU_ThrowByName(env, JNU_ThrowByName(env,
"java/lang/OutOfMemoryError", "java/lang/OutOfMemoryError",
"Initializing Reader"); "Initializing Reader");
imageio_dispose((j_common_ptr)cinfo);
return 0; return 0;
} }
cinfo->src->bytes_in_buffer = 0; cinfo->src->bytes_in_buffer = 0;
@ -1489,6 +1491,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_initJPEGImageReader
JNU_ThrowByName( env, JNU_ThrowByName( env,
"java/lang/OutOfMemoryError", "java/lang/OutOfMemoryError",
"Initializing Reader"); "Initializing Reader");
imageio_dispose((j_common_ptr)cinfo);
return 0; return 0;
} }
return (jlong) ret; return (jlong) ret;
@ -2420,8 +2423,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_initJPEGImageWriter
JNU_ThrowByName( env, JNU_ThrowByName( env,
"java/lang/OutOfMemoryError", "java/lang/OutOfMemoryError",
"Initializing Writer"); "Initializing Writer");
free(cinfo); imageio_dispose((j_common_ptr)cinfo);
free(jerr);
return 0; return 0;
} }
@ -2439,8 +2441,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_initJPEGImageWriter
JNU_ThrowByName( env, JNU_ThrowByName( env,
"java/lang/OutOfMemoryError", "java/lang/OutOfMemoryError",
"Initializing Writer"); "Initializing Writer");
free(cinfo); imageio_dispose((j_common_ptr)cinfo);
free(jerr);
return 0; return 0;
} }
return (jlong) ret; return (jlong) ret;

@ -960,21 +960,15 @@ Java_sun_awt_image_ImagingLib_transformRaster(JNIEnv *env, jobject this,
mlib_filter filter; mlib_filter filter;
unsigned int *dP; unsigned int *dP;
if ((srcRasterP = (RasterS_t *) calloc(1, sizeof(RasterS_t))) == NULL) {
JNU_ThrowOutOfMemoryError(env, "Out of memory");
return -1;
}
if ((dstRasterP = (RasterS_t *) calloc(1, sizeof(RasterS_t))) == NULL) {
JNU_ThrowOutOfMemoryError(env, "Out of memory");
free(srcRasterP);
return -1;
}
/* This function requires a lot of local refs ??? Is 64 enough ??? */ /* This function requires a lot of local refs ??? Is 64 enough ??? */
if ((*env)->EnsureLocalCapacity(env, 64) < 0) if ((*env)->EnsureLocalCapacity(env, 64) < 0)
return 0; return 0;
if (s_nomlib) return 0;
if (s_timeIt) {
(*start_timer)(3600);
}
switch(interpType) { switch(interpType) {
case java_awt_image_AffineTransformOp_TYPE_BILINEAR: case java_awt_image_AffineTransformOp_TYPE_BILINEAR:
filter = MLIB_BILINEAR; filter = MLIB_BILINEAR;
@ -990,9 +984,15 @@ Java_sun_awt_image_ImagingLib_transformRaster(JNIEnv *env, jobject this,
return -1; return -1;
} }
if (s_nomlib) return 0; if ((srcRasterP = (RasterS_t *) calloc(1, sizeof(RasterS_t))) == NULL) {
if (s_timeIt) { JNU_ThrowOutOfMemoryError(env, "Out of memory");
(*start_timer)(3600); return -1;
}
if ((dstRasterP = (RasterS_t *) calloc(1, sizeof(RasterS_t))) == NULL) {
JNU_ThrowOutOfMemoryError(env, "Out of memory");
free(srcRasterP);
return -1;
} }
if ((*env)->GetArrayLength(env, jmatrix) < 6) { if ((*env)->GetArrayLength(env, jmatrix) < 6) {
@ -1215,6 +1215,9 @@ Java_sun_awt_image_ImagingLib_lookupByteBI(JNIEnv *env, jobject this,
} }
if (tbl == NULL || table == NULL || jtable == NULL) { if (tbl == NULL || table == NULL || jtable == NULL) {
if (tbl != NULL) free(tbl);
if (table != NULL) free(table);
if (jtable != NULL) free(jtable);
awt_freeParsedImage(srcImageP, TRUE); awt_freeParsedImage(srcImageP, TRUE);
awt_freeParsedImage(dstImageP, TRUE); awt_freeParsedImage(dstImageP, TRUE);
JNU_ThrowNullPointerException(env, "NULL LUT"); JNU_ThrowNullPointerException(env, "NULL LUT");
@ -1224,6 +1227,11 @@ Java_sun_awt_image_ImagingLib_lookupByteBI(JNIEnv *env, jobject this,
for (i=0; i < jlen; i++) { for (i=0; i < jlen; i++) {
jtable[i] = (*env)->GetObjectArrayElement(env, jtableArrays, i); jtable[i] = (*env)->GetObjectArrayElement(env, jtableArrays, i);
if (jtable[i] == NULL) { if (jtable[i] == NULL) {
free(tbl);
free(table);
free(jtable);
awt_freeParsedImage(srcImageP, TRUE);
awt_freeParsedImage(dstImageP, TRUE);
return 0; return 0;
} }
} }
@ -1232,6 +1240,9 @@ Java_sun_awt_image_ImagingLib_lookupByteBI(JNIEnv *env, jobject this,
FALSE, &hint); FALSE, &hint);
if (nbands < 1) { if (nbands < 1) {
/* Can't handle any custom images */ /* Can't handle any custom images */
free(tbl);
free(table);
free(jtable);
awt_freeParsedImage(srcImageP, TRUE); awt_freeParsedImage(srcImageP, TRUE);
awt_freeParsedImage(dstImageP, TRUE); awt_freeParsedImage(dstImageP, TRUE);
return 0; return 0;
@ -1240,12 +1251,18 @@ Java_sun_awt_image_ImagingLib_lookupByteBI(JNIEnv *env, jobject this,
/* Allocate the arrays */ /* Allocate the arrays */
if (allocateArray(env, srcImageP, &src, &sdata, TRUE, FALSE, FALSE) < 0) { if (allocateArray(env, srcImageP, &src, &sdata, TRUE, FALSE, FALSE) < 0) {
/* Must be some problem */ /* Must be some problem */
free(tbl);
free(table);
free(jtable);
awt_freeParsedImage(srcImageP, TRUE); awt_freeParsedImage(srcImageP, TRUE);
awt_freeParsedImage(dstImageP, TRUE); awt_freeParsedImage(dstImageP, TRUE);
return 0; return 0;
} }
if (allocateArray(env, dstImageP, &dst, &ddata, FALSE, FALSE, FALSE) < 0) { if (allocateArray(env, dstImageP, &dst, &ddata, FALSE, FALSE, FALSE) < 0) {
/* Must be some problem */ /* Must be some problem */
free(tbl);
free(table);
free(jtable);
freeArray(env, srcImageP, src, sdata, NULL, NULL, NULL); freeArray(env, srcImageP, src, sdata, NULL, NULL, NULL);
awt_freeParsedImage(srcImageP, TRUE); awt_freeParsedImage(srcImageP, TRUE);
awt_freeParsedImage(dstImageP, TRUE); awt_freeParsedImage(dstImageP, TRUE);
@ -1284,6 +1301,9 @@ Java_sun_awt_image_ImagingLib_lookupByteBI(JNIEnv *env, jobject this,
(jbyte *) table[j], (jbyte *) table[j],
JNI_ABORT); JNI_ABORT);
} }
free(tbl);
free(table);
free(jtable);
freeArray(env, srcImageP, src, sdata, NULL, NULL, NULL); freeArray(env, srcImageP, src, sdata, NULL, NULL, NULL);
awt_freeParsedImage(srcImageP, TRUE); awt_freeParsedImage(srcImageP, TRUE);
awt_freeParsedImage(dstImageP, TRUE); awt_freeParsedImage(dstImageP, TRUE);
@ -1413,12 +1433,15 @@ Java_sun_awt_image_ImagingLib_lookupByteRaster(JNIEnv *env,
/* Parse the source raster - reject custom images */ /* Parse the source raster - reject custom images */
if ((status = awt_parseRaster(env, jsrc, srcRasterP)) <= 0) { if ((status = awt_parseRaster(env, jsrc, srcRasterP)) <= 0) {
free(srcRasterP);
free(dstRasterP);
return 0; return 0;
} }
/* Parse the destination image - reject custom images */ /* Parse the destination image - reject custom images */
if ((status = awt_parseRaster(env, jdst, dstRasterP)) <= 0) { if ((status = awt_parseRaster(env, jdst, dstRasterP)) <= 0) {
awt_freeParsedRaster(srcRasterP, TRUE); awt_freeParsedRaster(srcRasterP, TRUE);
free(dstRasterP);
return 0; return 0;
} }

@ -102,9 +102,21 @@ Java_sun_font_FreetypeFontScaler_initIDs(
} }
static void freeNativeResources(JNIEnv *env, FTScalerInfo* scalerInfo) { static void freeNativeResources(JNIEnv *env, FTScalerInfo* scalerInfo) {
void *stream;
if (scalerInfo == NULL) if (scalerInfo == NULL)
return; return;
//apparently Done_Face will only close the stream
// but will not relase the memory of stream structure.
// We need to free it explicitly to avoid leak.
//Direct access to the stream field might be not ideal solution as
// it is considred to be "private".
//Alternatively we could have stored pointer to the structure
// in the scalerInfo but this will increase size of the structure
// for no good reason
stream = scalerInfo->face->stream;
FT_Done_Face(scalerInfo->face); FT_Done_Face(scalerInfo->face);
FT_Done_FreeType(scalerInfo->library); FT_Done_FreeType(scalerInfo->library);
@ -116,6 +128,10 @@ static void freeNativeResources(JNIEnv *env, FTScalerInfo* scalerInfo) {
free(scalerInfo->fontData); free(scalerInfo->fontData);
} }
if (stream != NULL) {
free(stream);
}
free(scalerInfo); free(scalerInfo);
} }

@ -388,7 +388,10 @@ public abstract class X11SurfaceData extends SurfaceData {
// if a GlyphVector overrides the AA setting. // if a GlyphVector overrides the AA setting.
// We use getRenderLoops() rather than setting solidloops // We use getRenderLoops() rather than setting solidloops
// directly so that we get the appropriate loops in XOR mode. // directly so that we get the appropriate loops in XOR mode.
if (sg2d.loops == null) {
// assert(some pipe will always be a LoopBasedPipe)
sg2d.loops = getRenderLoops(sg2d); sg2d.loops = getRenderLoops(sg2d);
}
} else { } else {
super.validatePipe(sg2d); super.validatePipe(sg2d);
} }

@ -42,6 +42,10 @@
#include <sys/ipc.h> #include <sys/ipc.h>
#include <sys/shm.h> #include <sys/shm.h>
#include <X11/extensions/XShm.h> #include <X11/extensions/XShm.h>
#ifndef X_ShmAttach
#include <X11/Xmd.h>
#include <X11/extensions/shmproto.h>
#endif
extern int XShmQueryExtension(); extern int XShmQueryExtension();

@ -210,7 +210,10 @@ public class GDIWindowSurfaceData extends SurfaceData {
// if a GlyphVector overrides the AA setting. // if a GlyphVector overrides the AA setting.
// We use getRenderLoops() rather than setting solidloops // We use getRenderLoops() rather than setting solidloops
// directly so that we get the appropriate loops in XOR mode. // directly so that we get the appropriate loops in XOR mode.
if (sg2d.loops == null) {
// assert(some pipe will always be a LoopBasedPipe)
sg2d.loops = getRenderLoops(sg2d); sg2d.loops = getRenderLoops(sg2d);
}
} else { } else {
super.validatePipe(sg2d); super.validatePipe(sg2d);
} }

@ -687,7 +687,7 @@ BOOL AwtPrintControl::InitPrintDialog(JNIEnv *env,
// Now, set-up the struct for the real calls to ::PrintDlg and ::CreateDC // Now, set-up the struct for the real calls to ::PrintDlg and ::CreateDC
pd.hwndOwner = hwndOwner; pd.hwndOwner = hwndOwner;
pd.Flags = PD_ENABLEPRINTHOOK | PD_RETURNDC; pd.Flags = PD_ENABLEPRINTHOOK | PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE;
pd.lpfnPrintHook = (LPPRINTHOOKPROC)PrintDlgHook; pd.lpfnPrintHook = (LPPRINTHOOKPROC)PrintDlgHook;
if (env->CallBooleanMethod(printCtrl, AwtPrintControl::getCollateID)) { if (env->CallBooleanMethod(printCtrl, AwtPrintControl::getCollateID)) {

@ -0,0 +1,59 @@
/*
* 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 6887494
*
* @summary Verifies that no NullPointerException is thrown in Pisces Renderer
* under certain circumstances.
*
* @run main TestNPE
*/
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
public class TestNPE {
private static void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setClip(0, 0, 0, 0);
g2d.setTransform(
new AffineTransform(4.0f, 0.0f, 0.0f, 4.0f, -1248.0f, -744.0f));
g2d.draw(new Line2D.Float(131.21428571428572f, 33.0f,
131.21428571428572f, 201.0f));
}
public static void main(String[] args) {
BufferedImage im = new BufferedImage(100, 100,
BufferedImage.TYPE_INT_ARGB);
// Trigger exception in main thread.
Graphics g = im.getGraphics();
paint(g);
}
}