gt: 						shape[index++] = y + height + left[2*i+1] - 1;
context: /*******************************************************************************
   * Copyright (c) 2000, 2015 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
   *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 455263
   *******************************************************************************/
  package org.eclipse.swt.custom;
  
  import org.eclipse.swt.*;
  import org.eclipse.swt.graphics.*;
  import org.eclipse.swt.widgets.*;
  
  /**
   * Instances of this class provide all of the measuring and drawing functionality 
   * required by <code>CTabFolder</code>. This class can be subclassed in order to
   * customize the look of a CTabFolder.
   *
   * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
   * @since 3.6
   */
  public class CTabFolderRenderer {
  	
  	protected CTabFolder parent;
  	
  	int[] curve;
  	int[] topCurveHighlightStart;
  	int[] topCurveHighlightEnd;
  	int curveWidth = 0;
  	int curveIndent = 0;
  	int lastTabHeight = -1;
  	
  	Color fillColor;
  	/* Selected item appearance */
  	Color selectionHighlightGradientBegin = null;  //null == no highlight
  	//Although we are given new colours all the time to show different states (active, etc),
  	//some of which may have a highlight and some not, we'd like to retain the highlight colours
  	//as a cache so that we can reuse them if we're again told to show the highlight.
  	//We are relying on the fact that only one tab state usually gets a highlight, so only
  	//a single cache is required. If that happens to not be true, cache simply becomes less effective,
  	//but we don't leak colours.
  	Color[] selectionHighlightGradientColorsCache = null;  //null is a legal value, check on access
  	/* Colors for anti-aliasing */
  	Color selectedOuterColor = null;
  	Color selectedInnerColor = null;
  	Color tabAreaColor = null;
  	/* 
  	 * Border color that was used in computing the cached anti-alias Colors.
  	 * We have to recompute the colors if the border color changes
  	 */
  	Color lastBorderColor = null;
  	
  	//TOP_LEFT_CORNER_HILITE is laid out in reverse (ie. top to bottom)
  	//so can fade in same direction as right swoop curve
  	static final int[] TOP_LEFT_CORNER_HILITE = new int[] {5,2, 4,2, 3,3, 2,4, 2,5, 1,6};
  
  	static final int[] TOP_LEFT_CORNER = new int[] {0,6, 1,5, 1,4, 4,1, 5,1, 6,0};
  	static final int[] TOP_RIGHT_CORNER = new int[] {-6,0, -5,1, -4,1, -1,4, -1,5, 0,6};
  	static final int[] BOTTOM_LEFT_CORNER = new int[] {0,-6, 1,-5, 1,-4, 4,-1, 5,-1, 6,0};
  	static final int[] BOTTOM_RIGHT_CORNER = new int[] {-6,0, -5,-1, -4,-1, -1,-4, -1,-5, 0,-6};
  
  	static final int[] SIMPLE_TOP_LEFT_CORNER = new int[] {0,2, 1,1, 2,0};
  	static final int[] SIMPLE_TOP_RIGHT_CORNER = new int[] {-2,0, -1,1, 0,2};
  	static final int[] SIMPLE_BOTTOM_LEFT_CORNER = new int[] {0,-2, 1,-1, 2,0};
  	static final int[] SIMPLE_BOTTOM_RIGHT_CORNER = new int[] {-2,0, -1,-1, 0,-2};
  	static final int[] SIMPLE_UNSELECTED_INNER_CORNER = new int[] {0,0};
  
  	static final int[] TOP_LEFT_CORNER_BORDERLESS = new int[] {0,6, 1,5, 1,4, 4,1, 5,1, 6,0};
  	static final int[] TOP_RIGHT_CORNER_BORDERLESS = new int[] {-7,0, -6,1, -5,1, -2,4, -2,5, -1,6};
  	static final int[] BOTTOM_LEFT_CORNER_BORDERLESS = new int[] {0,-6, 1,-6, 1,-5, 2,-4, 4,-2, 5,-1, 6,-1, 6,0};
  	static final int[] BOTTOM_RIGHT_CORNER_BORDERLESS = new int[] {-7,0, -7,-1, -6,-1, -5,-2, -3,-4, -2,-5, -2,-6, -1,-6};
  
  	static final int[] SIMPLE_TOP_LEFT_CORNER_BORDERLESS = new int[] {0,2, 1,1, 2,0};
  	static final int[] SIMPLE_TOP_RIGHT_CORNER_BORDERLESS= new int[] {-3,0, -2,1, -1,2};
  	static final int[] SIMPLE_BOTTOM_LEFT_CORNER_BORDERLESS = new int[] {0,-3, 1,-2, 2,-1, 3,0};
  	static final int[] SIMPLE_BOTTOM_RIGHT_CORNER_BORDERLESS = new int[] {-4,0, -3,-1, -2,-2, -1,-3};
  	
  	static final RGB CLOSE_FILL = new RGB(252, 160, 160);
  	
  	static final int BUTTON_SIZE = 16;
  	static final int BUTTON_TRIM = 1;
  	
  	static final int BUTTON_BORDER = SWT.COLOR_WIDGET_DARK_SHADOW;
  	static final int BUTTON_FILL = SWT.COLOR_LIST_BACKGROUND;
  	static final int BORDER1_COLOR = SWT.COLOR_WIDGET_NORMAL_SHADOW;
  	
  	static final int ITEM_TOP_MARGIN = 2;
  	static final int ITEM_BOTTOM_MARGIN = 2;
  	static final int ITEM_LEFT_MARGIN = 4;
  	static final int ITEM_RIGHT_MARGIN = 4;
  	static final int INTERNAL_SPACING = 4;
  	static final int FLAGS = SWT.DRAW_TRANSPARENT | SWT.DRAW_MNEMONIC;
  	static final String ELLIPSIS = "..."; //$NON-NLS-1$ 
  	
  	//Part constants
  	/**
  	 * Part constant indicating the body of the tab folder. The body is the
  	 * underlying container for all of the tab folder and all other parts are
  	 * drawn on top of it. (value is -1).
  	 *
  	 * @see #computeSize(int, int, GC, int, int)
  	 * @see #computeTrim(int, int, int, int, int, int)
  	 * @see #draw(int, int, Rectangle, GC)
  	 */
  	public static final int PART_BODY = -1;
  	/**
  	 * Part constant indicating the tab header of the folder (value is -2). The
  	 * header is drawn on top of the body and provides an area for the tabs and
  	 * other tab folder buttons to be rendered.
  	 *
  	 * @see #computeSize(int, int, GC, int, int)
  	 * @see #computeTrim(int, int, int, int, int, int)
  	 * @see #draw(int, int, Rectangle, GC)
  	 */
  	public static final int PART_HEADER = -2;
  	/**
  	 * Part constant indicating the border of the tab folder. (value is -3). The
  	 * border is drawn around the body and is part of the body trim.
  	 *
  	 * @see #computeSize(int, int, GC, int, int)
  	 * @see #computeTrim(int, int, int, int, int, int)
  	 * @see #draw(int, int, Rectangle, GC)
  	 */
  	public static final int PART_BORDER = -3;
  	/**
  	 * Part constant indicating the background of the tab folder. (value is -4).
  	 *
  	 * @see #computeSize(int, int, GC, int, int)
  	 * @see #computeTrim(int, int, int, int, int, int)
  	 * @see #draw(int, int, Rectangle, GC)
  	 */
  	public static final int PART_BACKGROUND = -4;
  	/**
  	 * Part constant indicating the maximize button of the tab folder. (value is
  	 * -5).
  	 *
  	 * @see #computeSize(int, int, GC, int, int)
  	 * @see #computeTrim(int, int, int, int, int, int)
  	 * @see #draw(int, int, Rectangle, GC)
  	 */
  	public static final int PART_MAX_BUTTON = -5;
  	/**
  	 * Part constant indicating the minimize button of the tab folder. (value is
  	 * -6).
  	 *
  	 * @see #computeSize(int, int, GC, int, int)
  	 * @see #computeTrim(int, int, int, int, int, int)
  	 * @see #draw(int, int, Rectangle, GC)
  	 */
  	public static final int PART_MIN_BUTTON = -6;
  	/**
  	 * Part constant indicating the chevron button of the tab folder. (value is
  	 * -7).
  	 *
  	 * @see #computeSize(int, int, GC, int, int)
  	 * @see #computeTrim(int, int, int, int, int, int)
  	 * @see #draw(int, int, Rectangle, GC)
  	 */
  	public static final int PART_CHEVRON_BUTTON = -7;
  	/**
  	 * Part constant indicating the close button of a tab item. (value is -8).
  	 *
  	 * @see #computeSize(int, int, GC, int, int)
  	 * @see #computeTrim(int, int, int, int, int, int)
  	 * @see #draw(int, int, Rectangle, GC)
  	 */
  	public static final int PART_CLOSE_BUTTON = -8;
  
  	public static final int MINIMUM_SIZE = 1 << 24; //TODO: Should this be a state?
  
  
  	/**
  	 * Constructs a new instance of this class given its parent.
  	 * 
  	 * @param parent CTabFolder
  	 *
  	 * @exception IllegalArgumentException <ul>
  	 *    <li>ERROR_INVALID_ARGUMENT - if the parent is disposed</li>
  	 * </ul>
  	 * 
  	 * @see Widget#getStyle
  	 */
  	protected CTabFolderRenderer(CTabFolder parent) {
  		if (parent == null) return;
  		if (parent.isDisposed ()) SWT.error (SWT.ERROR_INVALID_ARGUMENT);
  		this.parent = parent;
  	}
  	
  	void antialias (int[] shape, Color innerColor, Color outerColor, GC gc){
  		// Don't perform anti-aliasing on Mac because the platform
  		// already does it.  The simple style also does not require anti-aliasing.
  		if (parent.simple) return;
  		String platform = SWT.getPlatform();
  		if ("cocoa".equals(platform)) return; //$NON-NLS-1$
  		// Don't perform anti-aliasing on low resolution displays
  		if (parent.getDisplay().getDepth() < 15) return;
  		if (outerColor != null) {
  			int index = 0;
  			boolean left = true;
  			int oldY = parent.onBottom ? 0 : parent.getSize().y;
  			int[] outer = new int[shape.length];
  			for (int i = 0; i < shape.length/2; i++) {
  				if (left && (index + 3 < shape.length)) {
  					left = parent.onBottom ? oldY <= shape[index+3] : oldY >= shape[index+3];
  					oldY = shape[index+1];
  				}
  				outer[index] = shape[index++] + (left ? -1 : +1);
  				outer[index] = shape[index++];
  			}
  			gc.setForeground(outerColor);
  			gc.drawPolyline(outer);
  		}
  		if (innerColor != null) {
  			int[] inner = new int[shape.length];
  			int index = 0;
  			boolean left = true;
  			int oldY = parent.onBottom ? 0 : parent.getSize().y;
  			for (int i = 0; i < shape.length/2; i++) {
  				if (left && (index + 3 < shape.length)) {
  					left = parent.onBottom ? oldY <= shape[index+3] : oldY >= shape[index+3];
  					oldY = shape[index+1];
  				}
  				inner[index] = shape[index++] + (left ? +1 : -1);
  				inner[index] = shape[index++];
  			}
  			gc.setForeground(innerColor);
  			gc.drawPolyline(inner);
  		}
  	}
  
  	/**
  	 * Returns the preferred size of a part.
  	 * <p>
  	 * The <em>preferred size</em> of a part is the size that it would
  	 * best be displayed at. The width hint and height hint arguments
  	 * allow the caller to ask a control questions such as "Given a particular
  	 * width, how high does the part need to be to show all of the contents?"
  	 * To indicate that the caller does not wish to constrain a particular 
  	 * dimension, the constant <code>SWT.DEFAULT</code> is passed for the hint. 
  	 * </p><p>
  	 * The <code>part</code> value indicated what component the preferred size is 
  	 * to be calculated for. Valid values are any of the part constants:
  	 * <ul> 
  	 * <li>PART_BODY</li>
  	 * <li>PART_HEADER</li> 
  	 * <li>PART_BORDER</li>
  	 * <li>PART_BACKGROUND</li> 
  	 * <li>PART_MAX_BUTTON</li> 
  	 * <li>PART_MIN_BUTTON</li> 
  	 * <li>PART_CHEVRON_BUTTON</li>
  	 * <li>PART_CLOSE_BUTTON</li> 
  	 * <li>A positive integer which is the index of an item in the CTabFolder.</li>
  	 * </ul>
  	 * </p>
  	 * <p>
  	 * The <code>state</code> parameter may be one of the following: 
  	 * <ul>
  	 * <li>SWT.NONE</li>
  	 * <li>SWT.SELECTED - whether the part is selected</li>
  	 * </ul>
  	 * </p>
  	 * @param part a part constant 
  	 * @param state current state 
  	 * @param gc the gc to use for measuring
  	 * @param wHint the width hint (can be <code>SWT.DEFAULT</code>)
  	 * @param hHint the height hint (can be <code>SWT.DEFAULT</code>)
  	 * @return the preferred size of the part
  	 * 
  	 * @since 3.6
  	 */
  	protected Point computeSize (int part, int state, GC gc, int wHint, int hHint) {
  		int width = 0, height = 0; 
  		switch (part) {
  			case PART_HEADER:
  				if (parent.fixedTabHeight != SWT.DEFAULT) {
  					height = parent.fixedTabHeight == 0 ? 0 : parent.fixedTabHeight + 1; // +1 for line drawn across top of tab
  				} else {
  					CTabItem[] items = parent.items;
  					if (items.length == 0) {
  						height = gc.textExtent("Default", FLAGS).y + ITEM_TOP_MARGIN + ITEM_BOTTOM_MARGIN; //$NON-NLS-1$
  					} else {
  						for (int i=0; i < items.length; i++) {
  							height = Math.max(height, computeSize(i, SWT.NONE, gc, wHint, hHint).y);
  						}
  					}
  					gc.dispose();
  				}
  				break;
  			case PART_MAX_BUTTON:
  			case PART_MIN_BUTTON:
  			case PART_CLOSE_BUTTON:
  				width = height = BUTTON_SIZE;
  				break;
  			case PART_CHEVRON_BUTTON:
  				width = 3*BUTTON_SIZE/2;
  				height = BUTTON_SIZE;
  				break;
  			default:
  				if (0 <= part && part < parent.getItemCount()) {
  					updateCurves();
  					CTabItem item = parent.items[part]; 
  					if (item.isDisposed()) return new Point(0,0);
  					Image image = item.getImage();
  					if (image != null && !image.isDisposed()) {
  						Rectangle bounds = image.getBounds();
  						if ((state & SWT.SELECTED) != 0 || parent.showUnselectedImage) {
  							width += bounds.width;
  						}
  						height =  bounds.height;
  					}
  					String text = null;
  					if ((state & MINIMUM_SIZE) != 0) {
  						int minChars = parent.minChars;
  						text = minChars == 0 ? null : item.getText();
  						if (text != null && text.length() > minChars) {
  							if (useEllipses()) {
  								int end = minChars < ELLIPSIS.length() + 1 ? minChars : minChars - ELLIPSIS.length();
  								text = text.substring(0, end);
  								if (minChars > ELLIPSIS.length() + 1) text += ELLIPSIS;
  							} else {
  								int end = minChars;
  								text = text.substring(0, end);
  							}
  						}
  					} else {
  						text = item.getText();
  					}
  					if (text != null) {
  						if (width > 0) width += INTERNAL_SPACING;
  						if (item.font == null) {
  							Point size = gc.textExtent(text, FLAGS);
  							width += size.x;
  							height = Math.max(height, size.y);
  						} else {
  							Font gcFont = gc.getFont();
  							gc.setFont(item.font);
  							Point size = gc.textExtent(text, FLAGS);
  							width += size.x;
  							height = Math.max(height, size.y);
  							gc.setFont(gcFont);
  						}
  					}
  					if (parent.showClose || item.showClose) {
  						if ((state & SWT.SELECTED) != 0 || parent.showUnselectedClose) {
  							if (width > 0) width += INTERNAL_SPACING;
  							width += computeSize(PART_CLOSE_BUTTON, SWT.NONE, gc, SWT.DEFAULT, SWT.DEFAULT).x;
  						}
  					}	
  				}
  				break;
  		}
  		Rectangle trim = computeTrim(part, state, 0, 0, width, height);
  		width = trim.width;
  		height = trim.height;
  		return new Point(width, height);
  	}
  
  	/**
  	 * Given a desired <em>client area</em> for the part
  	 * (as described by the arguments), returns the bounding
  	 * rectangle which would be required to produce that client
  	 * area.
  	 * <p>
  	 * In other words, it returns a rectangle such that, if the
  	 * part's bounds were set to that rectangle, the area
  	 * of the part which is capable of displaying data
  	 * (that is, not covered by the "trimmings") would be the
  	 * rectangle described by the arguments (relative to the
  	 * receiver's parent).
  	 * </p>
  	 * 
  	 * @param part one of the part constants 
  	 * @param state the state of the part
  	 * @param x the desired x coordinate of the client area
  	 * @param y the desired y coordinate of the client area
  	 * @param width the desired width of the client area
  	 * @param height the desired height of the client area
  	 * @return the required bounds to produce the given client area
  	 *
  	 * @see CTabFolderRenderer#computeSize(int, int, GC, int, int) valid part and state values
  	 *  
  	 * @since 3.6
  	 */
  	protected Rectangle computeTrim (int part, int state, int x, int y, int width, int height) {
  		int borderLeft = parent.borderVisible ? 1 : 0;
  		int borderRight = borderLeft;
  		int borderTop = parent.onBottom ? borderLeft : 0;
  		int borderBottom = parent.onBottom ? 0 : borderLeft;
  		int tabHeight = parent.tabHeight;
  		switch (part) {
  			case PART_BODY:
  				int style = parent.getStyle();
  				int highlight_header = (style & SWT.FLAT) != 0 ? 1 : 3;
  				int highlight_margin = (style & SWT.FLAT) != 0 ? 0 : 2;
  				if (parent.fixedTabHeight == 0 && (style & SWT.FLAT) != 0 && (style & SWT.BORDER) == 0) {
  					highlight_header = 0;	
  				}
  				int marginWidth = parent.marginWidth;
  				int marginHeight = parent.marginHeight;
  				x = x - marginWidth - highlight_margin - borderLeft;
  				width = width + borderLeft + borderRight + 2*marginWidth + 2*highlight_margin;
  				if (parent.minimized) {
  					y = parent.onBottom ? y - borderTop : y - highlight_header - tabHeight - borderTop;
  					height = borderTop + borderBottom + tabHeight + highlight_header;
  				} else {
  					y = parent.onBottom ? y - marginHeight - highlight_margin - borderTop : y - marginHeight - highlight_header - tabHeight - borderTop;
  					height = height + borderTop + borderBottom + 2*marginHeight + tabHeight + highlight_header + highlight_margin;
  				}
  				break;
  			case PART_HEADER:
  				//no trim 
  				break;
  			case PART_MAX_BUTTON:
  			case PART_MIN_BUTTON:
  			case PART_CLOSE_BUTTON:
  			case PART_CHEVRON_BUTTON:
  				x -= BUTTON_TRIM;
  				y -= BUTTON_TRIM;
  				width += BUTTON_TRIM*2;
  				height += BUTTON_TRIM*2;
  				break;
  			case PART_BORDER:
  				x = x - borderLeft;
  				width = width + borderLeft + borderRight; 
  				if (!parent.simple) width += 2; // TOP_RIGHT_CORNER needs more space
  				y = y - borderTop;
  				height = height + borderTop + borderBottom;
  				break;
  			default:
  				if (0 <= part && part < parent.getItemCount()) {
  					updateCurves();
  					x = x - ITEM_LEFT_MARGIN;
  					width = width + ITEM_LEFT_MARGIN + ITEM_RIGHT_MARGIN;
  					if (!parent.simple && !parent.single && (state & SWT.SELECTED) != 0) {
  						width += curveWidth - curveIndent;
  					}
  					y = y - ITEM_TOP_MARGIN;
  					height = height + ITEM_TOP_MARGIN + ITEM_BOTTOM_MARGIN;
  				}
  				break;
  		}
  		return new Rectangle(x, y, width, height);
  	}
  	
  	void createAntialiasColors() {
  	    disposeAntialiasColors();
  	    lastBorderColor = parent.getDisplay().getSystemColor(BORDER1_COLOR);
  	    RGB lineRGB = lastBorderColor.getRGB();
  	    /* compute the selected color */
  	    RGB innerRGB = parent.selectionBackground.getRGB();
  	    if (parent.selectionBgImage != null || 
  		    (parent.selectionGradientColors != null && parent.selectionGradientColors.length > 1)) {
  		    innerRGB = null;
  	    }
  	    RGB outerRGB = parent.getBackground().getRGB();		
  	    if (parent.gradientColors != null && parent.gradientColors.length > 1) {
  		    outerRGB = null;
  	    }
  	    if (outerRGB != null) {
  			RGB from = lineRGB;
  			RGB to = outerRGB;
  			int red = from.red + 2*(to.red - from.red)/3;
  			int green = from.green + 2*(to.green - from.green)/3;
  			int blue = from.blue + 2*(to.blue - from.blue)/3;
  			selectedOuterColor = new Color(parent.getDisplay(), red, green, blue);
  	    }
  	    if (innerRGB != null) {
  			RGB from = lineRGB;
  			RGB to = innerRGB;
  			int red = from.red + 2*(to.red - from.red)/3;
  			int green = from.green + 2*(to.green - from.green)/3;
  			int blue = from.blue + 2*(to.blue - from.blue)/3;
  			selectedInnerColor = new Color(parent.getDisplay(), red, green, blue);
  	    }
  	    /* compute the tabArea color */
  	    outerRGB = parent.getParent().getBackground().getRGB();
  	    if (outerRGB != null) {
  			RGB from = lineRGB;
  			RGB to = outerRGB;
  			int red = from.red + 2*(to.red - from.red)/3;
  			int green = from.green + 2*(to.green - from.green)/3;
  			int blue = from.blue + 2*(to.blue - from.blue)/3;
  			tabAreaColor = new Color(parent.getDisplay(), red, green, blue);
  	    }
  	}
  
  	/*
  	 * Allocate colors for the highlight line.
  	 * Colours will be a gradual blend ranging from to.
  	 * Blend length will be tab height.
  	 * Recompute this if tab height changes.
  	 * Could remain null if there'd be no gradient (start=end or low colour display)
  	 */
  	void createSelectionHighlightGradientColors(Color start) {
  		disposeSelectionHighlightGradientColors(); //dispose if existing
  
  		if(start == null)  //shouldn't happen but just to be safe
  			return;
  
  		//alloc colours for entire height to ensure it matches wherever we stop drawing
  		int fadeGradientSize = parent.tabHeight;
  
  		RGB from = start.getRGB();
  		RGB to = parent.selectionBackground.getRGB();
  
  		selectionHighlightGradientColorsCache = new Color[fadeGradientSize];
  		int denom = fadeGradientSize - 1;
  
  		for (int i = 0; i < fadeGradientSize; i++) {
  			int propFrom = denom - i;
  			int propTo = i;
  			int red = (to.red * propTo + from.red * propFrom) / denom;
  			int green = (to.green * propTo  + from.green * propFrom) / denom;
  			int blue = (to.blue * propTo  + from.blue * propFrom) / denom;
  			selectionHighlightGradientColorsCache[i] = new Color(parent.getDisplay(), red, green, blue);
  		}
  	}
  	
  	/**
  	 * Dispose of any operating system resources associated with
  	 * the renderer. Called by the CTabFolder parent upon receiving
  	 * the dispose event or when changing the renderer.
  	 * 
  	 * @since 3.6
  	 */
  	protected void dispose() {
  		disposeAntialiasColors();
  		disposeSelectionHighlightGradientColors();
  		if (fillColor != null) {
  		    fillColor.dispose();
  		    fillColor = null;
  		}
  	}
  	
  	void disposeAntialiasColors() {
  	    if (tabAreaColor != null) tabAreaColor.dispose();
  	    if (selectedInnerColor != null) selectedInnerColor.dispose();
  	    if (selectedOuterColor != null) selectedOuterColor.dispose();
  	    tabAreaColor = selectedInnerColor = selectedOuterColor = null;
  	}
  
  	void disposeSelectionHighlightGradientColors() {
  		if(selectionHighlightGradientColorsCache == null)
  			return;
  		for (Color element : selectionHighlightGradientColorsCache) {
  			element.dispose();
  		}
  		selectionHighlightGradientColorsCache = null;
  	}
  	
  	/**
  	 * Draw a specified <code>part</code> of the CTabFolder using the provided <code>bounds</code> and <code>GC</code>. 
  	 * <p>The valid CTabFolder <code>part</code> constants are:
  	 * <ul>
  	 * <li>PART_BODY - the entire body of the CTabFolder</li>
  	 * <li>PART_HEADER - the upper tab area of the CTabFolder</li>
  	 * <li>PART_BORDER - the border of the CTabFolder</li>
  	 * <li>PART_BACKGROUND - the background of the CTabFolder</li>
  	 * <li>PART_MAX_BUTTON</li> 
  	 * <li>PART_MIN_BUTTON</li>
  	 * <li>PART_CHEVRON_BUTTON</li>
  	 * <li>PART_CLOSE_BUTTON</li>
  	 * <li>A positive integer which is the index of an item in the CTabFolder.</li>
  	 * </ul>
  	 * </p>
  	 * <p>
  	 * The <code>state</code> parameter may be a combination of: 
  	 * <ul>
  	 * <li>SWT.BACKGROUND - whether the background should be drawn</li>
  	 * <li>SWT.FOREGROUND - whether the foreground should be drawn</li>
  	 * <li>SWT.SELECTED - whether the part is selected</li>
  	 * <li>SWT.HOT - whether the part is hot (i.e. mouse is over the part)</li>
  	 * </ul>
  	 * </p>
  	 * 
  	 * @param part part to draw 
  	 * @param state state of the part 
  	 * @param bounds the bounds of the part
  	 * @param gc the gc to draw the part on
  	 * 
  	 * @since 3.6
  	 */
  	protected void draw (int part, int state, Rectangle bounds, GC gc) {
  		switch (part) {
  			case PART_BACKGROUND:
  				this.drawBackground(gc, bounds, state);
  				break;
  			case PART_BODY:
  				drawBody(gc, bounds, state);
  				break;
  			case PART_HEADER:
  				drawTabArea(gc, bounds, state);
  				break;
  			case PART_MAX_BUTTON:
  				drawMaximize(gc, bounds, state);
  				break;
  			case PART_MIN_BUTTON:
  				drawMinimize(gc, bounds, state);
  				break;
  			case PART_CHEVRON_BUTTON:
  				drawChevron(gc, bounds, state);
  				break;
  			default:
  				if (0 <= part && part < parent.getItemCount()) {
  					if (bounds.width == 0 || bounds.height == 0) return;
  					if ((state & SWT.SELECTED) != 0 ) {
  						drawSelected(part, gc, bounds, state);
  					} else {
  						drawUnselected(part, gc, bounds, state);
  					}
  				}
  				break;
  		}
  	}
  	
  	void drawBackground(GC gc, Rectangle bounds, int state) {
  		boolean selected = (state & SWT.SELECTED) != 0;
  		Color defaultBackground = selected ? parent.selectionBackground : parent.getBackground();
  		Image image = selected ? parent.selectionBgImage : null;
  		Color[] colors = selected ? parent.selectionGradientColors : parent.gradientColors;
  		int[] percents = selected ? parent.selectionGradientPercents : parent.gradientPercents;
  		boolean vertical = selected ? parent.selectionGradientVertical : parent.gradientVertical; 
  		
  		drawBackground(gc, null, bounds.x, bounds.y, bounds.width, bounds.height, defaultBackground, image, colors, percents, vertical);
  	}
  	
  	void drawBackground(GC gc, int[] shape, boolean selected) {
  		Color defaultBackground = selected ? parent.selectionBackground : parent.getBackground();
  		Image image = selected ? parent.selectionBgImage : null;
  		Color[] colors = selected ? parent.selectionGradientColors : parent.gradientColors;
  		int[] percents = selected ? parent.selectionGradientPercents : parent.gradientPercents;
  		boolean vertical = selected ? parent.selectionGradientVertical : parent.gradientVertical; 
  		Point size = parent.getSize();
  		int width = size.x;
  		int height = parent.tabHeight + ((parent.getStyle() & SWT.FLAT) != 0 ? 1 : 3);
  		int x = 0;
  
  		int borderLeft = parent.borderVisible ? 1 : 0;
  		int borderTop = parent.onBottom ? borderLeft : 0;
  		int borderBottom = parent.onBottom ? 0 : borderLeft;
  		
  		if (borderLeft > 0) {
  			x += 1; width -= 2;
  		}
  		int y = parent.onBottom ? size.y - borderBottom - height : borderTop;
  		drawBackground(gc, shape, x, y, width, height, defaultBackground, image, colors, percents, vertical);
  	}
  	
  	void drawBackground(GC gc, int[] shape, int x, int y, int width, int height, Color defaultBackground, Image image, Color[] colors, int[] percents, boolean vertical) {
  		Region clipping = null, region = null;
  		if (shape != null) { 
  			clipping = new Region();
  			gc.getClipping(clipping);
  			region = new Region();
  			region.add(shape);
  			region.intersect(clipping);
  			gc.setClipping(region);
  		}
  		if (image != null) {
  			// draw the background image in shape
  			gc.setBackground(defaultBackground);
  			gc.fillRectangle(x, y, width, height);
  			Rectangle imageRect = image.getBounds();
  			gc.drawImage(image, imageRect.x, imageRect.y, imageRect.width, imageRect.height, x, y, width, height);
  		} else if (colors != null) {
  			// draw gradient
  			if (colors.length == 1) {
  				Color background = colors[0] != null ? colors[0] : defaultBackground;
  				gc.setBackground(background);
  				gc.fillRectangle(x, y, width, height);
  			} else {
  				if (vertical) {
  					if (parent.onBottom) {
  						int pos = 0;
  						if (percents[percents.length - 1] < 100) {
  							pos = (100 - percents[percents.length - 1]) * height / 100;
  							gc.setBackground(defaultBackground);
  							gc.fillRectangle(x, y, width, pos);
  						}
  						Color lastColor = colors[colors.length-1];
  						if (lastColor == null) lastColor = defaultBackground;
  						for (int i = percents.length-1; i >= 0; i--) {
  							gc.setForeground(lastColor);
  							lastColor = colors[i];
  							if (lastColor == null) lastColor = defaultBackground;
  							gc.setBackground(lastColor);
  							int percentage = i > 0 ? percents[i] - percents[i-1] : percents[i];
  							int gradientHeight = percentage * height / 100;
  							gc.fillGradientRectangle(x, y+pos, width, gradientHeight, true);
  							pos += gradientHeight;
  						}
  					} else {
  						Color lastColor = colors[0];
  						if (lastColor == null) lastColor = defaultBackground;
  						int pos = 0;
  						for (int i = 0; i < percents.length; i++) {
  							gc.setForeground(lastColor);
  							lastColor = colors[i + 1];
  							if (lastColor == null) lastColor = defaultBackground;
  							gc.setBackground(lastColor);
  							int percentage = i > 0 ? percents[i] - percents[i-1] : percents[i];
  							int gradientHeight = percentage * height / 100;
  							gc.fillGradientRectangle(x, y+pos, width, gradientHeight, true);
  							pos += gradientHeight;
  						}
  						if (pos < height) {
  							gc.setBackground(defaultBackground);
  							gc.fillRectangle(x, pos, width, height-pos+1);
  						}
  					}
  				} else { //horizontal gradient
  					y = 0;
  					height = parent.getSize().y;
  					Color lastColor = colors[0];
  					if (lastColor == null) lastColor = defaultBackground;
  					int pos = 0;
  					for (int i = 0; i < percents.length; ++i) {
  						gc.setForeground(lastColor);
  						lastColor = colors[i + 1];
  						if (lastColor == null) lastColor = defaultBackground;
  						gc.setBackground(lastColor);
  						int gradientWidth = (percents[i] * width / 100) - pos;
  						gc.fillGradientRectangle(x+pos, y, gradientWidth, height, false);
  						pos += gradientWidth;
  					}
  					if (pos < width) {
  						gc.setBackground(defaultBackground);
  						gc.fillRectangle(x+pos, y, width-pos, height);
  					}
  				}
  			}
  		} else {
  			// draw a solid background using default background in shape
  			if ((parent.getStyle() & SWT.NO_BACKGROUND) != 0 || !defaultBackground.equals(parent.getBackground())) {
  				gc.setBackground(defaultBackground);
  				gc.fillRectangle(x, y, width, height);
  			}
  		}
  		if (shape != null) {
  			gc.setClipping(clipping);
  			clipping.dispose();
  			region.dispose();
  		}
  	}
  	
  	/*
  	 * Draw the border of the tab
  	 * 
  	 * @param gc
  	 * @param shape
  	 */
  	void drawBorder(GC gc, int[] shape) {
  	
  		gc.setForeground(parent.getDisplay().getSystemColor(BORDER1_COLOR));
  		gc.drawPolyline(shape);
  	}
  
  	void drawBody(GC gc, Rectangle bounds, int state) {
  		Point size = new Point(bounds.width, bounds.height);
  		int selectedIndex = parent.selectedIndex;
  		int tabHeight = parent.tabHeight;
  		
  		int borderLeft = parent.borderVisible ? 1 : 0;
  		int borderRight = borderLeft;
  		int borderTop = parent.onBottom ? borderLeft : 0;
  		int borderBottom = parent.onBottom ? 0 : borderLeft;
  		
  		int style = parent.getStyle();
  		int highlight_header = (style & SWT.FLAT) != 0 ? 1 : 3;
  		int highlight_margin = (style & SWT.FLAT) != 0 ? 0 : 2;
  		
  		// fill in body
  		if (!parent.minimized){
  			int width = size.x  - borderLeft - borderRight - 2*highlight_margin;
  			int height = size.y - borderTop - borderBottom - tabHeight - highlight_header - highlight_margin;
  			// Draw highlight margin
  			if (highlight_margin > 0) {
  				int[] shape = null;
  				if (parent.onBottom) {
  					int x1 = borderLeft;
  					int y1 = borderTop;
  					int x2 = size.x - borderRight;
  					int y2 = size.y - borderBottom - tabHeight - highlight_header;
  					shape = new int[] {x1,y1, x2,y1, x2,y2, x2-highlight_margin,y2,
  							           x2-highlight_margin, y1+highlight_margin, x1+highlight_margin,y1+highlight_margin,
  									   x1+highlight_margin,y2, x1,y2};
  				} else {	
  					int x1 = borderLeft;
  					int y1 = borderTop + tabHeight + highlight_header;
  					int x2 = size.x - borderRight;
  					int y2 = size.y - borderBottom;
  					shape = new int[] {x1,y1, x1+highlight_margin,y1, x1+highlight_margin,y2-highlight_margin, 
  							           x2-highlight_margin,y2-highlight_margin, x2-highlight_margin,y1,
  									   x2,y1, x2,y2, x1,y2};
  				}
  				// If horizontal gradient, show gradient across the whole area
  				if (selectedIndex != -1 && parent.selectionGradientColors != null && parent.selectionGradientColors.length > 1 && !parent.selectionGradientVertical) {
  					drawBackground(gc, shape, true);
  				} else if (selectedIndex == -1 && parent.gradientColors != null && parent.gradientColors.length > 1 && !parent.gradientVertical) {
  					drawBackground(gc, shape, false);
  				} else {
  					gc.setBackground(selectedIndex == -1 ? parent.getBackground() : parent.selectionBackground);
  					gc.fillPolygon(shape);
  				}
  			}
  			//Draw client area
  			if ((parent.getStyle() & SWT.NO_BACKGROUND) != 0) {
  				gc.setBackground(parent.getBackground());
  				int marginWidth = parent.marginWidth;
  				int marginHeight = parent.marginHeight;
  				int xClient = borderLeft + marginWidth + highlight_margin, yClient;
  				if (parent.onBottom) {
  					yClient = borderTop + highlight_margin + marginHeight;
  				} else {
  					yClient = borderTop + tabHeight + highlight_header + marginHeight; 
  				}
  				gc.fillRectangle(xClient - marginWidth, yClient - marginHeight, width, height);
  			}
  		} else {
  			if ((parent.getStyle() & SWT.NO_BACKGROUND) != 0) {
  				int height = borderTop + tabHeight + highlight_header + borderBottom;
  				if (size.y > height) {
  					gc.setBackground(parent.getParent().getBackground());
  					gc.fillRectangle(0, height, size.x, size.y - height);
  				}
  			}
  		}
  		
  		//draw 1 pixel border around outside
  		if (borderLeft > 0) {
  			gc.setForeground(parent.getDisplay().getSystemColor(BORDER1_COLOR));
  			int x1 = borderLeft - 1;
  			int x2 = size.x - borderRight;
  			int y1 = parent.onBottom ? borderTop - 1 : borderTop + tabHeight;
  			int y2 = parent.onBottom ? size.y - tabHeight - borderBottom - 1 : size.y - borderBottom;
  			gc.drawLine(x1, y1, x1, y2); // left
  			gc.drawLine(x2, y1, x2, y2); // right
  			if (parent.onBottom) {
  				gc.drawLine(x1, y1, x2, y1); // top
  			} else {
  				gc.drawLine(x1, y2, x2, y2); // bottom
  			}
  		}
  	}
  	
  	void drawClose(GC gc, Rectangle closeRect, int closeImageState) {
  		if (closeRect.width == 0 || closeRect.height == 0) return;
  		Display display = parent.getDisplay();
  	
  		// draw X 9x9
  		int x = closeRect.x + Math.max(1, (closeRect.width-9)/2);
  		int y = closeRect.y + Math.max(1, (closeRect.height-9)/2);
  		y += parent.onBottom ? -1 : 1;
  		
  		Color closeBorder = display.getSystemColor(BUTTON_BORDER);
  		switch (closeImageState & (SWT.HOT | SWT.SELECTED | SWT.BACKGROUND)) {
  			case SWT.NONE: {
  				int[] shape = new int[] {x,y, x+2,y, x+4,y+2, x+5,y+2, x+7,y, x+9,y, 
  						                 x+9,y+2, x+7,y+4, x+7,y+5, x+9,y+7, x+9,y+9,
  				                         x+7,y+9, x+5,y+7, x+4,y+7, x+2,y+9, x,y+9,
  				                         x,y+7, x+2,y+5, x+2,y+4, x,y+2};
  				gc.setBackground(display.getSystemColor(BUTTON_FILL));
  				gc.fillPolygon(shape);
  				gc.setForeground(closeBorder);
  				gc.drawPolygon(shape);
  				break;
  			}
  			case SWT.HOT: {
  				int[] shape = new int[] {x,y, x+2,y, x+4,y+2, x+5,y+2, x+7,y, x+9,y, 
  						                 x+9,y+2, x+7,y+4, x+7,y+5, x+9,y+7, x+9,y+9,
  				                         x+7,y+9, x+5,y+7, x+4,y+7, x+2,y+9, x,y+9,
  				                         x,y+7, x+2,y+5, x+2,y+4, x,y+2};
  				gc.setBackground(getFillColor());
  				gc.fillPolygon(shape);
  				gc.setForeground(closeBorder);
  				gc.drawPolygon(shape);
  				break;
  			}
  			case SWT.SELECTED: {
  				int[] shape = new int[] {x+1,y+1, x+3,y+1, x+5,y+3, x+6,y+3, x+8,y+1, x+10,y+1, 
  						                 x+10,y+3, x+8,y+5, x+8,y+6, x+10,y+8, x+10,y+10,
  				                         x+8,y+10, x+6,y+8, x+5,y+8, x+3,y+10, x+1,y+10,
  				                         x+1,y+8, x+3,y+6, x+3,y+5, x+1,y+3};
  				gc.setBackground(getFillColor());
  				gc.fillPolygon(shape);
  				gc.setForeground(closeBorder);
  				gc.drawPolygon(shape);
  				break;
  			}
  			case SWT.BACKGROUND: {
  				int[] shape = new int[] {x,y, x+10,y, x+10,y+10, x,y+10};
  				drawBackground(gc, shape, false);
  				break;
  			}
  		}
  	}
  
  	void drawChevron(GC gc, Rectangle chevronRect, int chevronImageState) {
  		if (chevronRect.width == 0 || chevronRect.height == 0) return;
  		int selectedIndex = parent.selectedIndex;
  		// draw chevron (10x7)
  		Display display = parent.getDisplay();
  		Point dpi = display.getDPI();
  		int fontHeight = 72 * 10 / dpi.y;
  		FontData fd = parent.getFont().getFontData()[0];
  		fd.setHeight(fontHeight);
  		Font f = new Font(display, fd);
  		int fHeight = f.getFontData()[0].getHeight() * dpi.y / 72;
  		int indent = Math.max(2, (chevronRect.height - fHeight - 4) /2);
  		int x = chevronRect.x + 2;
  		int y = chevronRect.y + indent;
  		int count;
  		int itemCount = parent.getItemCount();
  		if (parent.single) {
  			count = selectedIndex == -1 ? itemCount : itemCount - 1;
  		} else {
  			int showCount = 0;
  			while (showCount < parent.priority.length && parent.items[parent.priority[showCount]].showing) {
  				showCount++;
  			}
  			count = itemCount - showCount;
  		}
  		String chevronString = count > 99 ? "99+" : String.valueOf(count); //$NON-NLS-1$
  		switch (chevronImageState & (SWT.HOT | SWT.SELECTED)) {
  			case SWT.NONE: {
  				Color chevronBorder = parent.single ? parent.getSelectionForeground() : parent.getForeground();
  				gc.setForeground(chevronBorder);
  				gc.setFont(f);
  				gc.drawLine(x,y,     x+2,y+2);
  				gc.drawLine(x+2,y+2, x,y+4);
  				gc.drawLine(x+1,y,   x+3,y+2);
  				gc.drawLine(x+3,y+2, x+1,y+4);
  				gc.drawLine(x+4,y,   x+6,y+2);
  				gc.drawLine(x+6,y+2, x+5,y+4);
  				gc.drawLine(x+5,y,   x+7,y+2);
  				gc.drawLine(x+7,y+2, x+4,y+4);
  				gc.drawString(chevronString, x+7, y+3, true);
  				break;
  			}
  			case SWT.HOT: {
  				gc.setForeground(display.getSystemColor(BUTTON_BORDER));
  				gc.setBackground(display.getSystemColor(BUTTON_FILL));
  				gc.setFont(f);
  				gc.fillRoundRectangle(chevronRect.x, chevronRect.y, chevronRect.width, chevronRect.height, 6, 6);
  				gc.drawRoundRectangle(chevronRect.x, chevronRect.y, chevronRect.width - 1, chevronRect.height - 1, 6, 6);
  				gc.drawLine(x,y,     x+2,y+2);
  				gc.drawLine(x+2,y+2, x,y+4);
  				gc.drawLine(x+1,y,   x+3,y+2);
  				gc.drawLine(x+3,y+2, x+1,y+4);
  				gc.drawLine(x+4,y,   x+6,y+2);
  				gc.drawLine(x+6,y+2, x+5,y+4);
  				gc.drawLine(x+5,y,   x+7,y+2);
  				gc.drawLine(x+7,y+2, x+4,y+4);
  				gc.drawString(chevronString, x+7, y+3, true);
  				break;
  			}
  			case SWT.SELECTED: {
  				gc.setForeground(display.getSystemColor(BUTTON_BORDER));
  				gc.setBackground(display.getSystemColor(BUTTON_FILL));
  				gc.setFont(f);
  				gc.fillRoundRectangle(chevronRect.x, chevronRect.y, chevronRect.width, chevronRect.height, 6, 6);
  				gc.drawRoundRectangle(chevronRect.x, chevronRect.y, chevronRect.width - 1, chevronRect.height - 1, 6, 6);
  				gc.drawLine(x+1,y+1, x+3,y+3);
  				gc.drawLine(x+3,y+3, x+1,y+5);
  				gc.drawLine(x+2,y+1, x+4,y+3);
  				gc.drawLine(x+4,y+3, x+2,y+5);
  				gc.drawLine(x+5,y+1, x+7,y+3);
  				gc.drawLine(x+7,y+3, x+6,y+5);
  				gc.drawLine(x+6,y+1, x+8,y+3);
  				gc.drawLine(x+8,y+3, x+5,y+5);
  				gc.drawString(chevronString, x+8, y+4, true);
  				break;
  			}
  		}
  		f.dispose();
  	}
  
  	/*
  	 * Draw a highlight effect along the left, top, and right edges of the tab.
  	 * Only for curved tabs, on top.
  	 * Do not draw if insufficient colors.
  	 */
  	void drawHighlight(GC gc, Rectangle bounds, int state, int rightEdge) {
  		//only draw for curvy tabs and only draw for top tabs
  		if(parent.simple || parent.onBottom)
  			return;
  		
  		if(selectionHighlightGradientBegin == null)
  			return;
  
  		Color[] gradients = selectionHighlightGradientColorsCache;
  		if(gradients == null)
  			return;
  		int gradientsSize = gradients.length;
  		if(gradientsSize == 0)
  			return;		//shouldn't happen but just to be tidy
  
  		int x = bounds.x;
  		int y = bounds.y;
  		
  		gc.setForeground(gradients[0]);
  		
  		//draw top horizontal line
  		gc.drawLine(
  				TOP_LEFT_CORNER_HILITE[0] + x + 1, //rely on fact that first pair is top/right of curve
  				1 + y,
  				rightEdge - curveIndent,
  				1 + y);
  		
  		int[] leftHighlightCurve = TOP_LEFT_CORNER_HILITE;
  
  		int d = parent.tabHeight - topCurveHighlightEnd.length /2;
  
  		int lastX = 0;
  		int lastY = 0;
  		int lastColorIndex = 0;
  		
  		//draw upper left curve highlight
  		for (int i = 0; i < leftHighlightCurve.length /2; i++) {
  			int rawX = leftHighlightCurve[i * 2];
  			int rawY = leftHighlightCurve[i * 2 + 1];
  			lastX = rawX + x;
  			lastY = rawY + y;
  			lastColorIndex = rawY - 1;
  			gc.setForeground(gradients[lastColorIndex]);
  			gc.drawPoint(lastX, lastY);
  		}
  		//draw left vertical line highlight
  		for(int i = lastColorIndex; i < gradientsSize; i++) {
  			gc.setForeground(gradients[i]);
  			gc.drawPoint(lastX, 1 + lastY++);
  		}
  		
  		int rightEdgeOffset = rightEdge - curveIndent;
  		
  		//draw right swoop highlight up to diagonal portion
  		for (int i = 0; i < topCurveHighlightStart.length /2; i++) {
  			int rawX = topCurveHighlightStart[i * 2];
  			int rawY = topCurveHighlightStart[i * 2 + 1];
  			lastX = rawX + rightEdgeOffset;
  			lastY = rawY + y;
  			lastColorIndex = rawY - 1;
  			if(lastColorIndex >= gradientsSize)
  				break;	//can happen if tabs are unusually short and cut off the curve
  			gc.setForeground(gradients[lastColorIndex]);
  			gc.drawPoint(lastX, lastY);
  		}
  		//draw right diagonal line highlight
  		for(int i = lastColorIndex; i < lastColorIndex + d; i++) {
  			if(i >= gradientsSize)
  				break;	//can happen if tabs are unusually short and cut off the curve
  			gc.setForeground(gradients[i]);
  			gc.drawPoint(1 + lastX++, 1 + lastY++);
  		}
  
  		//draw right swoop highlight from diagonal portion to end
  		for (int i = 0; i < topCurveHighlightEnd.length /2; i++) {
  			int rawX = topCurveHighlightEnd[i * 2]; //d is already encoded in this value
  			int rawY = topCurveHighlightEnd[i * 2 + 1]; //d already encoded
  			lastX = rawX + rightEdgeOffset;
  			lastY = rawY + y;
  			lastColorIndex = rawY - 1;
  			if(lastColorIndex >= gradientsSize)
  				break;	//can happen if tabs are unusually short and cut off the curve
  			gc.setForeground(gradients[lastColorIndex]);
  			gc.drawPoint(lastX, lastY);
  		}	
  	}
  
  	/*
  	 * Draw the unselected border for the receiver on the left.
  	 * 
  	 * @param gc
  	 */
  	void drawLeftUnselectedBorder(GC gc, Rectangle bounds, int state) {
  		int x = bounds.x;
  		int y = bounds.y;
  		int height = bounds.height;
  		
  		int[] shape = null;
  		if (parent.onBottom) {
  			int[] left = parent.simple
  				? SIMPLE_UNSELECTED_INNER_CORNER
  				: BOTTOM_LEFT_CORNER;
  			
  			shape = new int[left.length + 2];
  			int index = 0;
  			shape[index++] = x;
  			shape[index++] = y - 1;
  			for (int i = 0; i < left.length / 2; i++) {
  				shape[index++] = x + left[2 * i];
  				shape[index++] = y + height + left[2 * i + 1] - 1;
  			}
  		} else {
  			int[] left = parent.simple
  				? SIMPLE_UNSELECTED_INNER_CORNER
  				: TOP_LEFT_CORNER;
  
  			shape = new int[left.length + 2];
  			int index = 0;
  			shape[index++] = x;
  			shape[index++] = y + height;
  			for (int i = 0; i < left.length / 2; i++) {
  				shape[index++] = x + left[2 * i];
  				shape[index++] = y + left[2 * i + 1];
  			}
  
  		}
  
  		drawBorder(gc, shape);
  	}
  
  	void drawMaximize(GC gc, Rectangle maxRect, int maxImageState) {
  		if (maxRect.width == 0 || maxRect.height == 0) return;
  		Display display = parent.getDisplay();
  		// 5x4 or 7x9
  		int x = maxRect.x + (maxRect.width - 10)/2;
  		int y = maxRect.y + 3;
  		
  		gc.setForeground(display.getSystemColor(BUTTON_BORDER));
  		gc.setBackground(display.getSystemColor(BUTTON_FILL));
  		
  		switch (maxImageState & (SWT.HOT | SWT.SELECTED)) {
  			case SWT.NONE: {
  				if (!parent.getMaximized()) {
  					gc.fillRectangle(x, y, 9, 9);
  					gc.drawRectangle(x, y, 9, 9);
  					gc.drawLine(x+1, y+2, x+8, y+2);				
  				} else {
  					gc.fillRectangle(x, y+3, 5, 4);
  					gc.fillRectangle(x+2, y, 5, 4);
  					gc.drawRectangle(x, y+3, 5, 4);
  					gc.drawRectangle(x+2, y, 5, 4);
  					gc.drawLine(x+3, y+1, x+6, y+1);
  					gc.drawLine(x+1, y+4, x+4, y+4);
  				}
  				break;
  			}
  			case SWT.HOT: {
  				gc.fillRoundRectangle(maxRect.x, maxRect.y, maxRect.width, maxRect.height, 6, 6);
  				gc.drawRoundRectangle(maxRect.x, maxRect.y, maxRect.width - 1, maxRect.height - 1, 6, 6);
  				if (!parent.getMaximized()) {
  					gc.fillRectangle(x, y, 9, 9);
  					gc.drawRectangle(x, y, 9, 9);
  					gc.drawLine(x+1, y+2, x+8, y+2);
  				} else {
  					gc.fillRectangle(x, y+3, 5, 4);
  					gc.fillRectangle(x+2, y, 5, 4);
  					gc.drawRectangle(x, y+3, 5, 4);
  					gc.drawRectangle(x+2, y, 5, 4);
  					gc.drawLine(x+3, y+1, x+6, y+1);
  					gc.drawLine(x+1, y+4, x+4, y+4);
  				}
  				break;
  			}
  			case SWT.SELECTED: {
  				gc.fillRoundRectangle(maxRect.x, maxRect.y, maxRect.width, maxRect.height, 6, 6);
  				gc.drawRoundRectangle(maxRect.x, maxRect.y, maxRect.width - 1, maxRect.height - 1, 6, 6);
  				if (!parent.getMaximized()) {
  					gc.fillRectangle(x+1, y+1, 9, 9);
  					gc.drawRectangle(x+1, y+1, 9, 9);
  					gc.drawLine(x+2, y+3, x+9, y+3);
  				} else {
  					gc.fillRectangle(x+1, y+4, 5, 4);
  					gc.fillRectangle(x+3, y+1, 5, 4);
  					gc.drawRectangle(x+1, y+4, 5, 4);
  					gc.drawRectangle(x+3, y+1, 5, 4);
  					gc.drawLine(x+4, y+2, x+7, y+2);
  					gc.drawLine(x+2, y+5, x+5, y+5);
  				}
  				break;
  			}
  		}
  	}
  	void drawMinimize(GC gc, Rectangle minRect, int minImageState) {
  		if (minRect.width == 0 || minRect.height == 0) return;
  		Display display = parent.getDisplay();
  		// 5x4 or 9x3
  		int x = minRect.x + (minRect.width - 10)/2;
  		int y = minRect.y + 3;
  		
  		gc.setForeground(display.getSystemColor(BUTTON_BORDER));
  		gc.setBackground(display.getSystemColor(BUTTON_FILL));
  		
  		switch (minImageState & (SWT.HOT | SWT.SELECTED)) {
  			case SWT.NONE: {
  				if (!parent.getMinimized()) {
  					gc.fillRectangle(x, y, 9, 3);
  					gc.drawRectangle(x, y, 9, 3);
  				} else {
  					gc.fillRectangle(x, y+3, 5, 4);
  					gc.fillRectangle(x+2, y, 5, 4);
  					gc.drawRectangle(x, y+3, 5, 4);
  					gc.drawRectangle(x+2, y, 5, 4);
  					gc.drawLine(x+3, y+1, x+6, y+1);
  					gc.drawLine(x+1, y+4, x+4, y+4);
  				}
  				break;
  			}
  			case SWT.HOT: {
  				gc.fillRoundRectangle(minRect.x, minRect.y, minRect.width, minRect.height, 6, 6);
  				gc.drawRoundRectangle(minRect.x, minRect.y, minRect.width - 1, minRect.height - 1, 6, 6);
  				if (!parent.getMinimized()) {
  					gc.fillRectangle(x, y, 9, 3);
  					gc.drawRectangle(x, y, 9, 3);
  				} else {
  					gc.fillRectangle(x, y+3, 5, 4);
  					gc.fillRectangle(x+2, y, 5, 4);
  					gc.drawRectangle(x, y+3, 5, 4);
  					gc.drawRectangle(x+2, y, 5, 4);
  					gc.drawLine(x+3, y+1, x+6, y+1);
  					gc.drawLine(x+1, y+4, x+4, y+4);
  				}
  				break;
  			}
  			case SWT.SELECTED: {
  				gc.fillRoundRectangle(minRect.x, minRect.y, minRect.width, minRect.height, 6, 6);
  				gc.drawRoundRectangle(minRect.x, minRect.y, minRect.width - 1, minRect.height - 1, 6, 6);
  				if (!parent.getMinimized()) {
  					gc.fillRectangle(x+1, y+1, 9, 3);
  					gc.drawRectangle(x+1, y+1, 9, 3);
  				} else {
  					gc.fillRectangle(x+1, y+4, 5, 4);
  					gc.fillRectangle(x+3, y+1, 5, 4);
  					gc.drawRectangle(x+1, y+4, 5, 4);
  					gc.drawRectangle(x+3, y+1, 5, 4);
  					gc.drawLine(x+4, y+2, x+7, y+2);
  					gc.drawLine(x+2, y+5, x+5, y+5);
  				}
  				break;
  			}
  		}
  	}
  
  	/*
  	 * Draw the unselected border for the receiver on the right.
  	 * 
  	 * @param gc
  	 */
  	void drawRightUnselectedBorder(GC gc, Rectangle bounds, int state) {
  		int x = bounds.x;
  		int y = bounds.y;
  		int width = bounds.width;
  		int height = bounds.height;
  		
  		int[] shape = null;
  		int startX = x + width - 1;
  	
  		if (parent.onBottom) {
  			int[] right = parent.simple
  				? SIMPLE_UNSELECTED_INNER_CORNER
  				: BOTTOM_RIGHT_CORNER;
  			
  			shape = new int[right.length + 2];
  			int index = 0;
  			
  			for (int i = 0; i < right.length / 2; i++) {
  				shape[index++] = startX + right[2 * i];
  				shape[index++] = y + height + right[2 * i + 1] - 1;
  			}
  			shape[index++] = startX;
  			shape[index++] = y - 1;
  		} else {
  			int[] right = parent.simple
  				? SIMPLE_UNSELECTED_INNER_CORNER
  				: TOP_RIGHT_CORNER;
  			
  			shape = new int[right.length + 2];
  			int index = 0;
  	
  			for (int i = 0; i < right.length / 2; i++) {
  				shape[index++] = startX + right[2 * i];
  				shape[index++] = y + right[2 * i + 1];
  			}
  	
  			shape[index++] = startX;
  			shape[index++] = y + height;
  	
  		}
  	
  		drawBorder(gc, shape);
  	
  	}
  
  	void drawSelected(int itemIndex, GC gc, Rectangle bounds, int state ) {
  		CTabItem item = parent.items[itemIndex];
  		int x = bounds.x;
  		int y = bounds.y;
  		int height = bounds.height;
  		int width = bounds.width;
  		if (!parent.simple && !parent.single) width -= (curveWidth - curveIndent);
  		int borderLeft = parent.borderVisible ? 1 : 0;
  		int borderRight = borderLeft;
  		int borderTop = parent.onBottom ? borderLeft : 0;
  		int borderBottom = parent.onBottom ? 0 : borderLeft;
  		
  		Point size = parent.getSize();
  	
  		int rightEdge = Math.min (x + width, parent.getRightItemEdge(gc));
  		//	 Draw selection border across all tabs
  		
  		if ((state & SWT.BACKGROUND) != 0) {
  			int highlight_header = (parent.getStyle() & SWT.FLAT) != 0 ? 1 : 3;
  			int xx = borderLeft;
  			int yy = parent.onBottom ? size.y - borderBottom - parent.tabHeight - highlight_header : borderTop + parent.tabHeight + 1;
  			int ww = size.x - borderLeft - borderRight;
  			int hh = highlight_header - 1;
  			int[] shape = new int[] {xx,yy, xx+ww,yy, xx+ww,yy+hh, xx,yy+hh};
  			if (parent.selectionGradientColors != null && !parent.selectionGradientVertical) {
  				drawBackground(gc, shape, true);
  			} else {
  				gc.setBackground(parent.selectionBackground);
  				gc.fillRectangle(xx, yy, ww, hh);
  			}
  			
  			if (parent.single) {
  				if (!item.showing) return;
  			} else {
  				// if selected tab scrolled out of view or partially out of view
  				// just draw bottom line
  				if (!item.showing){
  					int x1 = Math.max(0, borderLeft - 1);
  					int y1 = (parent.onBottom) ? y - 1 : y + height;
  					int x2 = size.x - borderRight;
  					gc.setForeground(parent.getDisplay().getSystemColor(BORDER1_COLOR));
  					gc.drawLine(x1, y1, x2, y1);
  					return;
  				}
  					
  				// draw selected tab background and outline
  				shape = null;
  				if (parent.onBottom) {
  					int[] left = parent.simple ? SIMPLE_BOTTOM_LEFT_CORNER : BOTTOM_LEFT_CORNER;
  					int[] right = parent.simple ? SIMPLE_BOTTOM_RIGHT_CORNER : curve;
  					if (borderLeft == 0 && itemIndex == parent.firstIndex) {
  						left = new int[]{x, y+height};
  					}
  					shape = new int[left.length+right.length+8];
  					int index = 0;
  					shape[index++] = x; // first point repeated here because below we reuse shape to draw outline
  					shape[index++] = y - 1;
  					shape[index++] = x;
  					shape[index++] = y - 1;
  					for (int i = 0; i < left.length/2; i++) {
  						shape[index++] = x + left[2*i];
  