org.eclipse.birt.chart.device.swt.SwtRendererImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.birt.chart.device.swt.SwtRendererImpl.java

Source

/***********************************************************************
 * Copyright (c) 2004 Actuate Corporation.
 * 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:
 * Actuate Corporation - initial API and implementation
 ***********************************************************************/

package org.eclipse.birt.chart.device.swt;

import java.io.ByteArrayInputStream;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;

import org.apache.commons.codec.binary.Base64;
import org.eclipse.birt.chart.device.DeviceAdapter;
import org.eclipse.birt.chart.device.FontUtil;
import org.eclipse.birt.chart.device.IDeviceRenderer;
import org.eclipse.birt.chart.device.IDisplayServer;
import org.eclipse.birt.chart.device.IUpdateNotifier;
import org.eclipse.birt.chart.device.swt.i18n.Messages;
import org.eclipse.birt.chart.event.ArcRenderEvent;
import org.eclipse.birt.chart.event.AreaRenderEvent;
import org.eclipse.birt.chart.event.ClipRenderEvent;
import org.eclipse.birt.chart.event.ImageRenderEvent;
import org.eclipse.birt.chart.event.InteractionEvent;
import org.eclipse.birt.chart.event.LineRenderEvent;
import org.eclipse.birt.chart.event.OvalRenderEvent;
import org.eclipse.birt.chart.event.PolygonRenderEvent;
import org.eclipse.birt.chart.event.PrimitiveRenderEvent;
import org.eclipse.birt.chart.event.RectangleRenderEvent;
import org.eclipse.birt.chart.event.TextRenderEvent;
import org.eclipse.birt.chart.event.TransformationEvent;
import org.eclipse.birt.chart.exception.ChartException;
import org.eclipse.birt.chart.log.ILogger;
import org.eclipse.birt.chart.log.Logger;
import org.eclipse.birt.chart.model.attribute.Bounds;
import org.eclipse.birt.chart.model.attribute.ColorDefinition;
import org.eclipse.birt.chart.model.attribute.EmbeddedImage;
import org.eclipse.birt.chart.model.attribute.Fill;
import org.eclipse.birt.chart.model.attribute.Gradient;
import org.eclipse.birt.chart.model.attribute.ImageSourceType;
import org.eclipse.birt.chart.model.attribute.LineAttributes;
import org.eclipse.birt.chart.model.attribute.LineStyle;
import org.eclipse.birt.chart.model.attribute.Location;
import org.eclipse.birt.chart.model.attribute.PatternImage;
import org.eclipse.birt.chart.model.attribute.Position;
import org.eclipse.birt.chart.model.attribute.TriggerCondition;
import org.eclipse.birt.chart.model.data.Trigger;
import org.eclipse.birt.chart.render.InteractiveRenderer;
import org.eclipse.birt.chart.util.PatternImageUtil;
import org.eclipse.birt.chart.util.PatternImageUtil.ByteColorModel;
import org.eclipse.birt.chart.util.PluginSettings;
import org.eclipse.birt.chart.util.SecurityUtil;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.Path;
import org.eclipse.swt.graphics.Pattern;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.Region;
import org.eclipse.swt.widgets.Composite;

/**
 * This class implements the SWT primitive rendering code for each primitive
 * instruction sent out by the chart generation process.
 */
public class SwtRendererImpl extends DeviceAdapter {

    /**
     * A property name that identifies the double-buffered drawing capability.
     */
    public static final String DOUBLE_BUFFERED = "device.double.buffered"; //$NON-NLS-1$

    private final LinkedHashMap<TriggerCondition, List<RegionAction>> _lhmAllTriggers = new LinkedHashMap<TriggerCondition, List<RegionAction>>();

    private IDisplayServer _ids;

    private SwtTextRenderer _tr;

    private GC _gc = null;

    private IUpdateNotifier _iun = null;

    private SwtEventHandler _eh = null;

    private double dTranslateX = 0;

    private double dTranslateY = 0;

    private double dRotateInDegrees = 0;

    private double dScale = 1;

    private InteractiveRenderer iv;

    static final int CEIL = 1;

    static final int TRUNCATE = 2;

    private static ILogger logger = Logger.getLogger("org.eclipse.birt.chart.device.extension/swt"); //$NON-NLS-1$

    /**
     * The required zero-argument constructor
     */
    public SwtRendererImpl() {
        final PluginSettings ps = PluginSettings.instance();
        try {
            _ids = ps.getDisplayServer("ds.SWT"); //$NON-NLS-1$
            _tr = new SwtTextRenderer(_ids);
            iv = new InteractiveRenderer();
        } catch (ChartException pex) {
            logger.log(pex);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.event.IDeviceRenderer#getGraphicsContext()
     */
    public Object getGraphicsContext() {
        return _gc;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.event.IDeviceRenderer#getDisplayServer()
     */
    public IDisplayServer getDisplayServer() {
        return _ids;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.event.IPrimitiveRenderer#setClip(org.eclipse.birt.chart.event.ClipRenderEvent)
     */
    public void setClip(ClipRenderEvent cre) {
        final Location[] loa = cre.getVertices();

        if (loa == null) {
            _gc.setClipping((Region) null);
        } else {
            Region rgClipping = new Region();
            rgClipping.add(getCoordinatesAsInts(loa, TRUNCATE, dTranslateX, dTranslateY, dScale));
            _gc.setClipping(rgClipping);
            rgClipping.dispose();
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.event.IPrimitiveRenderer#drawImage(org.eclipse.birt.chart.event.ImageRenderEvent)
     */
    public void drawImage(ImageRenderEvent pre) throws ChartException {
        if (pre.getImage() == null || pre.getLocation() == null) {
            return;
        }

        Image img = null;

        if (pre.getImage() instanceof EmbeddedImage) {
            try {
                ByteArrayInputStream bis = new ByteArrayInputStream(
                        Base64.decodeBase64(((EmbeddedImage) pre.getImage()).getData().getBytes()));

                img = new org.eclipse.swt.graphics.Image(((SwtDisplayServer) _ids).getDevice(), bis);
            } catch (Exception ilex) {
                throw new ChartException(ChartDeviceSwtActivator.ID, ChartException.RENDERING, ilex);
            }
        } else if (pre.getImage().getSource() != ImageSourceType.FILE
                && pre.getImage().getSource() != ImageSourceType.REPORT) {
            try {
                final String sUrl = pre.getImage().getURL();
                img = (Image) _ids.loadImage(SecurityUtil.newURL(sUrl));
            } catch (ChartException ilex) {
                // Ignore the invalid path, and log it only
                logger.log(new ChartException(ChartDeviceSwtActivator.ID, ChartException.RENDERING, ilex));
            } catch (MalformedURLException muex) {
                throw new ChartException(ChartDeviceSwtActivator.ID, ChartException.RENDERING, muex);
            }
        }

        if (img == null) {
            return;
        }

        Location loc = pre.getLocation();
        Position pos = pre.getPosition();
        if (pos == null) {
            pos = Position.INSIDE_LITERAL;
        }

        final boolean bSizeSet = pre.getWidth() * pre.getHeight() > 0;
        int width = bSizeSet ? pre.getWidth() : img.getBounds().width;
        int height = bSizeSet ? pre.getHeight() : img.getBounds().height;
        int x = (int) loc.getX();
        int y = (int) loc.getY();

        switch (pos.getValue()) {
        case Position.INSIDE:
        case Position.OUTSIDE:
            x -= width / 2;
            y -= height / 2;
            break;
        case Position.LEFT:
            x -= width;
            y -= height / 2;
            break;
        case Position.RIGHT:
            y -= height / 2;
            break;
        case Position.ABOVE:
            x -= width / 2;
            y -= height;
            break;
        case Position.BELOW:
            x -= width / 2;
            break;
        }

        // Reset alpha
        R31Enhance.setAlpha(_gc, (ColorDefinition) null);
        if (bSizeSet) {
            _gc.drawImage(img, 0, 0, img.getBounds().width, img.getBounds().height, x, y, pre.getWidth(),
                    pre.getHeight());
        } else {
            _gc.drawImage(img, x, y);
        }

        img.dispose();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.event.IPrimitiveRenderer#drawLine(org.eclipse.birt.chart.event.LineRenderEvent)
     */
    public void drawLine(LineRenderEvent lre) throws ChartException {
        iv.modifyEvent(lre);
        // CHECK IF THE LINE ATTRIBUTES ARE CORRECTLY DEFINED
        final LineAttributes lia = lre.getLineAttributes();
        if (!validateLineAttributes(lre.getSource(), lia) || lia.getColor() == null) {
            return;
        }

        // DRAW THE LINE
        final int iOldLineStyle = _gc.getLineStyle();
        final int iOldLineWidth = _gc.getLineWidth();
        final Color cFG = (Color) _ids.getColor(lia.getColor());
        int iLineStyle = SWT.LINE_SOLID;
        switch (lia.getStyle().getValue()) {
        case (LineStyle.DOTTED):
            iLineStyle = SWT.LINE_DOT;
            break;
        case (LineStyle.DASH_DOTTED):
            iLineStyle = SWT.LINE_DASHDOT;
            break;
        case (LineStyle.DASHED):
            iLineStyle = SWT.LINE_DASH;
            break;
        }
        _gc.setLineStyle(iLineStyle);
        _gc.setLineWidth(lia.getThickness());
        final Location lo1 = lre.getStart();
        final Location lo2 = lre.getEnd();
        _gc.setForeground(cFG);

        R31Enhance.setAlpha(_gc, lia.getColor());

        _gc.drawLine((int) ((lo1.getX() + dTranslateX) * dScale), (int) ((lo1.getY() + dTranslateY) * dScale),
                (int) ((lo2.getX() + dTranslateX) * dScale), (int) ((lo2.getY() + dTranslateY) * dScale));

        _gc.setLineStyle(iOldLineStyle);
        _gc.setLineWidth(iOldLineWidth);
        cFG.dispose();

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.event.IPrimitiveRenderer#drawRectangle(org.eclipse.birt.chart.event.RectangleRenderEvent)
     */
    public void drawRectangle(RectangleRenderEvent rre) throws ChartException {
        iv.modifyEvent(rre);
        // CHECK IF THE LINE ATTRIBUTES ARE CORRECTLY DEFINED
        final LineAttributes lia = rre.getOutline();
        if (!validateLineAttributes(rre.getSource(), lia)) {
            return;
        }

        // SETUP THE FOREGROUND COLOR (DARKER BACKGROUND IF DEFINED AS NULL)
        final Color cFG = (Color) validateEdgeColor(lia.getColor(), rre.getBackground(), _ids);
        if (cFG == null) {
            return;
        }

        // DRAW THE RECTANGLE WITH THE APPROPRIATE LINE STYLE
        final int iOldLineStyle = _gc.getLineStyle();
        final int iOldLineWidth = _gc.getLineWidth();
        int iLineStyle = SWT.LINE_SOLID;
        switch (lia.getStyle().getValue()) {
        case (LineStyle.DOTTED):
            iLineStyle = SWT.LINE_DOT;
            break;
        case (LineStyle.DASH_DOTTED):
            iLineStyle = SWT.LINE_DASHDOT;
            break;
        case (LineStyle.DASHED):
            iLineStyle = SWT.LINE_DASH;
            break;
        }
        _gc.setLineStyle(iLineStyle);
        _gc.setLineWidth(lia.getThickness());
        final Bounds bo = normalizeBounds(rre.getBounds());
        _gc.setForeground(cFG);

        R31Enhance.setAlpha(_gc, lia.getColor());

        _gc.drawRectangle((int) ((bo.getLeft() + dTranslateX) * dScale),
                (int) ((bo.getTop() + dTranslateY) * dScale), (int) (bo.getWidth() * dScale) - 1,
                (int) (bo.getHeight() * dScale) - 1);

        _gc.setLineStyle(iOldLineStyle);
        _gc.setLineWidth(iOldLineWidth);
        cFG.dispose();

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.device.IPrimitiveRenderer#fillRectangle(org.eclipse.birt.chart.event.RectangleRenderEvent)
     */
    public void fillRectangle(RectangleRenderEvent rre) throws ChartException {
        iv.modifyEvent(rre);
        final Fill flBackground = validateMultipleFill(rre.getBackground());

        if (isFullTransparent(flBackground)) {
            return;
        }

        final Bounds bo = normalizeBounds(rre.getBounds());
        final Rectangle r = new Rectangle((int) ((bo.getLeft() + dTranslateX) * dScale),
                (int) ((bo.getTop() + dTranslateY) * dScale), (int) Math.ceil(bo.getWidth() * dScale),
                (int) Math.ceil(bo.getHeight() * dScale));

        final Path pt = new Path(((SwtDisplayServer) _ids).getDevice());
        pt.moveTo(r.x, r.y);
        pt.lineTo(r.x, r.y + r.height);
        pt.lineTo(r.x + r.width, r.y + r.height);
        pt.lineTo(r.x + r.width, r.y);

        try {
            if (flBackground instanceof ColorDefinition) {
                fillPathColor(pt, (ColorDefinition) flBackground);
            }
            if (flBackground instanceof Gradient) {
                fillPathGradient(pt, (Gradient) flBackground, r);
            } else if (flBackground instanceof org.eclipse.birt.chart.model.attribute.Image) {
                fillPathImage(pt, (org.eclipse.birt.chart.model.attribute.Image) flBackground);
            }
        } finally {
            pt.dispose();
        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.event.IPrimitiveRenderer#drawPolygon(org.eclipse.birt.chart.event.PolygonRenderEvent)
     */
    public void drawPolygon(PolygonRenderEvent pre) throws ChartException {
        iv.modifyEvent(pre);
        // CHECK IF THE LINE ATTRIBUTES ARE CORRECTLY DEFINED
        final LineAttributes lia = pre.getOutline();
        if (!validateLineAttributes(pre.getSource(), lia)) {
            return;
        }

        // SETUP THE FOREGROUND COLOR (DARKER BACKGROUND IF DEFINED AS NULL)
        final Color cFG = (Color) validateEdgeColor(lia.getColor(), pre.getBackground(), _ids);
        if (cFG == null) {
            return;
        }

        final int iOldLineStyle = _gc.getLineStyle();
        final int iOldLineWidth = _gc.getLineWidth();

        int iLineStyle = SWT.LINE_SOLID;
        switch (lia.getStyle().getValue()) {
        case (LineStyle.DOTTED):
            iLineStyle = SWT.LINE_DOT;
            break;
        case (LineStyle.DASH_DOTTED):
            iLineStyle = SWT.LINE_DASHDOT;
            break;
        case (LineStyle.DASHED):
            iLineStyle = SWT.LINE_DASH;
            break;
        }

        _gc.setLineStyle(iLineStyle);
        _gc.setLineWidth(lia.getThickness());
        _gc.setForeground(cFG);

        R31Enhance.setAlpha(_gc, lia.getColor());

        _gc.drawPolygon(getCoordinatesAsInts(pre.getPoints(), TRUNCATE, dTranslateX, dTranslateY, dScale));

        _gc.setLineStyle(iOldLineStyle);
        _gc.setLineWidth(iOldLineWidth);
        cFG.dispose();

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.event.IPrimitiveRenderer#fillPolygon(org.eclipse.birt.chart.event.PolygonRenderEvent)
     */
    public void fillPolygon(PolygonRenderEvent pre) throws ChartException {
        iv.modifyEvent(pre);

        // DUE TO RESTRICTIVE SWT API, WE SET A CLIPPED POLYGON REGION
        // AND RENDER THE POLYGON BY RENDERING A CONTAINING RECTANGLE WHERE
        // THE RECTANGLE BOUNDS CORRESPOND TO THE POLYGON BOUNDS
        // NOTE: SOME INCOMPLETE PAINTING ERRORS SEEM TO EXIST FOR GRADIENT POLY
        // FILLS

        final Fill flBackground = validateMultipleFill(pre.getBackground());

        if (isFullTransparent(flBackground)) {
            return;
        }

        final Bounds bo = normalizeBounds(pre.getBounds());
        final Rectangle r = new Rectangle((int) ((bo.getLeft() + dTranslateX) * dScale),
                (int) ((bo.getTop() + dTranslateY) * dScale), (int) Math.ceil(bo.getWidth() * dScale),
                (int) Math.ceil(bo.getHeight() * dScale));

        float[] points = convertDoubleToFloat(
                getDoubleCoordinatesAsInts(pre.getPoints(), TRUNCATE, dTranslateX, dTranslateY, dScale));
        if (points.length < 1) {
            return;
        }
        final Path pt = new Path(((SwtDisplayServer) _ids).getDevice());
        pt.moveTo(points[0], points[1]);
        for (int i = 1; i < points.length / 2; i++) {
            pt.lineTo(points[2 * i], points[2 * i + 1]);
        }

        try {
            if (flBackground instanceof ColorDefinition) {
                fillPathColor(pt, (ColorDefinition) flBackground);
            } else if (flBackground instanceof Gradient) {
                fillPathGradient(pt, (Gradient) flBackground, r);
            } else if (flBackground instanceof org.eclipse.birt.chart.model.attribute.Image) {
                fillPathImage(pt, (org.eclipse.birt.chart.model.attribute.Image) flBackground);
            }
        } finally {
            pt.dispose();
        }

    }

    /**
     * Extra fix due to SWT arc rendering limitation.
     * 
     * @param _gc
     * @param are
     * @param dTranslateX
     * @param dTranslateY
     * @param dScale
     */
    protected void drawArc(GC _gc, Device _dv, ArcRenderEvent are, double dTranslateX, double dTranslateY,
            double dScale) {

        if (are.getInnerRadius() >= 0 && (are.getOuterRadius() > 0 && are.getInnerRadius() < are.getOuterRadius())
                || (are.getInnerRadius() > 0 && are.getOuterRadius() <= 0)) {
            Bounds bo = goFactory.createBounds(are.getTopLeft().getX(), are.getTopLeft().getY(), are.getWidth(),
                    are.getHeight());

            Bounds rctOuter, rctInner;

            rctOuter = getOuterRectangle(are, dTranslateX, dTranslateY, dScale, bo);

            rctInner = getInnerRectangle(are, dTranslateX, dTranslateY, dScale, bo);

            double startAngle = Math.toRadians(-are.getStartAngle());
            double stopAngle = Math.toRadians(-are.getStartAngle() - are.getAngleExtent());

            double xsOuter = (rctOuter.getLeft() + (Math.cos(startAngle) * 0.5 + 0.5) * rctOuter.getWidth());
            double ysOuter = (rctOuter.getTop() + (Math.sin(startAngle) * 0.5 + 0.5) * rctOuter.getHeight());

            // double xeOuter = ( rctOuter.getLeft( ) + ( Math.cos( stopAngle )
            // * 0.5 + 0.5 )
            // * rctOuter.getWidth( ) );
            // double yeOuter = ( rctOuter.getTop( ) + ( Math.sin( stopAngle ) *
            // 0.5 + 0.5 )
            // * rctOuter.getHeight( ) );
            //
            // double xsInner = ( rctInner.getLeft( ) + ( Math.cos( startAngle )
            // * 0.5 + 0.5 )
            // * rctInner.getWidth( ) );
            // double ysInner = ( rctInner.getTop( ) + ( Math.sin( startAngle )
            // * 0.5 + 0.5 )
            // * rctInner.getHeight( ) );

            double xeInner = (rctInner.getLeft() + (Math.cos(stopAngle) * 0.5 + 0.5) * rctInner.getWidth());
            double yeInner = (rctInner.getTop() + (Math.sin(stopAngle) * 0.5 + 0.5) * rctInner.getHeight());

            Path pt = new Path(_dv);
            pt.addArc((float) rctOuter.getLeft(), (float) rctOuter.getTop(), (float) rctOuter.getWidth(),
                    (float) rctOuter.getHeight(), (float) are.getStartAngle(), (float) are.getAngleExtent());

            pt.lineTo((float) xeInner, (float) yeInner);

            pt.addArc((float) rctInner.getLeft(), (float) rctInner.getTop(), (float) rctInner.getWidth(),
                    (float) rctInner.getHeight(), (float) (are.getStartAngle() + are.getAngleExtent()),
                    (float) -are.getAngleExtent());

            pt.lineTo((float) xsOuter, (float) ysOuter);

            _gc.drawPath(pt);

            pt.dispose();
        } else {
            if (are.getStyle() == ArcRenderEvent.OPEN) {
                _gc.drawArc((int) ((are.getTopLeft().getX() + dTranslateX) * dScale),
                        (int) ((are.getTopLeft().getY() + dTranslateY) * dScale), (int) (are.getWidth() * dScale),
                        (int) (are.getHeight() * dScale), (int) are.getStartAngle(), (int) are.getAngleExtent());
            } else {
                double xc = ((are.getTopLeft().getX() + dTranslateX + are.getWidth() / 2d) * dScale);
                double yc = ((are.getTopLeft().getY() + dTranslateY + are.getHeight() / 2d) * dScale);

                double xs = 0, ys = 0, xe = 0, ye = 0;

                double angle = Math.toRadians(-are.getStartAngle());

                xs = ((are.getTopLeft().getX() + dTranslateX + (Math.cos(angle) * 0.5 + 0.5) * are.getWidth())
                        * dScale);
                ys = ((are.getTopLeft().getY() + dTranslateY + (Math.sin(angle) * 0.5 + 0.5) * are.getHeight())
                        * dScale);

                angle = Math.toRadians(-are.getStartAngle() - are.getAngleExtent());

                xe = ((are.getTopLeft().getX() + dTranslateX + (Math.cos(angle) * 0.5 + 0.5) * are.getWidth())
                        * dScale);
                ye = ((are.getTopLeft().getY() + dTranslateY + (Math.sin(angle) * 0.5 + 0.5) * are.getHeight())
                        * dScale);

                Path pt = new Path(_dv);
                if (are.getStyle() == ArcRenderEvent.CLOSED) {
                    pt.addArc((float) ((are.getTopLeft().getX() + dTranslateX) * dScale),
                            (float) ((are.getTopLeft().getY() + dTranslateY) * dScale),
                            (float) (are.getWidth() * dScale), (float) (are.getHeight() * dScale),
                            (float) are.getStartAngle(), (float) are.getAngleExtent());
                    // fix in case angle extent is zero.
                    pt.moveTo((float) xe, (float) ye);
                    pt.lineTo((float) xs, (float) ys);

                    _gc.drawPath(pt);
                } else if (are.getStyle() == ArcRenderEvent.SECTOR) {
                    pt.addArc((float) ((are.getTopLeft().getX() + dTranslateX) * dScale),
                            (float) ((are.getTopLeft().getY() + dTranslateY) * dScale),
                            (float) (are.getWidth() * dScale), (float) (are.getHeight() * dScale),
                            (float) are.getStartAngle(), (float) are.getAngleExtent());
                    // fix in case angle extent is zero.
                    pt.moveTo((float) xe, (float) ye);
                    pt.lineTo((float) xc, (float) yc);
                    pt.lineTo((float) xs, (float) ys);

                    _gc.drawPath(pt);
                }
                pt.dispose();
            }
        }

    }

    protected Bounds getOuterRectangle(ArcRenderEvent are, double dTranslateX, double dTranslateY, double dScale,
            Bounds bo) {
        Bounds rctOuter;
        if (are.getOuterRadius() > 0) {
            double radio = bo.getHeight() / bo.getWidth();
            rctOuter = goFactory.createBounds(
                    ((bo.getLeft() + dTranslateX + (bo.getWidth() / 2d - are.getOuterRadius())) * dScale),
                    ((bo.getTop() + dTranslateY + (bo.getHeight() / 2d - are.getOuterRadius() * radio)) * dScale),
                    (2 * are.getOuterRadius() * dScale), (2 * are.getOuterRadius() * dScale) * radio);
        } else {
            rctOuter = goFactory.createBounds(((bo.getLeft() + dTranslateX) * dScale),
                    ((bo.getTop() + dTranslateY) * dScale), (bo.getWidth() * dScale), (bo.getHeight() * dScale));
        }
        return rctOuter;
    }

    protected Bounds getInnerRectangle(ArcRenderEvent are, double dTranslateX, double dTranslateY, double dScale,
            Bounds bo) {
        Bounds rctInner;
        if (are.getInnerRadius() > 0) {
            double radio = bo.getHeight() / bo.getWidth();
            rctInner = goFactory.createBounds(
                    ((bo.getLeft() + dTranslateX + (bo.getWidth() / 2d - are.getInnerRadius())) * dScale),
                    ((bo.getTop() + dTranslateY + (bo.getHeight() / 2d - are.getInnerRadius() * radio)) * dScale),
                    (2 * are.getInnerRadius() * dScale), (2 * are.getInnerRadius() * dScale) * radio);
        } else {
            rctInner = goFactory.createBounds(((bo.getLeft() + dTranslateX + bo.getWidth() / 2d) * dScale),
                    ((bo.getTop() + dTranslateY + bo.getHeight() / 2d) * dScale), 0, 0);
        }
        return rctInner;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.event.IPrimitiveRenderer#drawArc(org.eclipse.birt.chart.event.ArcRenderEvent)
     */
    public void drawArc(ArcRenderEvent are) throws ChartException {
        iv.modifyEvent(are);

        // CHECK IF THE LINE ATTRIBUTES ARE CORRECTLY DEFINED
        final LineAttributes lia = are.getOutline();
        if (!validateLineAttributes(are.getSource(), lia)) {
            return;
        }

        // SETUP THE FOREGROUND COLOR (DARKER BACKGROUND IF DEFINED AS NULL)
        final Color cFG = (Color) validateEdgeColor(lia.getColor(), are.getBackground(), _ids);
        if (cFG == null) {
            return;
        }

        // DRAW THE ARC WITH THE SPECIFIED LINE ATTRIBUTES
        final int iOldLineStyle = _gc.getLineStyle();
        final int iOldLineWidth = _gc.getLineWidth();
        int iLineStyle = SWT.LINE_SOLID;
        switch (lia.getStyle().getValue()) {
        case LineStyle.DOTTED:
            iLineStyle = SWT.LINE_DOT;
            break;
        case LineStyle.DASH_DOTTED:
            iLineStyle = SWT.LINE_DASHDOT;
            break;
        case LineStyle.DASHED:
            iLineStyle = SWT.LINE_DASH;
            break;
        }
        _gc.setLineStyle(iLineStyle);
        _gc.setLineWidth(lia.getThickness());
        _gc.setForeground(cFG);

        R31Enhance.setAlpha(_gc, lia.getColor());

        drawArc(_gc, ((SwtDisplayServer) _ids).getDevice(), are, dTranslateX, dTranslateY, dScale);

        _gc.setLineStyle(iOldLineStyle);
        _gc.setLineWidth(iOldLineWidth);
        cFG.dispose();

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.event.IPrimitiveRenderer#fillArc(org.eclipse.birt.chart.event.ArcRenderEvent)
     */
    public void fillArc(ArcRenderEvent are) throws ChartException {
        iv.modifyEvent(are);

        Fill flBackground = validateMultipleFill(are.getBackground());

        if (isFullTransparent(flBackground) || are.getAngleExtent() == 0) {
            return;
        }

        Bounds bo = goFactory.createBounds(are.getTopLeft().getX(), are.getTopLeft().getY(), are.getWidth(),
                are.getHeight());
        final Rectangle r = new Rectangle((int) ((bo.getLeft() + dTranslateX) * dScale),
                (int) ((bo.getTop() + dTranslateY) * dScale), (int) Math.ceil(bo.getWidth() * dScale),
                (int) Math.ceil(bo.getHeight() * dScale));

        Path pt = new Path(((SwtDisplayServer) _ids).getDevice());

        if (are.getInnerRadius() >= 0 && (are.getOuterRadius() > 0 && are.getInnerRadius() < are.getOuterRadius())
                || (are.getInnerRadius() > 0 && are.getOuterRadius() <= 0)) {
            Bounds rctOuter, rctInner;

            rctOuter = getOuterRectangle(are, dTranslateX, dTranslateY, dScale, bo);

            rctInner = getInnerRectangle(are, dTranslateX, dTranslateY, dScale, bo);

            double startAngle = Math.toRadians(-are.getStartAngle());
            double stopAngle = Math.toRadians(-are.getStartAngle() - are.getAngleExtent());

            double xsOuter = (rctOuter.getLeft() + (Math.cos(startAngle) * 0.5 + 0.5) * rctOuter.getWidth());
            double ysOuter = (rctOuter.getTop() + (Math.sin(startAngle) * 0.5 + 0.5) * rctOuter.getHeight());

            double xeInner = (rctInner.getLeft() + (Math.cos(stopAngle) * 0.5 + 0.5) * rctInner.getWidth());
            double yeInner = (rctInner.getTop() + (Math.sin(stopAngle) * 0.5 + 0.5) * rctInner.getHeight());

            pt.addArc((float) rctOuter.getLeft(), (float) rctOuter.getTop(), (float) rctOuter.getWidth(),
                    (float) rctOuter.getHeight(), (float) are.getStartAngle(), (float) are.getAngleExtent());

            pt.lineTo((float) xeInner, (float) yeInner);

            pt.addArc((float) rctInner.getLeft(), (float) rctInner.getTop(), (float) rctInner.getWidth(),
                    (float) rctInner.getHeight(), (float) (are.getStartAngle() + are.getAngleExtent()),
                    (float) -are.getAngleExtent());

            pt.lineTo((float) xsOuter, (float) ysOuter);
        } else {
            if (are.getStyle() == ArcRenderEvent.SECTOR
                    || (are.getStyle() == ArcRenderEvent.CLOSED && Math.abs(are.getAngleExtent()) >= 360)) {
                double xc = ((are.getTopLeft().getX() + dTranslateX + are.getWidth() / 2d) * dScale);
                double yc = ((are.getTopLeft().getY() + dTranslateY + are.getHeight() / 2d) * dScale);

                double xs = 0, ys = 0;
                double angle = Math.toRadians(-are.getStartAngle());

                xs = ((are.getTopLeft().getX() + dTranslateX + (Math.cos(angle) * 0.5 + 0.5) * are.getWidth())
                        * dScale);
                ys = ((are.getTopLeft().getY() + dTranslateY + (Math.sin(angle) * 0.5 + 0.5) * are.getHeight())
                        * dScale);

                if (are.getStyle() == ArcRenderEvent.CLOSED) {
                    pt.addArc((float) ((are.getTopLeft().getX() + dTranslateX) * dScale),
                            (float) ((are.getTopLeft().getY() + dTranslateY) * dScale),
                            (float) (are.getWidth() * dScale), (float) (are.getHeight() * dScale),
                            (float) are.getStartAngle(), (float) are.getAngleExtent());
                    pt.lineTo((float) xs, (float) ys);
                } else if (are.getStyle() == ArcRenderEvent.SECTOR) {
                    pt.addArc((float) ((are.getTopLeft().getX() + dTranslateX) * dScale),
                            (float) ((are.getTopLeft().getY() + dTranslateY) * dScale),
                            (float) (are.getWidth() * dScale), (float) (are.getHeight() * dScale),
                            (float) are.getStartAngle(), (float) are.getAngleExtent());
                    pt.lineTo((float) xc, (float) yc);
                    pt.lineTo((float) xs, (float) ys);
                }
            }

            // Extra fix due to SWT arc rendering limitation.
            else if (are.getStyle() == ArcRenderEvent.OPEN || are.getStyle() == ArcRenderEvent.CLOSED) {
                double angle = Math.toRadians(-are.getStartAngle());

                double xs = ((are.getTopLeft().getX() + dTranslateX
                        + (Math.cos(angle) * 0.5 + 0.5) * are.getWidth()) * dScale);
                double ys = ((are.getTopLeft().getY() + dTranslateY
                        + (Math.sin(angle) * 0.5 + 0.5) * are.getHeight()) * dScale);

                pt.addArc((float) ((are.getTopLeft().getX() + dTranslateX) * dScale),
                        (float) ((are.getTopLeft().getY() + dTranslateY) * dScale),
                        (float) (are.getWidth() * dScale), (float) (are.getHeight() * dScale),
                        (float) are.getStartAngle(), (float) are.getAngleExtent());

                pt.lineTo((float) xs, (float) ys);
            }
        }

        try {
            if (flBackground instanceof ColorDefinition) {
                fillPathColor(pt, (ColorDefinition) flBackground);
            } else if (flBackground instanceof Gradient) {
                fillPathGradient(pt, (Gradient) flBackground, r);
            } else if (flBackground instanceof org.eclipse.birt.chart.model.attribute.Image) {
                fillPathImage(pt, (org.eclipse.birt.chart.model.attribute.Image) flBackground);
            }
        } finally {
            pt.dispose();
        }

    }

    private final void fillPathColor(Path path, ColorDefinition g) throws ChartException {
        // skip full transparency for optimization.
        if (!(g.isSetTransparency() && g.getTransparency() == 0)) {
            final Color cBG = (Color) _ids.getColor(g);
            final Color cPreviousBG = _gc.getBackground();
            _gc.setBackground(cBG);

            R31Enhance.setAlpha(_gc, g);

            _gc.fillPath(path);

            cBG.dispose();
            _gc.setBackground(cPreviousBG);
        }
    }

    private final void fillPathGradient(Path path, Gradient g, Rectangle r) throws ChartException {
        final ColorDefinition cdStart = g.getStartColor();
        final ColorDefinition cdEnd = g.getEndColor();
        double dAngleInDegrees = g.getDirection();

        if (dAngleInDegrees < -90 || dAngleInDegrees > 90) {
            throw new ChartException(ChartDeviceSwtActivator.ID, ChartException.RENDERING,
                    "SwtRendererImpl.exception.gradient.angle", //$NON-NLS-1$
                    new Object[] { new Double(dAngleInDegrees) }, Messages.getResourceBundle(getULocale()));
        }

        final Color cPreviousFG = _gc.getForeground();
        final Color cPreviousBG = _gc.getBackground();
        Color cFG = (Color) _ids.getColor(cdStart);
        Color cBG = (Color) _ids.getColor(cdEnd);

        float x1, y1, x2, y2;

        // #232647
        // The maximal round-off error to calculate x2 and y2 here can be 2.
        // And if the pattern value is less than the forground, it is very obvious.
        // So we add 2 here to overcome this error. 
        final int iMaxError = 2;

        if (dAngleInDegrees == 0) {
            x1 = r.x;
            x2 = r.x + r.width + iMaxError;
            y1 = y2 = r.y;
        } else if (dAngleInDegrees == 90) {
            x1 = x2 = r.x;
            y1 = r.y + r.height + iMaxError;
            y2 = r.y;
        } else if (dAngleInDegrees == -90) {
            x1 = x2 = r.x;
            y1 = r.y;
            y2 = r.y + r.height + iMaxError;
        } else if (dAngleInDegrees > 0) {
            x1 = r.x;
            y1 = r.y + r.height;
            x2 = r.x + r.width + iMaxError;
            y2 = r.y;
        } else {
            x1 = r.x;
            y1 = r.y;
            x2 = r.x + r.width;
            y2 = r.y + r.height;
        }

        _gc.setForeground(cFG);
        _gc.setBackground(cBG);

        R31Enhance.setAlpha(_gc, g);

        Pattern pattern = new Pattern(_gc.getDevice(), x1, y1, x2, y2, cFG, cdStart.getTransparency(), cBG,
                cdEnd.getTransparency());
        _gc.setBackgroundPattern(pattern);
        _gc.fillPath(path);

        _gc.setForeground(cPreviousFG);
        _gc.setBackground(cPreviousBG);
        cFG.dispose();
        cBG.dispose();
        pattern.dispose();
    }

    private final void fillPathImage(Path path, org.eclipse.birt.chart.model.attribute.Image g)
            throws ChartException {
        org.eclipse.swt.graphics.Image img = null;
        if (g instanceof EmbeddedImage) {
            try {
                String imageData = ((EmbeddedImage) g).getData();
                if (imageData != null) {
                    ByteArrayInputStream bis = new ByteArrayInputStream(
                            Base64.decodeBase64(((EmbeddedImage) g).getData().getBytes()));

                    img = new org.eclipse.swt.graphics.Image(((SwtDisplayServer) _ids).getDevice(), bis);
                } else {
                    img = createEmptyImage();
                }
            } catch (Exception ilex) {
                throw new ChartException(ChartDeviceSwtActivator.ID, ChartException.RENDERING, ilex);
            }
        } else if (g instanceof PatternImage) {
            PatternImage patternImage = (PatternImage) g;
            img = createImageFromPattern(patternImage);
        } else {
            if (g.getSource() == ImageSourceType.STATIC) {
                final String sUrl = g.getURL();
                try {
                    img = (org.eclipse.swt.graphics.Image) _ids.loadImage(SecurityUtil.newURL(sUrl));
                } catch (MalformedURLException muex) {
                    throw new ChartException(ChartDeviceSwtActivator.ID, ChartException.RENDERING, muex);
                }
            } else {
                img = createEmptyImage();
            }

        }

        Pattern pattern = new Pattern(_gc.getDevice(), img);
        _gc.setBackgroundPattern(pattern);
        _gc.fillPath(path);

        pattern.dispose();
        img.dispose();
    }

    private Image createEmptyImage() {
        // To render a blank image for null embedded data
        return new org.eclipse.swt.graphics.Image(((SwtDisplayServer) _ids).getDevice(), 10, 10);
    }

    private Image createImageFromPattern(PatternImage patternImage) {
        Device device = ((SwtDisplayServer) _ids).getDevice();

        PaletteData paletteData = new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
        byte[] data = PatternImageUtil.createImageData(patternImage, ByteColorModel.BGRA);

        ImageData imageData = new ImageData(8, 8, 32, paletteData, 4, data);

        return new Image(device, imageData);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.event.IPrimitiveRenderer#enableInteraction(org.eclipse.birt.chart.event.InteractionEvent)
     */
    public void enableInteraction(InteractionEvent iev) throws ChartException {
        if (_iun == null) {
            logger.log(ILogger.INFORMATION,
                    Messages.getString("SwtRendererImpl.exception.missing.component.interaction", getULocale())); //$NON-NLS-1$
            return;
        }

        final Trigger[] tga = iev.getTriggers();
        if (tga == null) {
            return;
        }

        Region clipping = new Region();
        _gc.getClipping(clipping);

        // CREATE AND SETUP THE SHAPES FOR INTERACTION
        TriggerCondition tc;
        List<RegionAction> al;
        final PrimitiveRenderEvent pre = iev.getHotSpot();
        if (pre instanceof PolygonRenderEvent) {
            final Location[] loa = ((PolygonRenderEvent) pre).getPoints();

            for (int i = 0; i < tga.length; i++) {
                tc = tga[i].getCondition();
                al = _lhmAllTriggers.get(tc);
                if (al == null) {
                    al = new ArrayList<RegionAction>(4); // UNDER NORMAL
                    // CONDITIONS
                    _lhmAllTriggers.put(tc, al);
                }
                RegionAction ra = new RegionAction(iev.getStructureSource(), loa, tga[i].getAction(), dTranslateX,
                        dTranslateY, dScale, clipping);
                ra.setCursor(iev.getCursor());
                al.add(0, ra);
            }
        } else if (pre instanceof RectangleRenderEvent) {
            final Bounds bo = ((RectangleRenderEvent) pre).getBounds();

            for (int i = 0; i < tga.length; i++) {
                tc = tga[i].getCondition();
                al = _lhmAllTriggers.get(tc);
                if (al == null) {
                    al = new ArrayList<RegionAction>(4); // UNDER NORMAL
                    // CONDITIONS
                    _lhmAllTriggers.put(tc, al);
                }
                RegionAction ra = new RegionAction(iev.getStructureSource(), bo, tga[i].getAction(), dTranslateX,
                        dTranslateY, dScale, clipping);
                ra.setCursor(iev.getCursor());
                al.add(0, ra);
            }
        } else if (pre instanceof OvalRenderEvent) {
            final Bounds boEllipse = ((OvalRenderEvent) pre).getBounds();

            for (int i = 0; i < tga.length; i++) {
                tc = tga[i].getCondition();
                al = _lhmAllTriggers.get(tc);
                if (al == null) {
                    al = new ArrayList<RegionAction>(4); // UNDER NORMAL
                    // CONDITIONS
                    _lhmAllTriggers.put(tc, al);
                }

                // using rectangle to simulate the oval due to swt limitation.
                RegionAction ra = new RegionAction(iev.getStructureSource(), boEllipse, tga[i].getAction(),
                        dTranslateX, dTranslateY, dScale, clipping);
                ra.setCursor(iev.getCursor());
                al.add(0, ra);
            }
        } else if (pre instanceof ArcRenderEvent) {
            final ArcRenderEvent are = (ArcRenderEvent) pre;
            final Bounds boEllipse = are.getEllipseBounds();
            double dStart = are.getStartAngle();
            double dExtent = are.getAngleExtent();
            int iArcType = are.getStyle();

            for (int i = 0; i < tga.length; i++) {
                tc = tga[i].getCondition();
                al = _lhmAllTriggers.get(tc);
                if (al == null) {
                    al = new ArrayList<RegionAction>(4); // UNDER NORMAL
                    // CONDITIONS
                    _lhmAllTriggers.put(tc, al);
                }

                // using rectangle to simulate the arc due to swt limitation.
                RegionAction ra = new RegionAction(iev.getStructureSource(), boEllipse, dStart, dExtent, iArcType,
                        tga[i].getAction(), dTranslateX, dTranslateY, dScale, clipping);
                ra.setCursor(iev.getCursor());
                al.add(0, ra);
            }
        } else if (pre instanceof AreaRenderEvent) {
            final Bounds bo = ((AreaRenderEvent) pre).getBounds();

            for (int i = 0; i < tga.length; i++) {
                tc = tga[i].getCondition();
                al = _lhmAllTriggers.get(tc);
                if (al == null) {
                    al = new ArrayList<RegionAction>(4); // UNDER NORMAL
                    // CONDITIONS
                    _lhmAllTriggers.put(tc, al);
                }
                RegionAction ra = new RegionAction(iev.getStructureSource(), bo, tga[i].getAction(), dTranslateX,
                        dTranslateY, dScale, clipping);
                ra.setCursor(iev.getCursor());
                al.add(0, ra);
            }
        }

        // free the clip region resource.
        clipping.dispose();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.event.IPrimitiveRenderer#drawArea(org.eclipse.birt.chart.event.AreaRenderEvent)
     */
    public void drawArea(AreaRenderEvent are) throws ChartException {
        iv.modifyEvent(are);

        // CHECK IF THE LINE ATTRIBUTES ARE CORRECTLY DEFINED
        final LineAttributes lia = are.getOutline();
        if (!validateLineAttributes(are.getSource(), lia)) {
            return;
        }

        // SETUP THE FOREGROUND COLOR (DARKER BACKGROUND IF DEFINED AS NULL)
        final Color cFG = (Color) validateEdgeColor(lia.getColor(), are.getBackground(), _ids);
        if (cFG == null) // IF UNDEFINED, EXIT
        {
            return;
        }

        // BUILD THE GENERAL PATH STRUCTURE
        final Path gp = new Path(((SwtDisplayServer) _ids).getDevice());
        PrimitiveRenderEvent pre;
        for (int i = 0; i < are.getElementCount(); i++) {
            pre = are.getElement(i);
            if (pre instanceof ArcRenderEvent) {
                final ArcRenderEvent acre = (ArcRenderEvent) pre;

                gp.addArc((float) acre.getTopLeft().getX(), (float) acre.getTopLeft().getY(),
                        (float) acre.getWidth(), (float) acre.getHeight(), (float) acre.getStartAngle(),
                        (float) acre.getAngleExtent());
            } else if (pre instanceof LineRenderEvent) {
                final LineRenderEvent lre = (LineRenderEvent) pre;
                gp.moveTo((float) lre.getStart().getX(), (float) lre.getStart().getY());
                gp.lineTo((float) lre.getEnd().getX(), (float) lre.getEnd().getY());
            }
        }

        // DRAW THE PATH
        final int iOldLineStyle = _gc.getLineStyle();
        final int iOldLineWidth = _gc.getLineWidth();
        int iLineStyle = SWT.LINE_SOLID;
        switch (lia.getStyle().getValue()) {
        case (LineStyle.DOTTED):
            iLineStyle = SWT.LINE_DOT;
            break;
        case (LineStyle.DASH_DOTTED):
            iLineStyle = SWT.LINE_DASHDOT;
            break;
        case (LineStyle.DASHED):
            iLineStyle = SWT.LINE_DASH;
            break;
        }
        _gc.setLineStyle(iLineStyle);
        _gc.setLineWidth(lia.getThickness());
        _gc.setForeground(cFG);

        R31Enhance.setAlpha(_gc, lia.getColor());

        _gc.drawPath(gp);

        // Restore state
        _gc.setLineStyle(iOldLineStyle);
        _gc.setLineWidth(iOldLineWidth);

        // Free resource
        gp.dispose();
        cFG.dispose();

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.event.IPrimitiveRenderer#fillArea(org.eclipse.birt.chart.event.AreaRenderEvent)
     */
    public void fillArea(AreaRenderEvent are) throws ChartException {
        iv.modifyEvent(are);

        Fill flBackground = validateMultipleFill(are.getBackground());

        if (isFullTransparent(flBackground)) {
            return;
        }

        // BUILD THE GENERAL PATH STRUCTURE
        final Path pt = new Path(((SwtDisplayServer) _ids).getDevice());
        PrimitiveRenderEvent pre;
        for (int i = 0; i < are.getElementCount(); i++) {
            pre = are.getElement(i);
            if (pre instanceof ArcRenderEvent) {
                final ArcRenderEvent acre = (ArcRenderEvent) pre;

                pt.addArc((float) acre.getTopLeft().getX(), (float) acre.getTopLeft().getY(),
                        (float) acre.getWidth(), (float) acre.getHeight(), (float) acre.getStartAngle(),
                        (float) acre.getAngleExtent());
            } else if (pre instanceof LineRenderEvent) {
                final LineRenderEvent lre = (LineRenderEvent) pre;
                if (i == 0) {
                    pt.moveTo((float) lre.getStart().getX(), (float) lre.getStart().getY());
                }
                pt.lineTo((float) lre.getEnd().getX(), (float) lre.getEnd().getY());
            }
        }

        try {
            if (flBackground instanceof ColorDefinition) {
                fillPathColor(pt, (ColorDefinition) flBackground);
            } else if (flBackground instanceof Gradient) {
                final Bounds bo = are.getBounds();
                final Rectangle r = new Rectangle((int) ((bo.getLeft() + dTranslateX) * dScale),
                        (int) ((bo.getTop() + dTranslateY) * dScale), (int) (bo.getWidth() * dScale),
                        (int) (bo.getHeight() * dScale));
                fillPathGradient(pt, (Gradient) flBackground, r);
            } else if (flBackground instanceof org.eclipse.birt.chart.model.attribute.Image) {
                fillPathImage(pt, (org.eclipse.birt.chart.model.attribute.Image) flBackground);
            }
        } finally {
            pt.dispose();
        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.event.IPrimitiveRenderer#drawOval(org.eclipse.birt.chart.event.OvalRenderEvent)
     */
    public void drawOval(OvalRenderEvent ore) throws ChartException {
        iv.modifyEvent(ore);

        // CHECK IF THE LINE ATTRIBUTES ARE CORRECTLY DEFINED
        final LineAttributes lia = ore.getOutline();
        if (!validateLineAttributes(ore.getSource(), lia)) {
            return;
        }

        // SETUP THE FOREGROUND COLOR (DARKER BACKGROUND IF DEFINED AS NULL)
        final Color cFG = (Color) validateEdgeColor(lia.getColor(), ore.getBackground(), _ids);
        if (cFG == null) {
            return;
        }

        // DRAW THE OVAL WITH THE SPECIFIED LINE ATTRIBUTES
        final int iOldLineStyle = _gc.getLineStyle();
        final int iOldLineWidth = _gc.getLineWidth();
        int iLineStyle = SWT.LINE_SOLID;
        switch (lia.getStyle().getValue()) {
        case (LineStyle.DOTTED):
            iLineStyle = SWT.LINE_DOT;
            break;
        case (LineStyle.DASH_DOTTED):
            iLineStyle = SWT.LINE_DASHDOT;
            break;
        case (LineStyle.DASHED):
            iLineStyle = SWT.LINE_DASH;
            break;
        }
        _gc.setLineStyle(iLineStyle);
        _gc.setLineWidth(lia.getThickness());
        final Bounds bo = ore.getBounds();
        _gc.setForeground(cFG);

        R31Enhance.setAlpha(_gc, lia.getColor());

        _gc.drawOval((int) ((bo.getLeft() + dTranslateX) * dScale), (int) ((bo.getTop() + dTranslateY) * dScale),
                (int) (bo.getWidth() * dScale), (int) (bo.getHeight() * dScale));

        _gc.setLineStyle(iOldLineStyle);
        _gc.setLineWidth(iOldLineWidth);
        cFG.dispose();

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.event.IPrimitiveRenderer#fillOval(org.eclipse.birt.chart.event.OvalRenderEvent)
     */
    public void fillOval(OvalRenderEvent ore) throws ChartException {
        iv.modifyEvent(ore);

        final Fill flBackground = validateMultipleFill(ore.getBackground());

        if (isFullTransparent(flBackground)) {
            return;
        }

        final Bounds bo = ore.getBounds();
        final Rectangle r = new Rectangle((int) ((bo.getLeft() + dTranslateX) * dScale),
                (int) ((bo.getTop() + dTranslateY) * dScale), (int) (bo.getWidth() * dScale),
                (int) (bo.getHeight() * dScale));
        Path pt = new Path(((SwtDisplayServer) _ids).getDevice());
        pt.addArc(r.x, r.y, r.width, r.height, 0, 360);

        try {
            if (flBackground instanceof ColorDefinition) {
                fillPathColor(pt, (ColorDefinition) flBackground);
            } else if (flBackground instanceof Gradient) {
                fillPathGradient(pt, (Gradient) flBackground, r);
            } else if (flBackground instanceof org.eclipse.birt.chart.model.attribute.Image) {
                fillPathImage(pt, (org.eclipse.birt.chart.model.attribute.Image) flBackground);
            }
        } finally {
            pt.dispose();
        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.event.IPrimitiveRenderer#drawText(org.eclipse.birt.chart.event.TextRenderEvent)
     */
    public void drawText(TextRenderEvent tre) throws ChartException {
        String fontName = convertFont(tre.getLabel().getCaption().getFont().getName());
        if (fontName != null) {
            tre.getLabel().getCaption().getFont().setName(fontName);
        }

        iv.modifyEvent(tre);
        if (!tre.getLabel().isVisible())
            return;

        switch (tre.getAction()) {
        case TextRenderEvent.UNDEFINED:
            throw new ChartException(ChartDeviceSwtActivator.ID, ChartException.RENDERING,
                    "SwtRendererImpl.exception.unspecified.text.rendering.action", //$NON-NLS-1$
                    Messages.getResourceBundle(getULocale()));

        case TextRenderEvent.RENDER_SHADOW_AT_LOCATION:
            Location lo = tre.getLocation().copyInstance();
            lo.translate(dTranslateX, dTranslateY);
            lo.scale(dScale);
            _tr.renderShadowAtLocation(this, tre.getTextPosition(), lo, tre.getLabel());
            break;

        case TextRenderEvent.RENDER_TEXT_AT_LOCATION:
            lo = tre.getLocation().copyInstance();
            lo.translate(dTranslateX, dTranslateY);
            lo.scale(dScale);

            _tr.renderTextAtLocation(this, tre.getTextPosition(), lo, tre.getLabel());
            break;

        case TextRenderEvent.RENDER_TEXT_IN_BLOCK:
            final Bounds bo = goFactory.copyOf(tre.getBlockBounds());
            bo.translate(dTranslateX, dTranslateY);
            bo.scale(dScale);

            _tr.renderTextInBlock(this, bo, tre.getBlockAlignment(), tre.getLabel());
            break;
        }

    }

    /**
     * Converts an array of high-res co-ordinates into a single dimensional
     * integer array that represents consecutive X/Y co-ordinates associated
     * with a polygon's vertices as required in SWT.
     * 
     * @param la
     * @return int array
     */
    static final int[] getCoordinatesAsInts(Location[] la, int iRoundingStyle, double dTranslateX,
            double dTranslateY, double dScale) {
        return convertDoubleToInt(getDoubleCoordinatesAsInts(la, iRoundingStyle, dTranslateX, dTranslateY, dScale));
    }

    /**
     * Converts an array of high-res co-ordinates into a single dimensional
     * double array that represents consecutive X/Y co-ordinates associated
     * with a polygon's vertices as required in SWT.
     * 
     * @param la
     * @return double array
     */
    static final double[] getDoubleCoordinatesAsInts(Location[] la, int iRoundingStyle, double dTranslateX,
            double dTranslateY, double dScale) {
        final int n = la.length * 2;
        final double[] iaXY = new double[n];

        if (iRoundingStyle == CEIL) {
            for (int i = 0; i < n / 2; i++) {
                iaXY[2 * i] = Math.ceil((la[i].getX() + dTranslateX) * dScale);
                iaXY[2 * i + 1] = Math.ceil((la[i].getY() + dTranslateY) * dScale);
            }
        } else if (iRoundingStyle == TRUNCATE) {
            for (int i = 0; i < n / 2; i++) {
                iaXY[2 * i] = ((la[i].getX() + dTranslateX) * dScale);
                iaXY[2 * i + 1] = ((la[i].getY() + dTranslateY) * dScale);
            }
        }

        return iaXY;
    }

    static final float[] convertDoubleToFloat(double[] da) {
        if (da == null) {
            return null;
        }
        final float[] fa = new float[da.length];
        for (int i = 0; i < fa.length; i++) {
            fa[i] = (float) da[i];
        }
        return fa;
    }

    static final int[] convertDoubleToInt(double[] da) {
        if (da == null) {
            return null;
        }
        final int[] fa = new int[da.length];
        for (int i = 0; i < fa.length; i++) {
            fa[i] = (int) da[i];
        }
        return fa;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.device.IPrimitiveRenderer#applyTransformation(org.eclipse.birt.chart.event.TransformationEvent)
     */
    public void applyTransformation(TransformationEvent tev) throws ChartException {
        // NOTE: Transformations are accumulated
        switch (tev.getTransform()) {
        case TransformationEvent.TRANSLATE:
            dTranslateX += tev.getTranslateX();
            dTranslateY += tev.getTranslateY();
            break;

        case TransformationEvent.ROTATE:
            dRotateInDegrees += tev.getRotation();
            break;

        // Currently not used
        case TransformationEvent.SCALE:
            dScale *= tev.getScale();
            ((SwtDisplayServer) _ids).setScale(dScale);
            break;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.device.IDeviceRenderer#start()
     */
    public void before() throws ChartException {
        // Clean previous status.
        cleanUpTriggers();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.device.IDeviceRenderer#end()
     */
    public void after() throws ChartException {
        // USED BY SUBCLASSES IF NEEDED
    }

    private void cleanUpTriggers() {
        for (Iterator<List<RegionAction>> itr = _lhmAllTriggers.values().iterator(); itr.hasNext();) {
            List<RegionAction> ralist = itr.next();

            if (ralist != null) {
                for (Iterator<RegionAction> sitr = ralist.iterator(); sitr.hasNext();) {
                    RegionAction ra = sitr.next();
                    ra.dispose();
                }
            }
        }

        _lhmAllTriggers.clear();
    }

    /**
     * Free all allocated system resources.
     */
    public void dispose() {
        cleanUpTriggers();

        if (_iun != null) {
            Object obj = _iun.peerInstance();

            if (obj instanceof Composite) {
                Composite jc = (Composite) obj;

                if (_eh != null) {
                    if (!jc.isDisposed()) {
                        // We can't promise to remove all the old
                        // swtEventHandler
                        // due to SWT limitation here, so be sure to just attach
                        // the
                        // update_notifier only to one renderer.

                        jc.removeMouseListener(_eh);
                        jc.removeMouseMoveListener(_eh);
                        jc.removeMouseTrackListener(_eh);
                        jc.removeKeyListener(_eh);
                        jc.removeFocusListener(_eh);
                    }

                    _eh.dispose();
                    _eh = null;
                }
            }
        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.chart.device.IDeviceRenderer#setProperty(java.lang.String,
     *      java.lang.Object)
     */
    public final void setProperty(final String sProperty, final Object oValue) {
        if (sProperty.equals(IDeviceRenderer.UPDATE_NOTIFIER)) {
            _iun = (IUpdateNotifier) oValue;
            iv.reset();
            iv.setUpdateNotifier(_iun);

            cleanUpTriggers();
            Object obj = _iun.peerInstance();

            if (obj instanceof Composite) {
                Composite jc = (Composite) obj;

                if (_eh != null) {
                    // We can't promise to remove all the old swtEventHandler
                    // due to SWT limitation here, so be sure to just attach the
                    // update_notifier only to one renderer.

                    jc.removeMouseListener(_eh);
                    jc.removeMouseMoveListener(_eh);
                    jc.removeMouseTrackListener(_eh);
                    jc.removeKeyListener(_eh);
                    jc.removeFocusListener(_eh);

                    _eh.dispose();
                }

                _eh = new SwtEventHandler(iv, _lhmAllTriggers, _iun, getULocale());

                jc.addMouseListener(_eh);
                jc.addMouseMoveListener(_eh);
                jc.addMouseTrackListener(_eh);
                jc.addKeyListener(_eh);
                jc.addFocusListener(_eh);
            }
        } else if (sProperty.equals(IDeviceRenderer.GRAPHICS_CONTEXT)) {
            _gc = (GC) oValue;

            if (R31Enhance.isR31Available()) {
                Region rg = new Region();
                _gc.getClipping(rg);

                R31Enhance.setAdvanced(_gc, true, rg);
                R31Enhance.setAntialias(_gc, SWT.ON);
                R31Enhance.setTextAntialias(_gc, SWT.ON);

                rg.dispose();
            }
            _ids.setGraphicsContext(_gc);

            logger.log(ILogger.INFORMATION, Messages.getString("SwtRendererImpl.info.graphics.context", //$NON-NLS-1$
                    new Object[] { _gc.getClass().getName(), _gc }, getULocale()));
        } else if (sProperty.equals(IDeviceRenderer.DPI_RESOLUTION)) {
            getDisplayServer().setDpiResolution(((Integer) oValue).intValue());
        } else if (sProperty.equals(IDeviceRenderer.EXPECTED_BOUNDS)) {
            Bounds bo = (Bounds) oValue;
            int x = (int) Math.round(bo.getLeft());
            int y = (int) Math.round(bo.getTop());
            int width = (int) Math.round(bo.getWidth());
            int height = (int) Math.round(bo.getHeight());
            this._gc.setClipping(x, y, width, height);
        }
    }

    /**
     * Make bounds height/width always positive.
     * 
     * @param bo
     * @return
     */
    protected static final Bounds normalizeBounds(Bounds bo) {
        if (bo.getHeight() < 0) {
            bo.setTop(bo.getTop() + bo.getHeight());
            bo.setHeight(-bo.getHeight());
        }

        if (bo.getWidth() < 0) {
            bo.setLeft(bo.getLeft() + bo.getWidth());
            bo.setWidth(-bo.getWidth());
        }

        return bo;
    }

    @Override
    protected String convertFont(String fontFamily) {
        return FontUtil.getFontFamily(fontFamily);
    }

}