--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/lcdui_qt/src/javax/microedition/lcdui/Buffer.java Tue Aug 31 15:09:22 2010 +0300
@@ -0,0 +1,871 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+package javax.microedition.lcdui;
+
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Widget;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.internal.qt.OS;
+import org.eclipse.swt.internal.qt.graphics.GraphicsContext;
+import org.eclipse.swt.internal.qt.graphics.JavaCommandBuffer;
+import org.eclipse.swt.internal.qt.graphics.WindowSurface;
+
+/**
+ * This class works a proxy between instances of Graphics class and common graphics
+ * (command buffer and GraphicsContext). The relation of this class to Graphics is one-to-many, i.e.
+ * one GraphicsBuffer instance handles multiple Graphics instances.
+ *
+ * Each LCDUI API class instance providing access to Graphics (Image, Canvas, GameCanvas, CustomItem),
+ * must instantiate one GraphicsBuffer and use it for creating instances of Graphics class.
+ *
+ * The implementation is not thread safe, thus all serialization must be implemented in
+ * callers, for instance the Graphics implementation serializes all calls to this class.
+ * Furthermore this class does not take care of switching to UI thread, it must be done by
+ * caller object.
+ */
+
+abstract class Buffer
+{
+
+ // Default values for Graphics
+ final static Font defaultFont = Font.getDefaultFont();
+ final static int defaultColor = 0xff000000;
+ final static int defaultStrokeStyle = Graphics.SOLID;
+ final static int defaultTranslateX = 0;
+ final static int defaultTranslateY = 0;
+
+ // Constants for buffer host types
+ final static int HOST_TYPE_IMAGE = 1;
+ final static int HOST_TYPE_CANVAS = 2;
+ final static int HOST_TYPE_CUSTOMITEM = 3;
+
+ // Flags for raising settings validation
+ // FORCE_SETTINGS Forces settings to validated also in case
+ // there's only one Graphics instance as client, normally
+ // settings are not checked in such case
+ final static int NONE = 0;
+ final static int COLOR = 1;
+ final static int CLIP = 2;
+ final static int FONT = 4;
+ final static int STROKESTYLE = 8;
+ final static int COORDS_TRANSLATION = 16;
+ final static int FORCE_SETTINGS = 32;
+
+ // Graphics settings active in buffer
+ // all values are comparable to those
+ // in Graphics except font which is stored
+ // as handle instead of LCDUI Font
+ private int bufferFontHandle;
+ private int bufferColor;
+ private int bufferStrokeStyle;
+ private int bufferTranslateX;
+ private int bufferTranslateY;
+ private Rectangle bufferClip;
+
+ private GraphicsContext gc;
+ private JavaCommandBuffer commandBuffer;
+ private Rectangle hostBounds;
+ private Graphics currentClient;
+ private boolean isInitialized;
+ private int clientCount;
+
+ private boolean isSurfaceSessionOpen;
+
+ /**
+ * Constructor
+ */
+ protected Buffer()
+ {
+ hostBounds = new Rectangle(0,0,0,0);
+ bufferClip = new Rectangle(0,0,0,0);
+ bufferFontHandle = 0;
+ bufferColor = 0xff000000;
+ bufferStrokeStyle = Graphics.SOLID;
+ bufferTranslateX = 0;
+ bufferTranslateY = 0;
+ }
+
+ /**
+ * Creates Buffer instance based on the type of given host object
+ * and the platform (symbian/linux) currently running on.
+ *
+ * @param host The host target where pixels are drawn. Given object must be Canvas, CustomItem or Image.
+ * @param control The eSWT control associated with the target, or null if the host is Image
+ * @return New buffer instance
+ */
+ static Buffer createInstance(Object host, Control control)
+ {
+ if(host instanceof Canvas)
+ {
+ if(OS.windowServer == OS.WS_SYMBIAN_S60)
+ {
+ return new CanvasBufferSymbian((Canvas) host, control);
+ }
+ else if(OS.windowServer == OS.WS_X11)
+ {
+ return new CanvasBufferLinux((Canvas) host, control);
+ }
+ return null;
+ }
+ else if(host instanceof CustomItem)
+ {
+ if(OS.windowServer == OS.WS_SYMBIAN_S60)
+ {
+ return new CustomItemBufferSymbian((CustomItem) host, control);
+ }
+ else if(OS.windowServer == OS.WS_X11)
+ {
+ return new CustomItemBufferLinux((CustomItem) host, control);
+ }
+ return null;
+ }
+ else if(host instanceof Image)
+ {
+ return new ImageBuffer((Image) host);
+ }
+ return null;
+ }
+
+ /**
+ * Initializes data, called once
+ */
+ protected void init()
+ {
+ clientCount = 0;
+ gc = new GraphicsContext();
+ commandBuffer = new JavaCommandBuffer();
+ gc.bindTarget(commandBuffer);
+ writeControlBoundsToBuffer(false);
+ isInitialized = true;
+ }
+
+ /**
+ * Defines the bounds of the host.
+ * Bounds are used for restricting the rendering in
+ * the area of the control that is being updated.
+ *
+ * @param crtl The Control of the host
+ * @param clienArea The area of the control which can be drawn by Graphics
+ */
+ void setControlBounds(final Control control)
+ {
+ // This implementation is based on the fact that
+ // the QWindowSurface has the size of the shell active area
+ // not the whole display, thus Shell clientArea equals QWindowSurface.
+ // This might change in future if/when Qt starts
+ // rendering e.g. the status pane i.e. the whole display
+ // to window surface
+ Point controlLoc = control.toDisplay(0,0);
+ Point shellLoc = control.getShell().toDisplay(0,0);
+ hostBounds.x = controlLoc.x - shellLoc.x;
+ hostBounds.y = controlLoc.y - shellLoc.y;
+ hostBounds.width = control.getBounds().width;
+ hostBounds.height = control.getBounds().height;
+ }
+
+ /**
+ * Defines the bounds of the host.
+ *
+ * @param crtl The Control of the host
+ * @param clienArea The area of the control which can be drawn by Graphics
+ */
+ void setImageBounds(int width, int height)
+ {
+ hostBounds.x = 0;
+ hostBounds.y = 0;
+ hostBounds.width = width;
+ hostBounds.height = height;
+ }
+
+ /**
+ * Prepares surface for a new frame and starts paint session.
+ * Must be called in UI thread (sync calls this automatically)
+ * and at the start of new frame. The rectangle provided as
+ * arguments are in control coordinates.
+ *
+ * @param x The x-coordinate of the area to be painted
+ * @param y The y-coordinate of the area to be painted
+ * @param w The width of the area to be painted
+ * @param h The height of the area to be painted
+ */
+ void startFrame(int x, int y, int w, int h)
+ {
+ if(!isSurfaceSessionOpen)
+ {
+ beginPaint(x, y, w, h);
+ isSurfaceSessionOpen = true;
+ }
+ }
+
+ /**
+ * Ends frame painting session. Must be called in UI thread and
+ * at the end of the frame. BlitToDisplay calls this automatically.
+ */
+ void endFrame()
+ {
+ if(isSurfaceSessionOpen)
+ {
+ endPaint();
+ isSurfaceSessionOpen = false;
+ }
+ }
+
+ /**
+ * Transfers the result of rendering to display.
+ * @param gc The graphics context used for blit, may be null in some cases
+ * @param widget The widget that is the target
+ */
+ void blitToDisplay(GraphicsContext gc, Widget widget)
+ {
+ endFrame();
+ blit(gc, widget);
+ }
+
+ /**
+ * Prepares surface for painting, implemented by
+ * child implementation.
+ * @param x The x-coordinate of the area to be painted
+ * @param y The y-coordinate of the area to be painted
+ * @param w The width of the area to be painted
+ * @param h The height of the area to be painted
+ */
+ abstract void beginPaint(int x, int y, int w, int h);
+
+ /**
+ * Ends frame painting session. Must be called in UI thread and
+ * at the end of the frame. Implemented by
+ * child implementation.
+ */
+ abstract void endPaint();
+
+ /**
+ * Performs binding to target in host specific way. Implemented by
+ * child implementation.
+ */
+ abstract void bindToHost(GraphicsContext gc);
+
+ /**
+ * Performs the actual blit operation in child class implementation.
+ * @param gc The graphics context used for blit, may be null in some cases
+ * @param widget The widget that is the target
+ */
+ abstract void blit(GraphicsContext gc, Widget widget);
+
+ /**
+ * Getter for the host of the buffer, implemented by
+ * child implementation.
+ * @return The host
+ */
+ abstract Object getHost();
+
+ /**
+ * Getter for the host type,implemented by
+ * child implementation.
+ * @return One of host types defined in this class
+ */
+ abstract int getHostType();
+
+ /**
+ * Status checker that indicates if this instance has requested a synchronous paint event,
+ * implemented by child implementation.
+ * @return True if this instance has requested a redraw paint event, otherwise false
+ */
+ abstract boolean isPaintingActive();
+
+ /**
+ * Creates and returns new Graphics instance
+ * @return new Graphics instance
+ */
+ Graphics getGraphics()
+ {
+ if(!isInitialized)
+ {
+ init();
+ }
+ clientCount++;
+ // In case this is the first Graphics instance
+ // write the default values to the buffer
+ if(clientCount == 1)
+ {
+ writeDefaultValuesToBuffer();
+ }
+ return new Graphics(this, hostBounds );
+ }
+
+ /**
+ * Synchronizes this buffer with the actual target
+ * must be called in UI thread. If no Graphics instances
+ * are created, sync has no effect. This variant always closes
+ * the surface session unconditionally
+ */
+ void sync()
+ {
+ sync(true);
+ }
+
+ /**
+ * Synchronizes this buffer with the actual target
+ * must be called in UI thread. If no Graphics instances
+ * are created, sync has no effect
+ *
+ * @param closeSurfaceSession If true the endFrame is called after sync has been
+ * performed closing the surface session, otherwise
+ * endFrame is performed and surface session is left open
+ */
+ void sync(boolean closeSurfaceSession)
+ {
+ if(!isInitialized)
+ {
+ return;
+ }
+
+ // if there's nothing to flush return
+ if(!commandBuffer.containsDrawnPrimitives())
+ {
+ return;
+ }
+
+ // Start surface session if not started yet
+ startFrame(hostBounds.x, hostBounds.y , hostBounds.width , hostBounds.height);
+
+ doRelease();
+ bindToHost(gc);
+ gc.render(commandBuffer);
+ doRelease();
+
+ // Close surface session
+ if(closeSurfaceSession)
+ {
+ endFrame();
+ }
+
+ // Reset commands
+ commandBuffer.reset();
+
+ // Write last settings to buffer
+ // as they are reset in bind
+ gc.bindTarget(commandBuffer);
+ gc.setFont(bufferFontHandle);
+ gc.setBackgroundColor(bufferColor, true);
+ gc.setForegroundColor(bufferColor, true);
+ writeControlBoundsToBuffer(true);
+ }
+
+ /**
+ * Decreases the client reference count,
+ * should be called by Graphics instances when
+ * they are about to be disposed
+ */
+ void removeRef()
+ {
+ clientCount--;
+ }
+
+ /**
+ * Disposes this instance
+ */
+ void dispose()
+ {
+ if(gc != null)
+ {
+ doRelease();
+ gc.dispose();
+ gc = null;
+ }
+ commandBuffer = null;
+ }
+
+ void copyArea(int x1, int y1, int width, int height, int x2, int y2, Graphics client)
+ {
+ gc.copyArea(x1, y1, width, height, x2, y2);
+ }
+
+ void fillRect(int x, int y, int w, int h, Graphics client)
+ {
+ validateAndApplySettings((COLOR|CLIP|COORDS_TRANSLATION), client);
+ gc.fillRect(x, y, w, h);
+ }
+
+ void fillRoundRect(int x, int y, int w, int h, int arcW, int arcH, Graphics client)
+ {
+ validateAndApplySettings((COLOR|CLIP|COORDS_TRANSLATION), client);
+ gc.fillRoundRect(x, y, w, h, arcW, arcH);
+ }
+
+ void fillArc(int x, int y, int w, int h, int startAngle, int arcAngle, Graphics client)
+ {
+ validateAndApplySettings((COLOR|CLIP|COORDS_TRANSLATION), client);
+ gc.fillArc(x, y, w, h, startAngle, arcAngle);
+ }
+
+ void fillTriangle(int[] points, Graphics client)
+ {
+ validateAndApplySettings((COLOR|CLIP|COORDS_TRANSLATION), client);
+ gc.fillPolygon(points);
+ }
+
+ void setClip(int x, int y, int w, int h, Graphics client)
+ {
+ validateAndApplySettings(COORDS_TRANSLATION, client);
+ // check if given clip is already active in buffer
+ if((bufferClip.x == x) && (bufferClip.y == y) &&
+ (bufferClip.width == w) && (bufferClip.height== h))
+ {
+ return;
+ }
+ // Images do not need special handling
+ if(getHostType() == HOST_TYPE_IMAGE)
+ {
+ gc.setClip(x, y, w, h, false);
+ return;
+ }
+
+ // translate clip to display coordinates and apply
+ Rectangle rect = clipToWindowCoords(x, y, w, h);
+ if(rect.isEmpty())
+ {
+ // check is buffer clip is already up to date
+ if(bufferClip.isEmpty())
+ {
+ return;
+ }
+ else
+ {
+ // This is a special case, where the clip defines
+ // an area outside control bounds and due to that the clip
+ // is set to zero size, in order t prevent drawing on top of other controls.
+ // In all other cases the buffer clip is always set
+ // to the same values as the client, i.e. Graphics has.
+ // So by setting the bufferClip here to zero means that the clip
+ // in Graphics and the buffer are not in sync and not comparable,
+ // however they will be back in sync when client sets clip
+ // with an area partly or completely inside the host control.
+ bufferClip = rect;
+ }
+ }
+ else
+ {
+ bufferClip.x = x;
+ bufferClip.y = y;
+ bufferClip.width = w;
+ bufferClip.height = h;
+ }
+ gc.setClip(rect.x, rect.y, rect.width, rect.height, false);
+ }
+
+ void setGraphicsDefaults(Graphics client)
+ {
+ validateAndApplySettings((FONT|COLOR|STROKESTYLE|COORDS_TRANSLATION|FORCE_SETTINGS), client);
+ }
+
+ void setColor(int r, int g, int b, Graphics client)
+ {
+ // check if given color is already active in buffer
+ if(bufferColor == (Graphics.OPAQUE_ALPHA | (r << 16) | (g << 8) | b))
+ {
+ return;
+ }
+ gc.setForegroundColor(r, g, b);
+ gc.setBackgroundColor(r, g, b);
+
+ // Cache active color
+ bufferColor = (Graphics.OPAQUE_ALPHA | (r << 16) | (g << 8) | b);
+ }
+
+ void setFont(int fontHandle, Graphics client)
+ {
+ // check if given font is already active in buffer
+ if(bufferFontHandle == fontHandle)
+ {
+ return;
+ }
+ gc.setFont(fontHandle);
+ // Cache active setting
+ bufferFontHandle = fontHandle;
+ }
+
+ void setStrokeStyle(int cgfxStyle, int graphicsStyle, Graphics client)
+ {
+ if(bufferStrokeStyle == graphicsStyle)
+ {
+ return;
+ }
+ gc.setStrokeStyle(cgfxStyle);
+ // Cache active setting
+ bufferStrokeStyle = graphicsStyle;
+ }
+
+ void translate(int xDelta, int yDelta, Graphics client)
+ {
+ if((xDelta == 0) && (yDelta == 0))
+ {
+ return;
+ }
+ gc.translate(xDelta, yDelta);
+ // Cache active settings
+ bufferTranslateX += xDelta;
+ bufferTranslateY += yDelta;
+ }
+
+ void drawLine(int xStart, int yStart, int xEnd, int yEnd, Graphics client)
+ {
+ validateAndApplySettings((COLOR|CLIP|COORDS_TRANSLATION|STROKESTYLE), client);
+ gc.drawLine(xStart, yStart, xEnd, yEnd);
+ }
+
+ void drawRect(int x, int y, int w, int h, Graphics client)
+ {
+ validateAndApplySettings((COLOR|CLIP|COORDS_TRANSLATION|STROKESTYLE), client);
+ gc.drawRect(x, y, w, h);
+ }
+
+ void drawRoundRect(int x, int y, int w, int h, int arcW, int arcH, Graphics client)
+ {
+ validateAndApplySettings((COLOR|CLIP|COORDS_TRANSLATION|STROKESTYLE), client);
+ gc.drawRoundRect(x, y, w, h, arcW, arcH);
+ }
+
+ void drawArc(int x, int y, int w, int h, int startAngle, int arcAngle, Graphics client)
+ {
+ validateAndApplySettings((COLOR|CLIP|COORDS_TRANSLATION|STROKESTYLE), client);
+ gc.drawArc(x, y, w, h, startAngle, arcAngle);
+ }
+
+ void drawString(String string, int x, int y, Graphics client)
+ {
+ validateAndApplySettings((COLOR|CLIP|COORDS_TRANSLATION|FONT), client);
+ gc.drawString(string, x, y, true);
+ }
+
+ void drawImage(org.eclipse.swt.internal.qt.graphics.Image image, int x,int y, Graphics client)
+ {
+ validateAndApplySettings((CLIP|COORDS_TRANSLATION), client);
+ gc.drawImage(image, x, y);
+ }
+
+ void drawImage(org.eclipse.swt.internal.qt.graphics.Image image, int xDst, int yDst,
+ int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc,
+ int transform, Graphics client)
+ {
+ validateAndApplySettings((CLIP|COORDS_TRANSLATION), client);
+ gc.drawImage(image, xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, transform);
+ }
+
+ void drawRGB(int[] rgb,
+ int offset,
+ int scanlength,
+ int x,
+ int y,
+ int w,
+ int h,
+ boolean alpha,
+ Graphics client)
+ {
+ validateAndApplySettings((CLIP|COORDS_TRANSLATION), client);
+ gc.drawRGB(rgb, offset, scanlength, x, y, w, h, alpha);
+ }
+
+ void drawRGB(int[] rgb,
+ int offset,
+ int scanlength,
+ int x,
+ int y,
+ int w,
+ int h,
+ boolean alpha,
+ int manipulation,
+ Graphics client)
+ {
+ validateAndApplySettings((CLIP|COORDS_TRANSLATION), client);
+ gc.drawRGB(rgb, offset, scanlength, x, y, w, h, alpha, manipulation);
+ }
+
+ void drawRGB(byte[] rgb,
+ byte[] transparencyMask,
+ int offset,
+ int scanlength,
+ int x,
+ int y,
+ int w,
+ int h,
+ int manipulation,
+ int format,
+ Graphics client)
+ {
+ validateAndApplySettings((CLIP|COORDS_TRANSLATION), client);
+ gc.drawRGB(rgb, transparencyMask, offset, scanlength, x, y, w, h, manipulation, format);
+ }
+
+ void drawRGB(short[] rgb,
+ int offset,
+ int scanlength,
+ int x,
+ int y,
+ int w,
+ int h,
+ boolean alpha,
+ int manipulation,
+ int format,
+ Graphics client)
+ {
+ validateAndApplySettings((CLIP|COORDS_TRANSLATION), client);
+ gc.drawRGB(rgb, offset, scanlength, x, y, w, h, alpha, manipulation, format);
+ }
+
+ void drawPolygon(int[] points, Graphics client)
+ {
+ validateAndApplySettings((COLOR|CLIP|COORDS_TRANSLATION|STROKESTYLE), client);
+ gc.drawPolygon(points);
+ }
+
+ void fillPolygon(int[] points, Graphics client)
+ {
+ validateAndApplySettings((COLOR|CLIP|COORDS_TRANSLATION), client);
+ gc.fillPolygon(points);
+ }
+
+ void setARGBColor(int argb, Graphics client)
+ {
+ if(bufferColor == argb)
+ {
+ return;
+ }
+ gc.setBackgroundColor(argb, true);
+ gc.setForegroundColor(argb, true);
+ // Cache active color
+ bufferColor = argb;
+ }
+
+ /**
+ * Translates given rectangle to window coordinates.
+ * Coordinate system translation does not affect on this method.
+ *
+ * @param x The x-coordinate of the rectangle
+ * @param y The y-coordinate of the rectangle
+ * @param w The width of the rectangle
+ * @param h The height of the rectangle
+ * @return
+ */
+ Rectangle toWindowCoordinates(int x, int y, int w, int h)
+ {
+ final int xInDpy = hostBounds.x + x;
+ final int yInDpy = hostBounds.y + y;
+ return new Rectangle(xInDpy, yInDpy, xInDpy + w, yInDpy + h);
+ }
+
+
+ /**
+ * Returns the WindowSurface that relates to this Buffer
+ *
+ * @return WindowSurface owned by this Buffer
+ */
+ WindowSurface getWindowSurface()
+ {
+ return null;
+ }
+
+ boolean containsDrawnPrimitives() {
+ boolean result = false;
+ if(commandBuffer != null) {
+ result = commandBuffer.containsDrawnPrimitives();
+ }
+ return result;
+ }
+
+ /**
+ * Translates given rectangle to window surface coordinates
+ * and outlines the clip inside the control bounds.
+ *
+ * @param x The x-coordinate of the rectangle
+ * @param y The y-coordinate of the rectangle
+ * @param w The width of the rectangle
+ * @param h The height of the rectangle
+ *
+ */
+ private Rectangle clipToWindowCoords(int x, int y, int w, int h)
+ {
+ // Bottom-right corner of control bounds in window coordinates
+ final int hostX2 = hostBounds.x + hostBounds.width;
+ final int hostY2 = hostBounds.y + hostBounds.height;
+ // clip in window coordinates
+ final int clipX1Dpy = hostBounds.x + bufferTranslateX + x;
+ final int clipY1Dpy = hostBounds.y + bufferTranslateY + y;
+ final int clipX2Dpy = hostBounds.x + bufferTranslateX + x + w;
+ final int clipY2Dpy = hostBounds.y + bufferTranslateY + y + h;
+ int clipX1 = x;
+ int clipY1 = y;
+ int clipX2 = x + w;
+ int clipY2 = y + h;
+
+ // check if the clip is completely outside of control bounds
+ if(!hostBounds.contains(clipX1Dpy, clipY1Dpy) && !hostBounds.contains(clipX2Dpy, clipY2Dpy))
+ {
+ return new Rectangle(0,0,0,0);
+ }
+
+ // At least one corner is inside control bounds so
+ // adjust clip coordinates so that they lie within control bounds
+ clipX1 = clipX1Dpy < hostBounds.x ? (x + (hostBounds.x - clipX1Dpy)) : x;
+ clipX1 = clipX1Dpy > hostX2 ? (x - (clipX1Dpy - hostX2)) : x;
+ clipY1 = clipY1Dpy < hostBounds.y ? (y + (hostBounds.y - clipY1Dpy)) : y;
+ clipY1 = clipY1Dpy > hostY2 ? (y - (clipY1Dpy - hostY2)) : y;
+
+ clipX2 = clipX2Dpy < hostBounds.x ? (clipX2 + (hostBounds.x - clipX1Dpy)) : clipX2;
+ clipX2 = clipX2Dpy > hostX2 ? (clipX2 - (clipX1Dpy - hostX2)) : clipX2;
+ clipY2 = clipY2Dpy < hostBounds.y ? (clipY2 + (hostBounds.y - clipY1Dpy)) : clipY2;
+ clipY2 = clipY2Dpy > hostY2 ? (clipY2 - (clipY1Dpy - hostY2)) : clipY2;
+
+ return new Rectangle(clipX1, clipY1, (clipX2 - clipX1) , (clipY2 - clipY1));
+ }
+
+ /**
+ * Validates the current settings active in buffer against
+ * caller settings and updated needed settings in buffer when
+ * that is required. This method does not update anything if
+ * there is only one (reference_count == 1)Graphics instance using this buffer.
+ *
+ * @param flags The settings that need to be checked
+ * @param client The Graphics instance that made the call
+ */
+ private void validateAndApplySettings(int flags, Graphics client)
+ {
+ if(!clientChanged(client) && (FORCE_SETTINGS & flags) == 0)
+ {
+ return;
+ }
+ if((COLOR & flags) != 0)
+ {
+ if(bufferColor != client.currentColor)
+ {
+ gc.setBackgroundColor(client.currentColor, true);
+ gc.setForegroundColor(client.currentColor, true);
+ bufferColor = client.currentColor;
+ }
+ }
+ if((CLIP & flags) != 0)
+ {
+ if(client.currentClip[0] != bufferClip.x &&
+ client.currentClip[1] != bufferClip.y &&
+ client.currentClip[2] != bufferClip.width &&
+ client.currentClip[3] != bufferClip.height)
+ {
+
+ Rectangle rect = clipToWindowCoords(client.currentClip[0], client.currentClip[1],
+ client.currentClip[2], client.currentClip[3]);
+ gc.setClip(rect.x, rect.y, rect.width, rect.height, false);
+ bufferClip.x = client.currentClip[0];
+ bufferClip.y = client.currentClip[1];
+ bufferClip.width = client.currentClip[2];
+ bufferClip.height = client.currentClip[3];
+ }
+ }
+ if((COORDS_TRANSLATION & flags) != 0)
+ {
+ if((bufferTranslateX != client.translateX) && (bufferTranslateY != client.translateY))
+ {
+ gc.translate((client.translateX - bufferTranslateX), (client.translateY - bufferTranslateY));
+ bufferTranslateX = client.translateX;
+ bufferTranslateY = client.translateY;
+ }
+ }
+ if((FONT & flags) != 0)
+ {
+ int fontHandle = Font.getESWTFont(client.currentFont).handle;
+ if(bufferFontHandle != fontHandle)
+ {
+ gc.setFont(fontHandle);
+ bufferFontHandle = fontHandle;
+ }
+ }
+ if((STROKESTYLE & flags) != 0)
+ {
+ if(bufferStrokeStyle != client.currentStrokeStyle)
+ {
+ gc.setStrokeStyle(Graphics.mapStrokeStyle(client.currentStrokeStyle));
+ bufferStrokeStyle = client.currentStrokeStyle;
+ }
+ }
+ }
+
+ private boolean clientChanged(Graphics client)
+ {
+ if(clientCount == 1)
+ {
+ return false;
+ }
+ if(currentClient != client)
+ {
+ currentClient = client;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Writes control bounds to buffer, including translation and clip
+ * @param writeClientTranslation If true write also client translation to buffer, otherwise not
+ */
+ private void writeControlBoundsToBuffer(boolean writeClientTranslation)
+ {
+ if((hostBounds.x != 0) || (hostBounds.y != 0))
+ {
+ gc.translate(hostBounds.x, hostBounds.y);
+ }
+ gc.setClip(0, 0, hostBounds.width, hostBounds.height, false);
+ // Cache buffer settings
+ bufferClip.x = 0;
+ bufferClip.y = 0;
+ bufferClip.width = hostBounds.width;
+ bufferClip.height = hostBounds.height;
+ // write client translation if requested
+ if(writeClientTranslation)
+ {
+ if((bufferTranslateX != 0) || (bufferTranslateY != 0))
+ {
+ gc.translate(bufferTranslateX, bufferTranslateY);
+ }
+ }
+ }
+
+ /**
+ * Writes Graphics default values to buffer
+ * @param force If true defaults are written unconditionally to buffer,
+ * otherwise only values that different than the ones in buffer
+ * are written
+ */
+ private void writeDefaultValuesToBuffer()
+ {
+ int handle = Font.getESWTFont(defaultFont).handle;
+ gc.setFont(handle);
+ bufferFontHandle = handle;
+ gc.setBackgroundColor(defaultColor, true);
+ gc.setForegroundColor(defaultColor, true);
+ bufferColor = defaultColor;
+ gc.setStrokeStyle(Graphics.mapStrokeStyle(defaultStrokeStyle));
+ bufferStrokeStyle = defaultStrokeStyle;
+ gc.resetTransform();
+ bufferTranslateX = defaultTranslateX;
+ bufferTranslateY = defaultTranslateY;
+ }
+
+ private void doRelease()
+ {
+ gc.releaseTarget();
+ }
+}