/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.
*/
/**
* This is a the master Graphics2D superclass for all of the Sun
* Graphics implementations. This class relies on subclasses to
* manage the various device information, but provides an overall
* general framework for performing all of the requests in the
* Graphics and Graphics2D APIs.
*
* @author Jim Graham
*/
public final class SunGraphics2D
extends Graphics2D
{
/*
* Attribute States
*/
/* Paint */
/* Composite*/
* i.e. Src, SrcOverNoEa, and other
* alpha modes which replace
* the destination.
*/
/* Stroke */
/* Transform */
/* Clipping */
/* The following fields are used when the current Paint is a Color. */
public int paintState;
public int compositeState;
public int strokeState;
public int transformState;
public int clipState;
public int transX;
public int transY;
public int renderHint;
public int antialiasHint;
public int textAntialiasHint;
protected int fractionalMetricsHint;
/* A gamma adjustment to the colour used in lcd text blitting */
public int lcdTextContrast;
public int strokeHint;
// interpolation and render Hints
public int constrainX;
public int constrainY;
// cached state for text rendering
private boolean validFontInfo;
private final static int slowTextTransformMask =
static {
if (PerformanceLogger.loggingEnabled()) {
}
}
surfaceData = sd;
transform = new AffineTransform();
interpolationHint = -1;
if (devScale != 1) {
}
font = f;
font = defaultFont;
}
}
try {
}
/* FontInfos are re-used, so must be cloned too, if they
* are valid, and be nulled out if invalid.
* The implied trade-off is that there is more to be gained
* from re-using these objects than is lost by having to
* clone them when the SG2D is cloned.
*/
if (this.validFontInfo) {
} else {
}
}
if (this.glyphVectorFontInfo != null) {
g.glyphVectorFRC = this.glyphVectorFRC;
}
//g.invalidatePipe();
return g;
} catch (CloneNotSupportedException e) {
}
return null;
}
/**
* Create a new SunGraphics2D based on this one.
*/
}
public void setDevClip(int x, int y, int w, int h) {
Region c = constrainClip;
if (c == null) {
} else {
devClip = c.getIntersectionXYWH(x, y, w, h);
}
}
}
/**
* Constrain rendering for lightweight objects.
*/
if ((x | y) != 0) {
translate(x, y);
}
if (transformState > TRANSFORM_TRANSLATESCALE) {
return;
}
// changes parameters according to the current scale and translate.
Region c = constrainClip;
if (c == null) {
c = Region.getInstanceXYXY(x, y, w, h);
} else {
c = c.getIntersectionXYXY(x, y, w, h);
}
c = c.getIntersection(region);
}
if (c == constrainClip) {
// Common case to ignore
return;
}
constrainClip = c;
if (!devClip.isInsideQuickCheck(c)) {
}
}
/**
* Constrain rendering for lightweight objects.
*
* REMIND: This method will back off to the "workaround"
* of using translate and clipRect if the Graphics
* to be constrained has a complex transform. The
* drawback of the workaround is that the resulting
* clip and device origin cannot be "enforced".
*
* @exception IllegalStateException If the Graphics
* to be constrained has a complex transform.
*/
public void constrain(int x, int y, int w, int h) {
}
/*
* Invalidate the pipeline
*/
protected void invalidatePipe() {
}
public void validatePipe() {
/* This workaround is for the situation when we update the Pipelines
* for invalid SurfaceData and run further code when the current
* pipeline doesn't support the type of new SurfaceData created during
* the current pipeline's work (in place of the invalid SurfaceData).
* Usually SurfaceData and Pipelines are repaired (through revalidateAll)
* and called again in the exception handlers */
if (!surfaceData.isValid()) {
throw new InvalidPipeException("attempt to validate Pipe with invalid SurfaceData");
}
surfaceData.validatePipe(this);
}
/*
* Intersect two Shapes by the simplest method, attempting to produce
* a simplified result.
* The boolean arguments keep1 and keep2 specify whether or not
* the first or second shapes can be modified during the operation
* or whether that shape must be "kept" unmodified.
*/
}
if (s1 instanceof Rectangle2D) {
} else if (s2 instanceof Rectangle2D) {
}
}
/*
* Intersect a Rectangle with a Shape by the simplest method,
* attempting to produce a simplified result.
* The boolean arguments keep1 and keep2 specify whether or not
* the first or second shapes can be modified during the operation
* or whether that shape must be "kept" unmodified.
*/
if (s instanceof Rectangle2D) {
if (!keep1) {
outrect = r;
} else if (!keep2) {
} else {
}
// Width or height is negative. No intersection.
else
return outrect;
}
if (r.contains(s.getBounds2D())) {
if (keep2) {
s = cloneShape(s);
}
return s;
}
}
return new GeneralPath(s);
}
/*
* Intersect two Shapes using the Area class. Presumably other
* attempts at simpler intersection methods proved fruitless.
* The boolean arguments keep1 and keep2 specify whether or not
* the first or second shapes can be modified during the operation
* or whether that shape must be "kept" unmodified.
* @see #intersectShapes
* @see #intersectRectShape
*/
// First see if we can find an overwriteable source shape
// to use as our destination area to avoid duplication.
} else {
}
} else {
}
if (a1.isRectangular()) {
}
return a1;
}
/*
* Intersect usrClip bounds and device bounds to determine the composite
* rendering boundaries.
*/
if (!surfaceData.isValid()) {
// revalidateAll() implicitly recalculcates the composite clip
}
return clipRegion;
}
font = defaultFont;
}
return font;
}
new AffineTransform();
new AffineTransform[TEXTARRSIZE];
static {
for (int i=MINALLOCATED;i<TEXTARRSIZE;i++) {
}
}
// cached state for various draw[String,Char,Byte] optimizations
/* Do not create a FontInfo object as part of construction of an
* SG2D as its possible it may never be needed - ie if no text
* is drawn using this SG2D.
*/
}
int txFontType;
if (font.isTransformed()) {
if (transformState >= TRANSFORM_TRANSLATESCALE) {
} else {
}
if (shearx != 0) {
}
} else {
if (transformState >= TRANSFORM_TRANSLATESCALE) {
for (int i = 0; i < 4; i++) {
}
if (shearx != 0) {
}
} else {
/* If the double represents a common integral, we
* may have pre-allocated objects.
* A "sparse" array be seems to be as fast as a switch
* even for 3 or 4 pt sizes, and is more flexible.
* This should perform comparably in single-threaded
* rendering to the old code which synchronized on the
* class and scale better on MP systems.
*/
} else {
}
}
}
}
int fmhint = fractionalMetricsHint;
}
/* The text anti-aliasing hints that are set by the client need
* to be interpreted for the current state and stored in the
* FontInfo.aahint which is what will actually be used and
* will be one of OFF, ON, LCD_HRGB or LCD_VRGB.
* This is what pipe selection code should typically refer to, not
* textAntialiasHint. This means we are now evaluating the meaning
* of "default" here. Any pipe that really cares about that will
* also need to consult that variable.
* Otherwise these are being used only as args to getStrike,
* and are encapsulated in that object which is part of the
* FontInfo, so we do not need to store them directly as fields
* in the FontInfo object.
* That could change if FontInfo's were more selectively
* revalidated when graphics state changed. Presently this
* method re-evaluates all fields in the fontInfo.
* The strike doesn't need to know the RGB subpixel order. Just
* if its H or V orientation, so if an LCD option is specified we
* always pass in the RGB hint to the strike.
* frc is non-null only if this is a GlyphVector. For reasons
* which are probably a historical mistake the AA hint in a GV
* is honoured when we render, overriding the Graphics setting.
*/
int aahint;
} else {
}
} else {
}
} else {
/* If we are in checkFontInfo because a rendering hint has been
* set then all pipes are revalidated. But we can also
* be here because setFont() has been called when the 'gasp'
* hint is set, as then the font size determines the text pipe.
* See comments in SunGraphics2d.setFont(Font).
*/
} else {
}
/* loops for default rendering modes are installed in the SG2D
* constructor. If there are none this will be null.
* Not all compositing modes update the render loops, so
* we also test that this is a mode we know should support
* this. One minor issue is that the loops aren't necessarily
* installed for a new rendering mode until after this
* method is called during pipeline validation. So it is
* theoretically possible that it was set to null for a
* compositing mode, the composite is then set back to Src,
* but the loop is still null when this is called and AA=ON
* is installed instead of an LCD mode.
* However this is done in the right order in SurfaceData.java
* so this is not likely to be a problem - but not
* guaranteed.
*/
if (
!surfaceData.canRenderLCDText(this)
// loops.drawGlyphListLCDLoop == null ||
// compositeState > COMP_ISCOPY ||
// paintState > PAINT_ALPHACOLOR
) {
} else {
info.lcdRGBOrder = true;
/* Collapse these into just HRGB or VRGB.
* Pipe selection code needs only to test for these two.
* Since these both select the same pipe anyway its
* tempting to collapse into one value. But they are
* different strikes (glyph caches) so the distinction
* needs to be made for that purpose.
*/
info.lcdRGBOrder = false;
} else if
info.lcdRGBOrder = false;
}
/* Support subpixel positioning only for the case in
* which the horizontal resolution is increased
*/
}
}
}
return info;
}
{
return false;
}
return true;
}
/* replacing the reference equality test font != this.font with
* !font.equals(this.font) did not yield any measurable difference
* in testing, but there may be yet to be identified cases where it
* is beneficial.
*/
/* In the GASP AA case the textpipe depends on the glyph size
* as determined by graphics and font transforms as well as the
* font size, and information in the font. But we may invalidate
* the pipe only to find that it made no difference.
* Deferring pipe invalidation to checkFontInfo won't work because
* when called we may already be rendering to the wrong pipe.
* So, if the font is transformed, or the graphics has more than
* a simple scale, we'll take that as enough of a hint to
* revalidate everything. But if they aren't we will
* use the font's point size to query the gasp table and see if
* what it says matches what's currently being used, in which
* case there's no need to invalidate the textpipe.
* This should be sufficient for all typical uses cases.
*/
textpipe != invalidpipe &&
font.isTransformed() ||
}
this.fontMetrics = null;
this.validFontInfo = false;
}
}
if (!validFontInfo) {
validFontInfo = true;
}
return this.fontInfo;
}
/* Used by drawGlyphVector which specifies its own font. */
if (glyphVectorFontInfo != null &&
glyphVectorFRC == frc) {
return glyphVectorFontInfo;
} else {
return glyphVectorFontInfo =
}
}
if (this.fontMetrics != null) {
return this.fontMetrics;
}
/* NB the constructor and the setter disallow "font" being null */
return this.fontMetrics =
}
return this.fontMetrics;
}
this.fontMetrics = fm;
}
return fm;
}
/**
* Checks to see if a Path intersects the specified Rectangle in device
* space. The rendering attributes taken into account include the
* clip, transform, and stroke attributes.
* @param rect The area in device space to check for a hit.
* @param p The path to check for a hit.
* @param onStroke Flag to choose between testing the stroked or
* the filled path.
* @return True if there is a hit, false otherwise.
* @see #setStroke
* @see #fillPath
* @see #drawPath
* @see #transform
* @see #setTransform
* @see #clip
* @see #setClip
*/
if (onStroke) {
s = stroke.createStrokedShape(s);
}
s = transformShape(s);
}
return s.intersects(rect);
}
/**
* Return the ColorModel associated with this Graphics2D.
*/
return surfaceData.getColorModel();
}
/**
* Return the device configuration associated with this Graphics2D.
*/
return surfaceData.getDeviceConfiguration();
}
/**
* Return the SurfaceData object assigned to manage the destination
* drawable surface of this Graphics2D.
*/
return surfaceData;
}
/**
* Sets the Composite in the current graphics state. Composite is used
* in all drawing methods such as drawImage, drawString, drawPath,
* and fillPath. It specifies how new pixels are to be combined with
* the existing pixels on the graphics device in the rendering process.
* @param comp The Composite object to be used for drawing.
* @see java.awt.Graphics#setXORMode
* @see java.awt.Graphics#setPaintMode
* @see AlphaComposite
*/
return;
}
int newCompState;
if (comp instanceof AlphaComposite) {
if (paintState == PAINT_OPAQUECOLOR ||
(paintState > PAINT_ALPHACOLOR &&
{
} else {
}
{
{
} else {
}
} else if (comp instanceof XORComposite) {
throw new IllegalArgumentException("null Composite");
} else {
}
if (compositeState != newCompState ||
imageComp != newCompType)
{
validFontInfo = false;
}
if (paintState <= PAINT_ALPHACOLOR) {
}
}
/**
* Sets the Paint in the current graphics state.
* @param paint The Paint object to be used to generate color in
* the rendering process.
* @see java.awt.Graphics#setColor
* @see GradientPaint
* @see TexturePaint
*/
return;
}
return;
}
// special case where compState depends on opacity of paint
if (compositeState != COMP_ISCOPY) {
}
} else {
if (compositeState == COMP_ISCOPY) {
}
}
}
if (paintClass == GradientPaint.class) {
} else if (paintClass == LinearGradientPaint.class) {
} else if (paintClass == RadialGradientPaint.class) {
} else if (paintClass == TexturePaint.class) {
} else {
}
validFontInfo = false;
}
static final int NON_UNIFORM_SCALE_MASK =
public static final double MinPenSizeAA =
public static final double MinPenSizeAASquared =
(MinPenSizeAA * MinPenSizeAA);
// Since inaccuracies in the trig package can cause us to
// calculated a rotated pen width of just slightly greater
// than 1.0, we add a fudge factor to our comparison value
// here so that we do not misclassify single width lines as
// wide lines under certain rotations.
if (transformState < TRANSFORM_TRANSLATESCALE) {
if (aa) {
} else {
}
} else {
}
} else {
if (bs == defaultStroke) {
} else {
}
} else {
}
}
} else {
double widthsquared;
/* sqrt omitted, compare to squared limits below. */
} else {
/* First calculate the "maximum scale" of this transform. */
/*
* Given a 2 x 2 affine matrix [ A B ] such that
* [ C D ]
* v' = [x' y'] = [Ax + Cy, Bx + Dy], we want to
* find the maximum magnitude (norm) of the vector v'
* with the constraint (x^2 + y^2 = 1).
* The equation to maximize is
* |v'| = sqrt((Ax+Cy)^2+(Bx+Dy)^2)
* or |v'| = sqrt((AA+BB)x^2 + 2(AC+BD)xy + (CC+DD)y^2).
* Since sqrt is monotonic we can maximize |v'|^2
* instead and plug in the substitution y = sqrt(1 - x^2).
* Trigonometric equalities can then be used to get
* rid of most of the sqrt terms.
*/
double EA = A*A + B*B; // x^2 coefficient
double EC = C*C + D*D; // y^2 coefficient
/*
* There is a lot of calculus omitted here.
*
* Conceptually, in the interests of understanding the
* terms that the calculus produced we can consider
* that EA and EC end up providing the lengths along
* the major axes and the hypot term ends up being an
* adjustment for the additional length along the off-axis
* angle of rotated or sheared ellipses as well as an
* adjustment for the fact that the equation below
* averages the two major axis lengths. (Notice that
* the hypot term contains a part which resolves to the
* difference of these two axis lengths in the absence
* of rotation.)
*
* In the calculus, the ratio of the EB and (EA-EC) terms
* ends up being the tangent of 2*theta where theta is
* the angle that the long axis of the ellipse makes
* with the horizontal axis. Thus, this equation is
* calculating the length of the hypotenuse of a triangle
* along that axis.
*/
/* sqrt omitted, compare to squared limits below. */
}
if (bs != defaultStroke) {
}
if (widthsquared <=
{
} else {
}
} else {
}
}
}
/*
* Sets the Stroke in the current graphics state.
* @param s The Stroke object to be used to stroke a Path in
* the rendering process.
* @see BasicStroke
*/
if (s == null) {
throw new IllegalArgumentException("null Stroke");
}
int saveStrokeState = strokeState;
stroke = s;
if (s instanceof BasicStroke) {
} else {
}
if (strokeState != saveStrokeState) {
}
}
/**
* Sets the preferences for the rendering algorithms.
* Hint categories include controls for rendering quality and
* @param hintKey The key of hint to be set. The strings are
* defined in the RenderingHints class.
* @param hintValue The value indicating preferences for the specified
* hint category. These strings are defined in the RenderingHints
* class.
* @see RenderingHints
*/
// If we recognize the key, we must recognize the value
// otherwise throw an IllegalArgumentException
// and do not change the Hints object
// If we do not recognize the key, just pass it through
// to the Hints object untouched
throw new IllegalArgumentException
}
boolean stateChanged;
boolean textStateChanged = false;
boolean recognized = true;
int newHint;
} else {
}
case SunHints.INTKEY_RENDERING:
if (stateChanged) {
if (interpolationHint == -1) {
}
}
break;
case SunHints.INTKEY_ANTIALIASING:
if (stateChanged) {
if (strokeState != STROKE_CUSTOM) {
}
}
break;
break;
break;
stateChanged = false;
/* Already have validated it is an int 100 <= newHint <= 250 */
break;
case SunHints.INTKEY_INTERPOLATION:
switch (newHint) {
break;
break;
default:
break;
}
break;
break;
default:
recognized = false;
stateChanged = false;
break;
}
if (recognized) {
if (stateChanged) {
if (textStateChanged) {
fontMetrics = null;
validFontInfo = false;
this.glyphVectorFontInfo = null;
}
}
}
return;
}
}
// Nothing we recognize so none of "our state" has changed
}
}
/**
* Returns the preferences for the rendering algorithms.
* @param hintCategory The category of hint to be set. The strings
* are defined in the RenderingHints class.
* @return The preferences for rendering algorithms. The strings
* are defined in the RenderingHints class.
* @see RenderingHints
*/
}
return null;
}
switch (keyindex) {
case SunHints.INTKEY_RENDERING:
case SunHints.INTKEY_ANTIALIASING:
return new Integer(lcdTextContrast);
case SunHints.INTKEY_INTERPOLATION:
switch (interpolationHint) {
return SunHints.VALUE_INTERPOLATION_BILINEAR;
return SunHints.VALUE_INTERPOLATION_BICUBIC;
}
return null;
}
return null;
}
/**
* Sets the preferences for the rendering algorithms.
* Hint categories include controls for rendering quality and
* @param hints The rendering hints to be set
* @see RenderingHints
*/
interpolationHint = -1;
boolean customHintPresent = false;
{
} else {
customHintPresent = true;
}
}
if (customHintPresent) {
}
}
/**
* Adds a number of preferences for the rendering algorithms.
* Hint categories include controls for rendering quality and
* @param hints The rendering hints to be set
* @see RenderingHints
*/
boolean customHintPresent = false;
{
} else {
customHintPresent = true;
}
}
if (customHintPresent) {
} else {
}
}
}
/**
* Gets the preferences for the rendering algorithms.
* Hint categories include controls for rendering quality and
* @see RenderingHints
*/
} else {
}
}
renderHint));
switch (interpolationHint) {
break;
break;
break;
default:
break;
}
}
strokeHint));
return model;
}
/**
* Concatenates the current transform of this Graphics2D with a
* translation transformation.
* This is equivalent to calling transform(T), where T is an
* AffineTransform represented by the following matrix:
* <pre>
* [ 1 0 tx ]
* [ 0 1 ty ]
* [ 0 0 1 ]
* </pre>
*/
}
/**
* Concatenates the current transform of this Graphics2D with a
* rotation transformation.
* This is equivalent to calling transform(R), where R is an
* AffineTransform represented by the following matrix:
* <pre>
* [ cos(theta) -sin(theta) 0 ]
* [ sin(theta) cos(theta) 0 ]
* [ 0 0 1 ]
* </pre>
* Rotating with a positive angle theta rotates points on the positive
* x axis toward the positive y axis.
* @param theta The angle of rotation in radians.
*/
}
/**
* Concatenates the current transform of this Graphics2D with a
* translated rotation transformation.
* This is equivalent to the following sequence of calls:
* <pre>
* translate(x, y);
* rotate(theta);
* translate(-x, -y);
* </pre>
* Rotating with a positive angle theta rotates points on the positive
* x axis toward the positive y axis.
* @param theta The angle of rotation in radians.
* @param x The x coordinate of the origin of the rotation
* @param y The x coordinate of the origin of the rotation
*/
}
/**
* Concatenates the current transform of this Graphics2D with a
* scaling transformation.
* This is equivalent to calling transform(S), where S is an
* AffineTransform represented by the following matrix:
* <pre>
* [ sx 0 0 ]
* [ 0 sy 0 ]
* [ 0 0 1 ]
* </pre>
*/
}
/**
* Concatenates the current transform of this Graphics2D with a
* shearing transformation.
* This is equivalent to calling transform(SH), where SH is an
* AffineTransform represented by the following matrix:
* <pre>
* [ 1 shx 0 ]
* [ shy 1 0 ]
* [ 0 0 1 ]
* </pre>
* @param shx The factor by which coordinates are shifted towards the
* positive X axis direction according to their Y coordinate
* @param shy The factor by which coordinates are shifted towards the
* positive Y axis direction according to their X coordinate
*/
}
/**
* Composes a Transform object with the transform in this
* Graphics2D according to the rule last-specified-first-applied.
* If the currrent transform is Cx, the result of composition
* with Tx is a new transform Cx'. Cx' becomes the current
* transform for this Graphics2D.
* Transforming a point p by the updated transform Cx' is
* equivalent to first transforming p by Tx and then transforming
* the result by the original transform Cx. In other words,
* Cx'(p) = Cx(Tx(p)).
* A copy of the Tx is made, if necessary, so further
* modifications to Tx do not affect rendering.
* @param Tx The Transform object to be composed with the current
* transform.
* @see #setTransform
* @see AffineTransform
*/
}
/**
* Translate
*/
public void translate(int x, int y) {
if (transformState <= TRANSFORM_INT_TRANSLATE) {
transX += x;
transY += y;
} else {
}
}
/**
* Sets the Transform in the current graphics state.
* @param Tx The Transform object to be used in the rendering process.
* @see #transform
* @see TransformChain
* @see AffineTransform
*/
} else {
}
}
protected void invalidateTransform() {
int origTransformState = transformState;
} else {
}
{
} else {
}
if (transformState >= TRANSFORM_TRANSLATESCALE ||
{
/* Its only in this case that the previous or current transform
* was more than a translate that font info is invalidated
*/
this.validFontInfo = false;
this.fontMetrics = null;
this.glyphVectorFontInfo = null;
if (transformState != origTransformState) {
}
}
if (strokeState != STROKE_CUSTOM) {
}
}
/**
* Returns the current Transform in the Graphics2D state.
* @see #transform
* @see #setTransform
*/
return new AffineTransform(transform);
}
-constrainX * invScale,
-constrainY * invScale);
return tx;
}
/**
* Returns the current Transform ignoring the "constrain"
* rectangle.
*/
return new AffineTransform(transform);
}
/**
* Returns the current Paint in the Graphics2D state.
* @see #setPaint
* @see java.awt.Graphics#setColor
*/
return paint;
}
/**
* Returns the current Composite in the Graphics2D state.
* @see #setComposite
*/
return composite;
}
return foregroundColor;
}
/*
* Validate the eargb and pixel fields against the current color.
*
* The eargb field must take into account the extraAlpha
* value of an AlphaComposite. It may also take into account
* the Fsrc Porter-Duff blending function if such a function is
* a constant (see handling of Clear mode below). For instance,
* by factoring in the (Fsrc == 0) state of the Clear mode we can
* use a SrcNoEa loop just as easily as a general Alpha loop
* since the math will be the same in both cases.
*
* The pixel field will always be the best pixel data choice for
* the final result of all calculations applied to the eargb field.
*
* Note that this method is only necessary under the following
* conditions:
* (paintState <= PAINT_ALPHA_COLOR &&
* compositeState <= COMP_CUSTOM)
* though nothing bad will happen if it is run in other states.
*/
final void validateColor() {
int eargb;
eargb = 0;
} else {
if (compositeState <= COMP_ALPHA &&
{
}
}
}
return;
}
if (paintState == PAINT_OPAQUECOLOR) {
return;
}
// special case where compState depends on opacity of paint
}
} else {
if (paintState == PAINT_ALPHACOLOR) {
return;
}
// special case where compState depends on opacity of paint
}
}
validFontInfo = false;
}
/**
* Sets the background color in this context used for clearing a region.
* When Graphics2D is constructed for a component, the backgroung color is
* inherited from the component. Setting the background color in the
* Graphics2D context only affects the subsequent clearRect() calls and
* not the background color of the component. To change the background
* of the component, use appropriate methods of the component.
* @param color The background color that should be used in
* subsequent calls to clearRect().
* @see getBackground
* @see Graphics.clearRect()
*/
}
/**
* Returns the background color used for clearing a region.
* @see setBackground
*/
return backgroundColor;
}
/**
* Returns the current Stroke in the Graphics2D state.
* @see setStroke
*/
return stroke;
}
Rectangle r;
if (clipState == CLIP_DEVICE) {
r = null;
} else if (transformState <= TRANSFORM_INT_TRANSLATE) {
} else {
}
} else {
}
return r;
}
if (clipState != CLIP_DEVICE) {
if (transformState <= TRANSFORM_INT_TRANSLATE) {
} else {
}
} else {
}
} else if (r == null) {
throw new NullPointerException("null rectangle parameter");
}
return r;
}
return false;
}
if (transformState > TRANSFORM_INT_TRANSLATE) {
// Note: Technically the most accurate test would be to
// raster scan the parallelogram of the transformed rectangle
// and do a span for span hit test against the clip, but for
// speed we approximate the test with a bounding box of the
// transformed rectangle. The cost of rasterizing the
// transformed rectangle is probably high enough that it is
// not worth doing so to save the caller from having to call
// a rendering method where we will end up discovering the
// same answer in about the same amount of time anyway.
// This logic breaks down if this hit test is being performed
// on the bounds of a group of shapes in which case it might
// be beneficial to be a little more accurate to avoid lots
// of subsequent rendering calls. In either case, this relaxed
// test should not be significantly less accurate than the
// optimal test for most transforms and so the conservative
// answer should not cause too much extra work.
double d[] = {
x, y,
x+width, y,
x, y+height,
};
} else {
x += transX;
y += transY;
width += x;
height += y;
}
try {
return false;
}
} catch (InvalidPipeException e) {
return false;
}
// REMIND: We could go one step further here and examine the
// non-rectangular clip shape more closely if there is one.
// Since the clip has already been rasterized, the performance
// penalty of doing the scan is probably still within the bounds
// of a good tradeoff between speed and quality of the answer.
return true;
}
protected void validateCompClip() {
int origClipState = clipState;
} else if (usrClip instanceof Rectangle2D) {
} else {
}
} else {
int box[] = new int[4];
try {
r.appendSpans(sr);
clipRegion = r;
} finally {
}
}
if (origClipState != clipState &&
{
validFontInfo = false;
}
}
static final int NON_RECTILINEAR_TRANSFORM_MASK =
if (s == null) {
return null;
}
if (transformState > TRANSFORM_INT_TRANSLATE) {
return transformShape(transform, s);
} else {
}
}
if (s == null) {
return null;
}
if (transformState > TRANSFORM_INT_TRANSLATE) {
try {
} catch (NoninvertibleTransformException e) {
return null;
}
} else {
}
}
if (s == null) {
return null;
}
if (s instanceof Rectangle) {
return r;
}
if (s instanceof Rectangle2D) {
}
return cloneShape(s);
}
return mat.createTransformedShape(s);
}
return null;
}
if (clip instanceof Rectangle2D &&
{
double matrix[] = new double[4];
return rect;
}
if (tx.isIdentity()) {
return cloneShape(clip);
}
}
public void clipRect(int x, int y, int w, int h) {
}
public void setClip(int x, int y, int w, int h) {
}
return untransformShape(usrClip);
}
}
/**
* Intersects the current clip with the specified Path and sets the
* current clip to the resulting intersection. The clip is transformed
* with the current transform in the Graphics2D state before being
* intersected with the current clip. This method is used to make the
* current clip smaller. To make the clip larger, use any setClip method.
* @param p The Path to be intersected with the current clip.
*/
s = transformShape(s);
s = intersectShapes(usrClip, s, true, true);
}
usrClip = s;
}
public void setPaintMode() {
}
if (c == null) {
throw new IllegalArgumentException("null XORColor");
}
}
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
if (w <= 0 || h <= 0) {
return;
}
return;
}
if (transformState >= TRANSFORM_TRANSLATESCALE) {
throw new InternalError("transformed copyArea not implemented yet");
}
// REMIND: This method does not deal with missing data from the
// source object (i.e. it does not send exposure events...)
if (lastCAcomp != comp) {
{
}
lastCAcomp = comp;
}
x += transX;
y += transY;
while (w > 0) {
w -= partW;
int sx = x + w;
}
return;
}
while (h > 0) {
h -= partH;
int sy = y + h;
}
return;
}
}
/*
public void XcopyArea(int x, int y, int w, int h, int dx, int dy) {
Rectangle rect = new Rectangle(x, y, w, h);
rect = transformBounds(rect, transform);
Point2D point = new Point2D.Float(dx, dy);
Point2D root = new Point2D.Float(0, 0);
point = transform.transform(point, point);
root = transform.transform(root, root);
int fdx = (int)(point.getX()-root.getX());
int fdy = (int)(point.getY()-root.getY());
Rectangle r = getCompBounds().intersection(rect.getBounds());
if (r.isEmpty()) {
return;
}
// Begin Rasterizer for Clip Shape
boolean skipClip = true;
byte[] clipAlpha = null;
if (clipState == CLIP_SHAPE) {
int box[] = new int[4];
clipRegion.getBounds(box);
Rectangle devR = new Rectangle(box[0], box[1],
box[2] - box[0],
box[3] - box[1]);
if (!devR.isEmpty()) {
OutputManager mgr = getOutputManager();
RegionIterator ri = clipRegion.getIterator();
while (ri.nextYRange(box)) {
int spany = box[1];
int spanh = box[3] - spany;
while (ri.nextXBand(box)) {
int spanx = box[0];
int spanw = box[2] - spanx;
mgr.copyArea(this, null,
spanw, 0,
spanx, spany,
spanw, spanh,
fdx, fdy,
null);
}
}
}
return;
}
// End Rasterizer for Clip Shape
getOutputManager().copyArea(this, null,
r.width, 0,
r.x, r.y, r.width,
r.height, fdx, fdy,
null);
}
*/
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
public void drawOval(int x, int y, int w, int h) {
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
public void fillOval(int x, int y, int w, int h) {
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
public void drawArc(int x, int y, int w, int h,
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
public void fillArc(int x, int y, int w, int h,
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
public void drawRect (int x, int y, int w, int h) {
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
public void fillRect (int x, int y, int w, int h) {
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
private void revalidateAll() {
try {
// REMIND: This locking needs to be done around the
// caller of this method so that the pipe stays valid
// long enough to call the new primitive.
// REMIND: No locking yet in screen SurfaceData objects!
// surfaceData.lock();
if (surfaceData == null) {
}
// this will recalculate the composite clip
if (paintState <= PAINT_ALPHACOLOR) {
}
if (composite instanceof XORComposite) {
}
validatePipe();
} finally {
// REMIND: No locking yet in screen SurfaceData objects!
// surfaceData.unlock();
}
}
public void clearRect(int x, int y, int w, int h) {
// REMIND: has some "interesting" consequences if threads are
// not synchronized
fillRect(x, y, w, h);
setPaint(p);
setComposite(c);
}
/**
* Strokes the outline of a Path using the settings of the current
* graphics state. The rendering attributes applied include the
* clip, transform, paint or color, composite and stroke attributes.
* @param p The path to be drawn.
* @see #setStroke
* @see #setPaint
* @see java.awt.Graphics#setColor
* @see #transform
* @see #setTransform
* @see #clip
* @see #setClip
* @see #setComposite
*/
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
/**
* Fills the interior of a Path using the settings of the current
* graphics state. The rendering attributes applied include the
* clip, transform, paint or color, and composite.
* @see #setPaint
* @see java.awt.Graphics#setColor
* @see #transform
* @see #setTransform
* @see #setComposite
* @see #clip
* @see #setClip
*/
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
/**
* Returns true if the given AffineTransform is an integer
* translation.
*/
if (xform.isIdentity()) {
return true;
}
}
return false;
}
/**
* Returns the index of the tile corresponding to the supplied position
* given the tile grid offset and size along the same axis.
*/
p -= tileGridOffset;
if (p < 0) {
}
return p/tileSize;
}
/**
* Returns a rectangle in image coordinates that may be required
* in order to draw the given image into the given clipping region
* through a pair of AffineTransforms. In addition, horizontal and
* vertical padding factors for antialising and interpolation may
* be used.
*/
try {
double p[] = new double[8];
// Inverse transform the output bounding rect
// Determine a bounding box for the inverse transformed region
for (int i = 2; i < 8; ) {
double pt = p[i++];
}
pt = p[i++];
}
}
// This is padding for anti-aliasing and such. It may
// be more than is needed.
} catch (NoninvertibleTransformException nte) {
// Worst case bounds are the bounds of the image.
}
return result;
}
/**
* Draws an image, applying a transform from image space into user space
* before drawing.
* The transformation from user space into device space is done with
* the current transform in the Graphics2D.
* The given transformation is applied to the image before the
* transform attribute in the Graphics2D state is applied.
* The rendering attributes applied include the clip, transform,
* and composite attributes. Note that the result is
* undefined, if the given transform is noninvertible.
* @param img The image to be drawn. Does nothing if img is null.
* @param xform The transformation from image space into user space.
* @see #transform
* @see #setTransform
* @see #setComposite
* @see #clip
* @see #setClip
*/
return;
}
// BufferedImage case: use a simple drawImage call
if (img instanceof BufferedImage) {
return;
}
// transformState tracks the state of transform and
// transX, transY contain the integer casts of the
// translation factors
boolean isIntegerTranslate =
// Include padding for interpolation/antialiasing if necessary
try {
clip = getCompClip();
} catch (InvalidPipeException e) {
return;
}
// Determine the region of the image that may contribute to
// the clipped drawing area
clip,
return;
}
// Attempt to optimize integer translation of tiled images.
// Although theoretically we are O.K. if the concatenation of
// the user transform and the device transform is an integer
// translation, we'll play it safe and only optimize the case
// where both are integer translations.
if (isIntegerTranslate) {
// Use optimized code
// Note that drawTranslatedRenderedImage calls copyImage
// which takes the user space to device space transform into
// account, but we need to provide the image space to user space
// translations.
(int) xform.getTranslateX(),
(int) xform.getTranslateY());
return;
}
// General case: cobble the necessary region into a single Raster
// Make a new Raster with the same contents as raster
// but starting at (0, 0). This raster is thus in the same
// coordinate system as the SampleModel of the original raster.
null);
// If the original raster was in a different coordinate
// system than its SampleModel, we need to perform an
// additional translation in order to get the (minX, minY)
// pixel of raster to be pixel (0, 0) of wRaster. We also
// have to have the correct width and height.
wRaster =
py,
0, 0,
null);
}
// Now we have a BufferedImage starting at (0, 0)
// with the same contents that started at (minX, minY)
// in raster. So we must draw the BufferedImage with a
// translation of (minX, minY).
null);
}
/**
* Intersects <code>destRect</code> with <code>clip</code> and
* overwrites <code>destRect</code> with the result.
* Returns false if the intersection was empty, true otherwise.
*/
return false;
} else {
return true;
}
}
/**
* Draw a portion of a RenderedImage tile-by-tile with a given
* integer image to user space translation. The user to
* device transform must also be an integer translation.
*/
int i2uTransX,
int i2uTransY) {
// Cache tile grid info
// Determine the tile index extrema in each direction
int minTileX =
int minTileY =
int maxTileX =
int maxTileY =
// Create a single ColorModel to use for all BufferedImages
// Reuse the same Rectangle for each iteration
// Get the current tile.
// Fill in tileRect with the tile bounds
// Clip the tile against the image bounds and
// backwards mapped clip region
// The result can't be empty
// Create a WritableRaster containing the tile
if (raster instanceof WritableRaster) {
} else {
// Create a WritableRaster in the same coordinate system
// as the original raster.
wRaster =
null);
}
// Translate wRaster to start at (0, 0) and to contain
// only the relevent portion of the tile
0, 0,
null);
// Wrap wRaster in a BufferedImage
new BufferedImage(colorModel,
null);
// Now we have a BufferedImage starting at (0, 0) that
// represents data from a Raster starting at
// (tileRect.x, tileRect.y). Additionally, it needs
// to be translated by (i2uTransX, i2uTransY). We call
// copyImage to draw just the region of interest
// without needing to create a child image.
}
}
}
return;
}
try {
} catch (NoninvertibleTransformException nte) {
reverseTransform = new AffineTransform();
}
}
/*
* Transform the bounding box of the BufferedImage
*/
if (tx.isIdentity()) {
return rect;
}
return s.getBounds();
}
// text rendering methods
throw new NullPointerException("String is null");
}
if (font.hasLayoutAttributes()) {
return;
}
return;
}
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
throw new NullPointerException("String is null");
}
if (font.hasLayoutAttributes()) {
return;
}
return;
}
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
int x, int y) {
throw new NullPointerException("AttributedCharacterIterator is null");
}
return; /* nothing to draw */
}
}
float x, float y) {
throw new NullPointerException("AttributedCharacterIterator is null");
}
return; /* nothing to draw */
}
}
{
throw new NullPointerException("GlyphVector is null");
}
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
throw new NullPointerException("char data is null");
}
throw new ArrayIndexOutOfBoundsException("bad offset/length");
}
if (font.hasLayoutAttributes()) {
return;
}
return;
}
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
throw new NullPointerException("byte data is null");
}
throw new ArrayIndexOutOfBoundsException("bad offset/length");
}
/* Byte data is interpreted as 8-bit ASCII. Re-use drawChars loops */
for (int i = length; i-- > 0; ) {
}
if (font.hasLayoutAttributes()) {
return;
}
return;
}
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
// end of text rendering methods
}
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
return false;
}
} finally {
}
}
/**
* Draws an image scaled to x,y,w,h in nonblocking mode with a
* callback object.
*/
}
/**
* Not part of the advertised API but a useful utility method
* to call internally. This is for the case where we are
* areas are equal (no scale needed). Note that this method intentionally
* ignore scale factor of the source image, and copy it as is.
*/
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
return false;
}
} finally {
}
}
/**
* Draws an image scaled to x,y,w,h in nonblocking mode with a
* solid background color and a callback object.
*/
return true;
}
return true;
}
if (isHiDPIImage(img)) {
}
}
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
return false;
}
} finally {
}
}
/**
* Draws an image at x,y in nonblocking mode.
*/
}
/**
* Draws an image at x,y in nonblocking mode with a solid background
* color and a callback object.
*/
return true;
}
if (isHiDPIImage(img)) {
}
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
return false;
}
} finally {
}
}
/**
* Draws a subrectangle of an image scaled to a destination rectangle
* in nonblocking mode with a callback object.
*/
observer);
}
/**
* Draws a subrectangle of an image scaled to a destination rectangle in
* nonblocking mode with a solid background color and a callback object.
*/
return true;
}
{
return true;
}
if (isHiDPIImage(img)) {
}
{
// Not a scale - forward it to a copy routine
} else {
}
} else {
}
}
try {
observer);
} catch (InvalidPipeException e) {
try {
observer);
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
return false;
}
} finally {
}
}
/**
* Draw an image, applying a transform from image space into user space
* before drawing.
* The transformation from user space into device space is done with
* the current transform in the Graphics2D.
* The given transformation is applied to the image before the
* transform attribute in the Graphics2D state is applied.
* The rendering attributes applied include the clip, transform,
* paint or color and composite attributes. Note that the result is
* undefined, if the given transform is non-invertible.
* @param img The image to be drawn.
* @param xform The transformation from image space into user space.
* @param observer The image observer to be notified on the image producing
* progress.
* @see #transform
* @see #setComposite
* @see #setClip
*/
return true;
}
}
if (isHiDPIImage(img)) {
observer);
return result;
}
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
return false;
}
} finally {
}
}
int x,
int y) {
return;
}
try {
} catch (InvalidPipeException e) {
try {
} catch (InvalidPipeException e2) {
// Still catching the exception; we are not yet ready to
// validate the surfaceData correctly. Fail for now and
// try again next time around.
}
} finally {
}
}
/**
* Get the rendering context of the font
* within this Graphics2D context.
*/
int aahint = textAntialiasHint;
}
// Translation components should be excluded from the FRC transform
if (transformState >= TRANSFORM_TRANSLATESCALE) {
} else {
0, 0);
}
}
}
return cachedFRC;
}
/**
* This object has no resources to dispose of per se, but the
* doc comments for the base method in java.awt.Graphics imply
* that this object will not be useable after it is disposed.
* So, we sabotage the object to prevent further use to prevent
* developers from relying on behavior that may not work on
* other, less forgiving, VMs that really need to dispose of
* resources.
*/
public void dispose() {
}
/**
* Graphics has a finalize method that automatically calls dispose()
* for subclasses. For SunGraphics2D we do not need to be finalized
* so that method simply causes us to be enqueued on the Finalizer
* queues for no good reason. Unfortunately, that method and
* implementation are now considered part of the public contract
* of that base class so we can not remove or gut the method.
* We override it here with an empty method and the VM is smart
* enough to know that if our override is empty then it should not
* mark us as finalizeable.
*/
public void finalize() {
// DO NOT REMOVE THIS METHOD
}
/**
* Returns destination that this Graphics renders to. This could be
* either an Image or a Component; subclasses of SurfaceData are
* responsible for returning the appropriate object.
*/
return surfaceData.getDestination();
}
/**
* {@inheritDoc}
*
* @see sun.java2d.DestSurfaceProvider#getDestSurface
*/
return surfaceData;
}
}