blob: 6e7c17c703505a1232433599dc2a270a8c071255 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2000, 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Mariot Chauvin <mariot.chauvin@obeo.fr> - patch 244297
****************************************************************************/
package org.eclipse.gmf.runtime.draw2d.ui.internal.graphics;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.draw2d.FigureUtilities;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gmf.runtime.common.core.util.Log;
import org.eclipse.gmf.runtime.draw2d.ui.graphics.GCUtilities;
import org.eclipse.gmf.runtime.draw2d.ui.internal.Draw2dPlugin;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.LineAttributes;
import org.eclipse.swt.graphics.Path;
import org.eclipse.swt.graphics.PathData;
import org.eclipse.swt.graphics.Pattern;
import org.eclipse.swt.graphics.TextLayout;
import org.eclipse.swt.graphics.TextStyle;
import org.eclipse.swt.widgets.Display;
/**
* @canBeSeenBy %partners
*
* Subclass of Graphics that uses resource manager for its font cache and
* scales graphics/fonts by a specified scale factor
*
* <p>
* Code taken from Eclipse reference bugzilla #77403
* See also bugzilla #111454
* See also bugzilla #230056 setLineWidth in ScaledGraphics does not support the
* zoom factor.
*/
/**
* A Graphics object able to scale all operations based on the current scale factor.
*/
public class ScaledGraphics
extends Graphics {
private static class FontHeightCache {
Font font;
int height;
}
static class FontKey {
Font font;
int height;
protected FontKey() { }
protected FontKey(Font font, int height) {
this.font = font;
this.height = height;
}
public boolean equals(Object obj) {
return (((FontKey)obj).font.equals(font)
&& ((FontKey)obj).height == height);
}
public int hashCode() {
return font.hashCode() ^ height;
}
protected void setValues(Font font, int height) {
this.font = font;
this.height = height;
}
}
/**
* The internal state of the scaled graphics.
*/
protected static class State {
private double appliedX;
private double appliedY;
private Font font;
private float lineWidth;
private double zoom;
/**
* Constructs a new, uninitialized State object.
*/
protected State() { }
/**
* Constructs a new State object and initializes the properties based on the given
* values.
*
* @param zoom the zoom factor
* @param x the x offset
* @param y the y offset
* @param font the font
* @param lineWidth the line width
*/
protected State(double zoom, double x, double y, Font font, int lineWidth) {
this(zoom, x, y, font, (float)lineWidth);
}
/**
* Constructs a new State object and initializes the properties based on the given
* values.
*
* @param zoom the zoom factor
* @param x the x offset
* @param y the y offset
* @param font the font
* @param lineWidth the line width
*
* @since 3.5
*/
protected State(double zoom, double x, double y, Font font, float lineWidth) {
this.zoom = zoom;
this.appliedX = x;
this.appliedY = y;
this.font = font;
this.lineWidth = lineWidth;
}
/**
* Sets all the properties of the state object.
* @param zoom the zoom factor
* @param x the x offset
* @param y the y offset
* @param font the font
* @param lineWidth the line width
*/
protected void setValues(double zoom, double x, double y,
Font font, int lineWidth) {
setValues(zoom, x, y, font, (float)lineWidth);
}
/**
* Sets all the properties of the state object.
* @param zoom the zoom factor
* @param x the x offset
* @param y the y offset
* @param font the font
* @param lineWidth the line width
*
* @since 3.5
*/
protected void setValues(double zoom, double x, double y,
Font font, float lineWidth) {
this.zoom = zoom;
this.appliedX = x;
this.appliedY = y;
this.font = font;
this.lineWidth = lineWidth;
}
}
static private boolean advancedGraphicsWarningLogged = false;
private static int[][] intArrayCache = new int[8][];
private final Rectangle tempRECT = new Rectangle();
static {
for (int i = 0; i < intArrayCache.length; i++) {
intArrayCache[i] = new int[i + 1];
}
}
private boolean allowText = true;
//private static final Point PT = new Point();
//private Map fontCache = new HashMap();
private Map<Font, FontData> fontDataCache = new HashMap<Font, FontData>();
private FontKey fontKey = new FontKey();
private double fractionalX;
private double fractionalY;
private Graphics graphics;
private FontHeightCache localCache = new FontHeightCache();
private Font localFont;
private float localLineWidth;
private List<State> stack = new ArrayList<State>();
private int stackPointer = 0;
private FontHeightCache targetCache = new FontHeightCache();
double zoom = 1.0;
/**
* Constructs a new ScaledGraphics based on the given Graphics object.
* @param g the base graphics object
*/
public ScaledGraphics(Graphics g) {
graphics = g;
localFont = g.getFont();
localLineWidth = g.getLineWidthFloat();
}
/** @see Graphics#clipRect(Rectangle) */
public void clipRect(Rectangle r) {
graphics.clipRect(zoomClipRect(r));
}
Font createFont(FontData data) {
return new Font(Display.getCurrent(), data);
}
/**
* Scales given path by zoom factor
*
* @param path
* Path to be scaled
* @return Scaled path
* @since 1.2
*/
private Path createScaledPath(Path path) {
PathData p = path.getPathData();
for (int i = 0; i < p.points.length; i += 2) {
p.points[i] = (float) (p.points[i] * zoom + fractionalX);
p.points[i + 1] = (float) (p.points[i + 1] * zoom + fractionalY);
}
Path scaledPath = new Path(path.getDevice());
int index = 0;
for (int i = 0; i < p.types.length; i++) {
byte type = p.types[i];
switch (type) {
case SWT.PATH_MOVE_TO:
scaledPath.moveTo(p.points[index], p.points[index + 1]);
index += 2;
break;
case SWT.PATH_LINE_TO:
scaledPath.lineTo(p.points[index], p.points[index + 1]);
index += 2;
break;
case SWT.PATH_CUBIC_TO:
scaledPath.cubicTo(p.points[index], p.points[index + 1],
p.points[index + 2], p.points[index + 3],
p.points[index + 4], p.points[index + 5]);
index += 6;
break;
case SWT.PATH_QUAD_TO:
scaledPath.quadTo(p.points[index], p.points[index + 1],
p.points[index + 2], p.points[index + 3]);
index += 4;
break;
case SWT.PATH_CLOSE:
scaledPath.close();
break;
}
}
return scaledPath;
}
/** @see Graphics#dispose() */
public void dispose() {
//Remove all states from the stack
while (stackPointer > 0) {
popState();
}
// Resource manager handles fonts
}
/** @see Graphics#drawArc(int, int, int, int, int, int) */
public void drawArc(int x, int y, int w, int h, int offset, int sweep) {
Rectangle z = zoomRect(x, y, w, h);
if (z.isEmpty() || sweep == 0)
return;
graphics.drawArc(z, offset, sweep);
}
/** @see Graphics#drawFocus(int, int, int, int) */
public void drawFocus(int x, int y, int w, int h) {
graphics.drawFocus(zoomRect(x, y, w, h));
}
/** @see Graphics#drawImage(Image, int, int) */
public void drawImage(Image srcImage, int x, int y) {
org.eclipse.swt.graphics.Rectangle size = srcImage.getBounds();
Dimension sizeLPDim = new Dimension(size.width, size.height);
if (graphics instanceof MapModeGraphics) {
((MapModeGraphics)graphics).getMapMode().DPtoLP(sizeLPDim);
}
Rectangle z = new Rectangle((int)(Math.floor((x * zoom + fractionalX))),
(int)(Math.floor((y * zoom + fractionalY))),
(int)(Math.floor((sizeLPDim.width * zoom + fractionalX))),
(int)(Math.floor((sizeLPDim.height * zoom + fractionalY))));
graphics.drawImage(srcImage, 0, 0, size.width, size.height,
z.x, z.y, z.width, z.height);
}
/** @see Graphics#drawImage(Image, int, int, int, int, int, int, int, int) */
public void drawImage(Image srcImage, int sx, int sy, int sw, int sh,
int tx, int ty, int tw, int th) {
//"t" == target rectangle, "s" = source
Rectangle t = zoomRect(tx, ty, tw, th);
if (!t.isEmpty())
graphics.drawImage(srcImage, sx, sy, sw, sh, t.x, t.y, t.width, t.height);
}
/** @see Graphics#drawLine(int, int, int, int) */
public void drawLine(int x1, int y1, int x2, int y2) {
graphics.drawLine(
(int)(Math.floor((x1 * zoom + fractionalX))),
(int)(Math.floor((y1 * zoom + fractionalY))),
(int)(Math.floor((x2 * zoom + fractionalX))),
(int)(Math.floor((y2 * zoom + fractionalY))));
}
/** @see Graphics#drawOval(int, int, int, int) */
public void drawOval(int x, int y, int w, int h) {
graphics.drawOval(zoomRect(x, y, w, h));
}
/** @see Graphics#drawPath(Path) */
public void drawPath(Path path) {
Path scaledPath = createScaledPath(path);
try {
graphics.drawPath(scaledPath);
} finally {
scaledPath.dispose();
}
}
/** @see Graphics#drawPoint(int, int) */
public void drawPoint(int x, int y) {
graphics.drawPoint((int)Math.floor(x * zoom + fractionalX),
(int)Math.floor(y * zoom + fractionalY));
}
/**
* @see Graphics#drawPolygon(int[])
*/
public void drawPolygon(int[] points) {
graphics.drawPolygon(zoomPointList(points));
}
/** @see Graphics#drawPolygon(PointList) */
public void drawPolygon(PointList points) {
graphics.drawPolygon(zoomPointList(points.toIntArray()));
}
/**
* @see Graphics#drawPolyline(int[])
*/
public void drawPolyline(int[] points) {
graphics.drawPolyline(zoomPointList(points));
}
/** @see Graphics#drawPolyline(PointList) */
public void drawPolyline(PointList points) {
graphics.drawPolyline(zoomPointList(points.toIntArray()));
}
/** @see Graphics#drawRectangle(int, int, int, int) */
public void drawRectangle(int x, int y, int w, int h) {
graphics.drawRectangle(zoomRect(x, y, w, h));
}
/** @see Graphics#drawRoundRectangle(Rectangle, int, int) */
public void drawRoundRectangle(Rectangle r, int arcWidth, int arcHeight) {
graphics.drawRoundRectangle(zoomRect(r.x, r.y, r.width, r.height),
(int)(arcWidth * zoom),
(int)(arcHeight * zoom));
}
/** @see Graphics#drawString(String, int, int) */
public void drawString(String s, int x, int y) {
if (allowText)
graphics.drawString(s, zoomTextPoint(x, y));
}
/** @see Graphics#drawText(String, int, int) */
public void drawText(String s, int x, int y) {
if (allowText)
graphics.drawText(s, zoomTextPoint(x, y));
}
/**
* @see Graphics#drawText(String, int, int, int)
*/
public void drawText(String s, int x, int y, int style) {
if (allowText)
graphics.drawText(s, zoomTextPoint(x, y), style);
}
/**
* @see Graphics#drawTextLayout(TextLayout, int, int, int, int, Color, Color)
*/
public void drawTextLayout(TextLayout layout, int x, int y, int selectionStart,
int selectionEnd, Color selectionForeground, Color selectionBackground) {
TextLayout scaled = zoomTextLayout(layout);
graphics.drawTextLayout(scaled,
(int)Math.floor(x * zoom + fractionalX),
(int)Math.floor(y * zoom + fractionalY),
selectionStart, selectionEnd, selectionBackground, selectionForeground);
scaled.dispose();
}
/** @see Graphics#fillArc(int, int, int, int, int, int) */
public void fillArc(int x, int y, int w, int h, int offset, int sweep) {
Rectangle z = zoomFillRect(x, y, w, h);
if (z.isEmpty() || sweep == 0)
return;
graphics.fillArc(z, offset, sweep);
}
/** @see Graphics#fillGradient(int, int, int, int, boolean) */
public void fillGradient(int x, int y, int w, int h, boolean vertical) {
graphics.fillGradient(zoomFillRect(x, y, w, h), vertical);
}
/** @see Graphics#fillOval(int, int, int, int) */
public void fillOval(int x, int y, int w, int h) {
graphics.fillOval(zoomFillRect(x, y, w, h));
}
/** @see Graphics#fillPath(Path) */
public void fillPath(Path path) {
Path scaledPath = createScaledPath(path);
try {
graphics.fillPath(scaledPath);
} finally {
scaledPath.dispose();
}
}
/**
* @see Graphics#fillPolygon(int[])
*/
public void fillPolygon(int[] points) {
graphics.fillPolygon(zoomPointList(points));
}
/** @see Graphics#fillPolygon(PointList) */
public void fillPolygon(PointList points) {
graphics.fillPolygon(zoomPointList(points.toIntArray()));
}
/** @see Graphics#fillRectangle(int, int, int, int) */
public void fillRectangle(int x, int y, int w, int h) {
graphics.fillRectangle(zoomFillRect(x, y, w, h));
}
/** @see Graphics#fillRoundRectangle(Rectangle, int, int) */
public void fillRoundRectangle(Rectangle r, int arcWidth, int arcHeight) {
graphics.fillRoundRectangle(zoomFillRect(r.x, r.y, r.width, r.height),
(int)(arcWidth * zoom),
(int)(arcHeight * zoom));
}
/** @see Graphics#fillString(String, int, int) */
public void fillString(String s, int x, int y) {
if (allowText)
graphics.fillString(s, zoomTextPoint(x, y));
}
/** @see Graphics#fillText(String, int, int) */
public void fillText(String s, int x, int y) {
if (allowText)
graphics.fillText(s, zoomTextPoint(x, y));
}
/**
* @see Graphics#getAbsoluteScale()
*/
public double getAbsoluteScale() {
return zoom * graphics.getAbsoluteScale();
}
/**
* @see Graphics#getAlpha()
*/
public int getAlpha() {
return graphics.getAlpha();
}
/**
* @see Graphics#getAntialias()
*/
public int getAntialias() {
return graphics.getAntialias();
}
/** @see Graphics#getBackgroundColor() */
public Color getBackgroundColor() {
return graphics.getBackgroundColor();
}
Font getCachedFont(FontKey key) {
FontData data = key.font.getFontData()[0];
data.setHeight(key.height);
return FontRegistry.getInstance().getFont(Display.getCurrent(), data);
}
/**
* Allows clients to reset the font cache utilized by the ScaledGraphics in
* order to avoid caching more objects then necessary.
*/
static public void resetFontCache() {
FontRegistry.getInstance().clearFontCache();
}
FontData getCachedFontData(Font f) {
FontData data = fontDataCache.get(f);
if (data == null) {
data = getLocalFont().getFontData()[0];
fontDataCache.put(f, data);
}
return data;
}
/** @see Graphics#getClip(Rectangle) */
public Rectangle getClip(Rectangle rect) {
graphics.getClip(rect);
int x = (int)(rect.x / zoom);
int y = (int)(rect.y / zoom);
/*
* If the clip rectangle is queried, perform an inverse zoom, and take the ceiling of
* the resulting double. This is necessary because forward scaling essentially performs
* a floor() function. Without this, figures will think that they don't need to paint
* when actually they do.
*/
rect.width = (int)Math.ceil(rect.right() / zoom) - x;
rect.height = (int)Math.ceil(rect.bottom() / zoom) - y;
rect.x = x;
rect.y = y;
return rect;
}
/**
* @see Graphics#getAdvanced()
*/
public boolean getAdvanced() {
return graphics.getAdvanced();
}
/**
* @see Graphics#getFillRule()
*/
public int getFillRule() {
return graphics.getFillRule();
}
/** @see Graphics#getFont() */
public Font getFont() {
return getLocalFont();
}
/** @see Graphics#getFontMetrics() */
public FontMetrics getFontMetrics() {
return FigureUtilities.getFontMetrics(localFont);
}
/** @see Graphics#getForegroundColor() */
public Color getForegroundColor() {
return graphics.getForegroundColor();
}
/**
* @see Graphics#getInterpolation()
*/
public int getInterpolation() {
return graphics.getInterpolation();
}
/**
* @see Graphics#getLineCap()
*/
public int getLineCap() {
return graphics.getLineCap();
}
/**
* @see Graphics#getLineJoin()
*/
public int getLineJoin() {
return graphics.getLineJoin();
}
/** @see Graphics#getLineStyle() */
public int getLineStyle() {
return graphics.getLineStyle();
}
/** @see Graphics#getLineMiterLimit() */
public float getLineMiterLimit() {
return graphics.getLineMiterLimit();
}
/** @see Graphics#getLineWidth() */
public int getLineWidth() {
return (int)getLineWidthFloat();
}
/** @see Graphics#getLineWidthFloat() */
public float getLineWidthFloat() {
return getLocalLineWidth();
}
/** @see Graphics#getLineAttributes() */
public LineAttributes getLineAttributes() {
LineAttributes a = graphics.getLineAttributes();
a.width = getLocalLineWidth();
return a;
}
private Font getLocalFont() {
return localFont;
}
private float getLocalLineWidth() {
return localLineWidth;
}
/**
* @see Graphics#getTextAntialias()
*/
public int getTextAntialias() {
return graphics.getTextAntialias();
}
/** @see Graphics#getXORMode() */
public boolean getXORMode() {
return graphics.getXORMode();
}
/** @see Graphics#popState() */
public void popState() {
graphics.popState();
stackPointer--;
restoreLocalState(stack.get(stackPointer));
}
/** @see Graphics#pushState() */
public void pushState() {
State s;
if (stack.size() > stackPointer) {
s = stack.get(stackPointer);
s.setValues(zoom, fractionalX, fractionalY, getLocalFont(), localLineWidth);
} else {
stack.add(new State(zoom, fractionalX, fractionalY, getLocalFont(),
localLineWidth));
}
stackPointer++;
graphics.pushState();
}
private void restoreLocalState(State state) {
this.fractionalX = state.appliedX;
this.fractionalY = state.appliedY;
setScale(state.zoom);
setLocalFont(state.font);
setLocalLineWidth(state.lineWidth);
}
/** @see Graphics#restoreState() */
public void restoreState() {
graphics.restoreState();
restoreLocalState(stack.get(stackPointer - 1));
}
/** @see Graphics#scale(double) */
public void scale(double amount) {
setScale(zoom * amount);
}
/** @see Graphics#setAdvanced(boolean) */
public void setAdvanced(boolean advanced) {
graphics.setAdvanced(advanced);
}
/**
* This method requires advanced graphics support. A check should be made to
* ensure advanced graphics is supported in the user's environment before
* calling this method. See {@link GCUtilities#supportsAdvancedGraphics()}.
*
* @see Graphics#setAlpha(int)
*/
public void setAlpha(int alpha) {
if (!GCUtilities.supportsAdvancedGraphics()) {
logAdvancedGraphicsWarning();
return;
}
graphics.setAlpha(alpha);
}
/**
* This method requires advanced graphics support. A check should be made to
* ensure advanced graphics is supported in the user's environment before
* calling this method. See {@link GCUtilities#supportsAdvancedGraphics()}.
*
* @see Graphics#setAntialias(int)
*/
public void setAntialias(int value) {
if (!GCUtilities.supportsAdvancedGraphics()) {
logAdvancedGraphicsWarning();
return;
}
graphics.setAntialias(value);
}
/** @see Graphics#setBackgroundColor(Color) */
public void setBackgroundColor(Color rgb) {
graphics.setBackgroundColor(rgb);
}
/** @see Graphics#setClip(Path) */
public void setClip(Path path) {
Path scaledPath = createScaledPath(path);
try {
graphics.setClip(scaledPath);
} finally {
scaledPath.dispose();
}
}
public void clipPath(Path path) {
Path scaledPath = createScaledPath(path);
try {
graphics.clipPath(scaledPath);
} finally {
scaledPath.dispose();
}
}
/** @see Graphics#setBackgroundPattern(Pattern) */
public void setBackgroundPattern(Pattern pattern) {
graphics.setBackgroundPattern(pattern);
}
/** @see Graphics#setClip(Rectangle) */
public void setClip(Rectangle r) {
graphics.setClip(zoomClipRect(r));
}
/**
* @see Graphics#setFillRule(int)
*/
public void setFillRule(int rule) {
graphics.setFillRule(rule);
}
/** @see Graphics#setFont(Font) */
public void setFont(Font f) {
setLocalFont(f);
}
/** @see Graphics#setForegroundColor(Color) */
public void setForegroundColor(Color rgb) {
graphics.setForegroundColor(rgb);
}
/** @see Graphics#setForegroundPattern(Pattern) */
public void setForegroundPattern(Pattern pattern) {
graphics.setForegroundPattern(pattern);
}
/**
* This method requires advanced graphics support. A check should be made to
* ensure advanced graphics is supported in the user's environment before
* calling this method. See {@link GCUtilities#supportsAdvancedGraphics()}.
*
* @see org.eclipse.draw2d.Graphics#setInterpolation(int)
*/
public void setInterpolation(int interpolation) {
if (!GCUtilities.supportsAdvancedGraphics()) {
logAdvancedGraphicsWarning();
return;
}
graphics.setInterpolation(interpolation);
}
/**
* @see Graphics#setLineCap(int)
*/
public void setLineCap(int cap) {
graphics.setLineCap(cap);
}
/**
* @see Graphics#setLineDash(int[])
*/
public void setLineDash(int[] dash) {
graphics.setLineDash(dash);
}
/**
* @see Graphics#setLineJoin(int)
*/
public void setLineJoin(int join) {
graphics.setLineJoin(join);
}
/** @see Graphics#setLineStyle(int) */
public void setLineStyle(int style) {
graphics.setLineStyle(style);
}
/** @see Graphics#setLineMiterLimit(float) */
public void setLineMiterLimit(float value) {
graphics.setLineMiterLimit(value);
}
/** @see Graphics#setLineWidth(int) */
public void setLineWidth(int width) {
setLineWidthFloat(width);
}
/** @see Graphics#setLineWidthFloat(float) */
public void setLineWidthFloat(float width) {
setLocalLineWidth(width);
}
/** @see Graphics#setLineAttributes(LineAttributes) */
public void setLineAttributes(LineAttributes attributes) {
graphics.setLineAttributes(attributes);
setLocalLineWidth(attributes.width);
}
private void setLocalFont(Font f) {
localFont = f;
graphics.setFont(zoomFont(f));
}
private void setLocalLineWidth(float width) {
localLineWidth = width;
graphics.setLineWidthFloat(zoomLineWidth(width));
}
void setScale(double value) {
if (zoom != value) {
this.zoom = value;
graphics.setFont(zoomFont(getLocalFont()));
graphics.setLineWidthFloat(zoomLineWidth(localLineWidth));
}
}
/**
* This method requires advanced graphics support. A check should be made to
* ensure advanced graphics is supported in the user's environment before
* calling this method. See {@link GCUtilities#supportsAdvancedGraphics()}.
*
* @see Graphics#setTextAntialias(int)
*/
public void setTextAntialias(int value) {
if (!GCUtilities.supportsAdvancedGraphics()) {
logAdvancedGraphicsWarning();
return;
}
graphics.setTextAntialias(value);
}
/** @see Graphics#setXORMode(boolean) */
public void setXORMode(boolean b) {
graphics.setXORMode(b);
}
/** @see Graphics#translate(int, int) */
public void translate(int dx, int dy) {
// fractionalX/Y is the fractional part left over from previous
// translates that gets lost in the integer approximation.
double dxFloat = dx * zoom + fractionalX;
double dyFloat = dy * zoom + fractionalY;
fractionalX = dxFloat - Math.floor(dxFloat);
fractionalY = dyFloat - Math.floor(dyFloat);
graphics.translate((int)Math.floor(dxFloat), (int)Math.floor(dyFloat));
}
/** @see Graphics#translate(float, float) */
public void translate(float dx, float dy) {
double dxFloat = dx * zoom + fractionalX;
double dyFloat = dy * zoom + fractionalY;
fractionalX = dxFloat - Math.floor(dxFloat);
fractionalY = dyFloat - Math.floor(dyFloat);
graphics.translate((int)Math.floor(dxFloat), (int)Math.floor(dyFloat));
}
private Rectangle zoomClipRect(Rectangle r) {
tempRECT.x = (int)(Math.floor(r.x * zoom + fractionalX));
tempRECT.y = (int)(Math.floor(r.y * zoom + fractionalY));
tempRECT.width = (int)(Math.ceil(((r.x + r.width) * zoom + fractionalX))) - tempRECT.x;
tempRECT.height = (int)(Math.ceil(((r.y + r.height) * zoom + fractionalY))) - tempRECT.y;
return tempRECT;
}
private Rectangle zoomFillRect(int x, int y, int w, int h) {
tempRECT.x = (int)(Math.floor((x * zoom + fractionalX)));
tempRECT.y = (int)(Math.floor((y * zoom + fractionalY)));
tempRECT.width = (int)(Math.floor(((x + w - 1) * zoom + fractionalX))) - tempRECT.x + 1;
tempRECT.height = (int)(Math.floor(((y + h - 1) * zoom + fractionalY))) - tempRECT.y + 1;
return tempRECT;
}
Font zoomFont(Font f) {
if (f == null) {
f = Display.getCurrent().getSystemFont();
}
FontData data = getCachedFontData(f);
int zoomedFontHeight = zoomFontHeight(data.getHeight());
allowText = zoomedFontHeight > 0;
fontKey.setValues(f, zoomedFontHeight);
return getCachedFont(fontKey);
}
int zoomFontHeight(int height) {
return (int)(zoom * height);
}
float zoomLineWidth(float w) {
/*
* We introduced line width zoom in GMF 2.1.
* Unfortunately GMF 2.0 clients used HiMetric map mode and called
* setLineWidth(1) rather than setLineWidth(getMapMode().LPtoDP(1)).
* This small piece of code detects this case and simply returns the
* line width.
*/
if (zoom < 0.04 && w <= 5) {
return w;
}
/*
* We interestingly add 0.1 to eliminate rounding errors with HiMetric
* map mode. This has no effect with identity/pixel map mode.
*/
return (float)((zoom * w) + 0.1);
}
private int[] zoomPointList(int[] points) {
int[] scaled = null;
// Look in cache for a integer array with the same length as 'points'
for (int i = 0; i < intArrayCache.length; i++) {
if (intArrayCache[i].length == points.length) {
scaled = intArrayCache[i];
// Move this integer array up one notch in the array
if (i != 0) {
int[] temp = intArrayCache[i - 1];
intArrayCache[i - 1] = scaled;
intArrayCache[i] = temp;
}
}
}
// If no match is found, take the one that is last and resize it.
if (scaled == null) {
intArrayCache[intArrayCache.length - 1] = new int[points.length];
scaled = intArrayCache[intArrayCache.length - 1];
}
// Scale the points
for (int i = 0; (i + 1) < points.length; i += 2) {
scaled[i] = (int)(Math.floor((points[i] * zoom + fractionalX)));
scaled[i + 1] = (int)(Math.floor((points[i + 1] * zoom + fractionalY)));
}
return scaled;
}
protected Rectangle zoomRect(int x, int y, int w, int h) {
tempRECT.x = (int)(Math.floor(x * zoom + fractionalX));
tempRECT.y = (int)(Math.floor(y * zoom + fractionalY));
tempRECT.width = (int)(Math.floor(((x + w) * zoom + fractionalX))) - tempRECT.x;
tempRECT.height = (int)(Math.floor(((y + h) * zoom + fractionalY))) - tempRECT.y;
return tempRECT;
}
private TextLayout zoomTextLayout(TextLayout layout) {
TextLayout zoomed = new TextLayout(Display.getCurrent());
zoomed.setText(layout.getText());
int zoomWidth = -1;
if (layout.getWidth() != -1)
zoomWidth = ((int)(layout.getWidth() * zoom));
if (zoomWidth < -1 || zoomWidth == 0)
return null;
zoomed.setFont(zoomFont(layout.getFont()));
zoomed.setAlignment(layout.getAlignment());
zoomed.setAscent(layout.getAscent());
zoomed.setDescent(layout.getDescent());
zoomed.setOrientation(layout.getOrientation());
zoomed.setSegments(layout.getSegments());
zoomed.setSpacing(layout.getSpacing());
zoomed.setTabs(layout.getTabs());
zoomed.setWidth(zoomWidth);
int length = layout.getText().length();
if (length > 0) {
int start = 0, offset = 1;
TextStyle style = null, lastStyle = layout.getStyle(0);
for (; offset <= length; offset++) {
if (offset != length
&& (style = layout.getStyle(offset)) == lastStyle)
continue;
int end = offset - 1;
if (lastStyle != null) {
TextStyle zoomedStyle = new TextStyle(zoomFont(lastStyle.font),
lastStyle.foreground, lastStyle.background);
zoomedStyle.metrics = lastStyle.metrics;
zoomedStyle.rise = lastStyle.rise;
zoomedStyle.strikeout = lastStyle.strikeout;
zoomedStyle.underline = lastStyle.underline;
zoomed.setStyle(zoomedStyle, start, end);
}
lastStyle = style;
start = offset;
}
}
return zoomed;
}
Point zoomTextPoint(int x, int y) {
if (localCache.font != localFont) {
//Font is different, re-calculate its height
FontMetrics metric = FigureUtilities.getFontMetrics(localFont);
localCache.height = metric.getHeight() - metric.getDescent();
localCache.font = localFont;
}
if (targetCache.font != graphics.getFont()) {
FontMetrics metric = graphics.getFontMetrics();
targetCache.font = graphics.getFont();
targetCache.height = metric.getHeight() - metric.getDescent();
}
return new Point(((int)(Math.floor((x * zoom) + fractionalX))),
(int)(Math.floor((y + localCache.height - 1) * zoom
- targetCache.height + 1 + fractionalY)));
}
protected Graphics getGraphics() {
return graphics;
}
/**
* Logs a warning once if advanced graphics support is not available.
*/
private void logAdvancedGraphicsWarning() {
if (!advancedGraphicsWarningLogged) {
if (Window.getDefaultOrientation() == SWT.RIGHT_TO_LEFT) {
Log
.warning(
Draw2dPlugin.getInstance(),
IStatus.WARNING,
"Advanced graphics support is not available in right-to-left mode. Diagrams might not look as nice as they could in right-to-left mode."); //$NON-NLS-1$
} else {
Log
.warning(
Draw2dPlugin.getInstance(),
IStatus.WARNING,
"Unable to load advanced graphics library. Diagrams might not look as nice as they could with an advanced graphics library installed (e.g. Cairo or GDI+)"); //$NON-NLS-1$
}
advancedGraphicsWarningLogged = true;
}
}
}