diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:31:44 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:31:44 -0800 |
commit | 9066cfe9886ac131c34d59ed0e2d287b0e3c0087 (patch) | |
tree | d88beb88001f2482911e3d28e43833b50e4b4e97 /awt/java | |
parent | d83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (diff) | |
download | frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.zip frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.tar.gz frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'awt/java')
246 files changed, 70723 insertions, 0 deletions
diff --git a/awt/java/awt/AWTEvent.java b/awt/java/awt/AWTEvent.java new file mode 100644 index 0000000..a8dc83a --- /dev/null +++ b/awt/java/awt/AWTEvent.java @@ -0,0 +1,681 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev, Michael Danilov + * @version $Revision$ + */ + +package java.awt; + +import java.util.EventObject; +import java.util.Hashtable; +import java.util.EventListener; + +import java.awt.event.*; + +/** + * The abstract class AWTEvent is the base class for all AWT events. This class + * and its subclasses supersede the original java.awt.Event class. + * + * @since Android 1.0 + */ +public abstract class AWTEvent extends EventObject { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -1825314779160409405L; + + /** + * The Constant COMPONENT_EVENT_MASK indicates the event relates to a + * component. + */ + public static final long COMPONENT_EVENT_MASK = 1; + + /** + * The Constant CONTAINER_EVENT_MASK indicates the event relates to a + * container. + */ + public static final long CONTAINER_EVENT_MASK = 2; + + /** + * The Constant FOCUS_EVENT_MASK indicates the event relates to the focus. + */ + public static final long FOCUS_EVENT_MASK = 4; + + /** + * The Constant KEY_EVENT_MASK indicates the event relates to a key. + */ + public static final long KEY_EVENT_MASK = 8; + + /** + * The Constant MOUSE_EVENT_MASK indicates the event relates to the mouse. + */ + public static final long MOUSE_EVENT_MASK = 16; + + /** + * The Constant MOUSE_MOTION_EVENT_MASK indicates the event relates to a + * mouse motion. + */ + public static final long MOUSE_MOTION_EVENT_MASK = 32; + + /** + * The Constant WINDOW_EVENT_MASK indicates the event relates to a window. + */ + public static final long WINDOW_EVENT_MASK = 64; + + /** + * The Constant ACTION_EVENT_MASK indicates the event relates to an action. + */ + public static final long ACTION_EVENT_MASK = 128; + + /** + * The Constant ADJUSTMENT_EVENT_MASK indicates the event relates to an + * adjustment. + */ + public static final long ADJUSTMENT_EVENT_MASK = 256; + + /** + * The Constant ITEM_EVENT_MASK indicates the event relates to an item. + */ + public static final long ITEM_EVENT_MASK = 512; + + /** + * The Constant TEXT_EVENT_MASK indicates the event relates to text. + */ + public static final long TEXT_EVENT_MASK = 1024; + + /** + * The Constant INPUT_METHOD_EVENT_MASK indicates the event relates to an + * input method. + */ + public static final long INPUT_METHOD_EVENT_MASK = 2048; + + /** + * The Constant PAINT_EVENT_MASK indicates the event relates to a paint + * method. + */ + public static final long PAINT_EVENT_MASK = 8192; + + /** + * The Constant INVOCATION_EVENT_MASK indicates the event relates to a + * method invocation. + */ + public static final long INVOCATION_EVENT_MASK = 16384; + + /** + * The Constant HIERARCHY_EVENT_MASK indicates the event relates to a + * hierarchy. + */ + public static final long HIERARCHY_EVENT_MASK = 32768; + + /** + * The Constant HIERARCHY_BOUNDS_EVENT_MASK indicates the event relates to + * hierarchy bounds. + */ + public static final long HIERARCHY_BOUNDS_EVENT_MASK = 65536; + + /** + * The Constant MOUSE_WHEEL_EVENT_MASK indicates the event relates to the + * mouse wheel. + */ + public static final long MOUSE_WHEEL_EVENT_MASK = 131072; + + /** + * The Constant WINDOW_STATE_EVENT_MASK indicates the event relates to a + * window state. + */ + public static final long WINDOW_STATE_EVENT_MASK = 262144; + + /** + * The Constant WINDOW_FOCUS_EVENT_MASK indicates the event relates to a + * window focus. + */ + public static final long WINDOW_FOCUS_EVENT_MASK = 524288; + + /** + * The Constant RESERVED_ID_MAX indicates the maximum value for reserved AWT + * event IDs. + */ + public static final int RESERVED_ID_MAX = 1999; + + /** + * The Constant eventsMap. + */ + private static final Hashtable<Integer, EventDescriptor> eventsMap = new Hashtable<Integer, EventDescriptor>(); + + /** + * The converter. + */ + private static EventConverter converter; + + /** + * The ID of the event. + */ + protected int id; + + /** + * The consumed indicates whether or not the event is sent back down to the + * peer once the source has processed it (false means it's sent to the peer, + * true means it's not). + */ + protected boolean consumed; + + /** + * The dispatched by kfm. + */ + boolean dispatchedByKFM; + + /** + * The is posted. + */ + transient boolean isPosted; + + static { + eventsMap.put(new Integer(KeyEvent.KEY_TYPED), new EventDescriptor(KEY_EVENT_MASK, + KeyListener.class)); + eventsMap.put(new Integer(KeyEvent.KEY_PRESSED), new EventDescriptor(KEY_EVENT_MASK, + KeyListener.class)); + eventsMap.put(new Integer(KeyEvent.KEY_RELEASED), new EventDescriptor(KEY_EVENT_MASK, + KeyListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_CLICKED), new EventDescriptor(MOUSE_EVENT_MASK, + MouseListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_PRESSED), new EventDescriptor(MOUSE_EVENT_MASK, + MouseListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_RELEASED), new EventDescriptor(MOUSE_EVENT_MASK, + MouseListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_MOVED), new EventDescriptor( + MOUSE_MOTION_EVENT_MASK, MouseMotionListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_ENTERED), new EventDescriptor(MOUSE_EVENT_MASK, + MouseListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_EXITED), new EventDescriptor(MOUSE_EVENT_MASK, + MouseListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_DRAGGED), new EventDescriptor( + MOUSE_MOTION_EVENT_MASK, MouseMotionListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_WHEEL), new EventDescriptor( + MOUSE_WHEEL_EVENT_MASK, MouseWheelListener.class)); + eventsMap.put(new Integer(ComponentEvent.COMPONENT_MOVED), new EventDescriptor( + COMPONENT_EVENT_MASK, ComponentListener.class)); + eventsMap.put(new Integer(ComponentEvent.COMPONENT_RESIZED), new EventDescriptor( + COMPONENT_EVENT_MASK, ComponentListener.class)); + eventsMap.put(new Integer(ComponentEvent.COMPONENT_SHOWN), new EventDescriptor( + COMPONENT_EVENT_MASK, ComponentListener.class)); + eventsMap.put(new Integer(ComponentEvent.COMPONENT_HIDDEN), new EventDescriptor( + COMPONENT_EVENT_MASK, ComponentListener.class)); + eventsMap.put(new Integer(FocusEvent.FOCUS_GAINED), new EventDescriptor(FOCUS_EVENT_MASK, + FocusListener.class)); + eventsMap.put(new Integer(FocusEvent.FOCUS_LOST), new EventDescriptor(FOCUS_EVENT_MASK, + FocusListener.class)); + eventsMap.put(new Integer(PaintEvent.PAINT), new EventDescriptor(PAINT_EVENT_MASK, null)); + eventsMap.put(new Integer(PaintEvent.UPDATE), new EventDescriptor(PAINT_EVENT_MASK, null)); + eventsMap.put(new Integer(WindowEvent.WINDOW_OPENED), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_CLOSING), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_CLOSED), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_DEICONIFIED), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_ICONIFIED), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_STATE_CHANGED), new EventDescriptor( + WINDOW_STATE_EVENT_MASK, WindowStateListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_LOST_FOCUS), new EventDescriptor( + WINDOW_FOCUS_EVENT_MASK, WindowFocusListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_GAINED_FOCUS), new EventDescriptor( + WINDOW_FOCUS_EVENT_MASK, WindowFocusListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_DEACTIVATED), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_ACTIVATED), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(HierarchyEvent.HIERARCHY_CHANGED), new EventDescriptor( + HIERARCHY_EVENT_MASK, HierarchyListener.class)); + eventsMap.put(new Integer(HierarchyEvent.ANCESTOR_MOVED), new EventDescriptor( + HIERARCHY_BOUNDS_EVENT_MASK, HierarchyBoundsListener.class)); + eventsMap.put(new Integer(HierarchyEvent.ANCESTOR_RESIZED), new EventDescriptor( + HIERARCHY_BOUNDS_EVENT_MASK, HierarchyBoundsListener.class)); + eventsMap.put(new Integer(ContainerEvent.COMPONENT_ADDED), new EventDescriptor( + CONTAINER_EVENT_MASK, ContainerListener.class)); + eventsMap.put(new Integer(ContainerEvent.COMPONENT_REMOVED), new EventDescriptor( + CONTAINER_EVENT_MASK, ContainerListener.class)); + eventsMap.put(new Integer(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED), new EventDescriptor( + INPUT_METHOD_EVENT_MASK, InputMethodListener.class)); + eventsMap.put(new Integer(InputMethodEvent.CARET_POSITION_CHANGED), new EventDescriptor( + INPUT_METHOD_EVENT_MASK, InputMethodListener.class)); + eventsMap.put(new Integer(InvocationEvent.INVOCATION_DEFAULT), new EventDescriptor( + INVOCATION_EVENT_MASK, null)); + eventsMap.put(new Integer(ItemEvent.ITEM_STATE_CHANGED), new EventDescriptor( + ITEM_EVENT_MASK, ItemListener.class)); + eventsMap.put(new Integer(TextEvent.TEXT_VALUE_CHANGED), new EventDescriptor( + TEXT_EVENT_MASK, TextListener.class)); + eventsMap.put(new Integer(ActionEvent.ACTION_PERFORMED), new EventDescriptor( + ACTION_EVENT_MASK, ActionListener.class)); + eventsMap.put(new Integer(AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED), new EventDescriptor( + ADJUSTMENT_EVENT_MASK, AdjustmentListener.class)); + converter = new EventConverter(); + } + + /** + * Instantiates a new AWT event from the specified Event object. + * + * @param event + * the Event object. + */ + public AWTEvent(Event event) { + this(event.target, event.id); + } + + /** + * Instantiates a new AWT event with the specified object and type. + * + * @param source + * the source Object. + * @param id + * the event's type. + */ + public AWTEvent(Object source, int id) { + super(source); + this.id = id; + consumed = false; + } + + /** + * Gets the event's type. + * + * @return the event type ID. + */ + public int getID() { + return id; + } + + /** + * Sets a new source for the AWTEvent. + * + * @param newSource + * the new source Object for the AWTEvent. + */ + public void setSource(Object newSource) { + source = newSource; + } + + /** + * Returns a String representation of the AWTEvent. + * + * @return the String representation of the AWTEvent. + */ + @Override + public String toString() { + /* + * The format is based on 1.5 release behavior which can be revealed by + * the following code: AWTEvent event = new AWTEvent(new Component(){}, + * 1){}; System.out.println(event); + */ + String name = ""; //$NON-NLS-1$ + + if (source instanceof Component && (source != null)) { + Component comp = (Component)getSource(); + name = comp.getName(); + if (name == null) { + name = ""; //$NON-NLS-1$ + } + } + + return (getClass().getName() + "[" + paramString() + "]" //$NON-NLS-1$ //$NON-NLS-2$ + + " on " + (name.length() > 0 ? name : source)); //$NON-NLS-1$ + } + + /** + * Returns a string representation of the AWTEvent state. + * + * @return a string representation of the AWTEvent state. + */ + public String paramString() { + // nothing to implement: all event types must override this method + return ""; //$NON-NLS-1$ + } + + /** + * Checks whether or not this AWTEvent has been consumed. + * + * @return true, if this AWTEvent has been consumed, false otherwise. + */ + protected boolean isConsumed() { + return consumed; + } + + /** + * Consumes the AWTEvent. + */ + protected void consume() { + consumed = true; + } + + /** + * Convert AWTEvent object to a corresponding (deprecated) Event object. + * + * @return new Event object which is a converted AWTEvent object or null if + * the conversion is not possible + */ + Event getEvent() { + + if (id == ActionEvent.ACTION_PERFORMED) { + ActionEvent ae = (ActionEvent)this; + return converter.convertActionEvent(ae); + + } else if (id == AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED) { + AdjustmentEvent ae = (AdjustmentEvent)this; + return converter.convertAdjustmentEvent(ae); + + // ???AWT + // } else if (id == ComponentEvent.COMPONENT_MOVED + // && source instanceof Window) { + // //the only type of Component events is COMPONENT_MOVED on window + // ComponentEvent ce = (ComponentEvent) this; + // return converter.convertComponentEvent(ce); + + } else if (id >= FocusEvent.FOCUS_FIRST && id <= FocusEvent.FOCUS_LAST) { + // nothing to convert + + // ???AWT + // } else if (id == ItemEvent.ITEM_STATE_CHANGED) { + // ItemEvent ie = (ItemEvent) this; + // return converter.convertItemEvent(ie); + + } else if (id == KeyEvent.KEY_PRESSED || id == KeyEvent.KEY_RELEASED) { + KeyEvent ke = (KeyEvent)this; + return converter.convertKeyEvent(ke); + } else if (id >= MouseEvent.MOUSE_FIRST && id <= MouseEvent.MOUSE_LAST) { + MouseEvent me = (MouseEvent)this; + return converter.convertMouseEvent(me); + } else if (id == WindowEvent.WINDOW_CLOSING || id == WindowEvent.WINDOW_ICONIFIED + || id == WindowEvent.WINDOW_DEICONIFIED) { + // nothing to convert + } else { + return null; + } + return new Event(source, id, null); + } + + /** + * The class EventDescriptor. + */ + static final class EventDescriptor { + + /** + * The event mask. + */ + final long eventMask; + + /** + * The listener type. + */ + final Class<? extends EventListener> listenerType; + + /** + * Instantiates a new event descriptor. + * + * @param eventMask + * the event mask. + * @param listenerType + * the listener type. + */ + EventDescriptor(long eventMask, Class<? extends EventListener> listenerType) { + this.eventMask = eventMask; + this.listenerType = listenerType; + } + + } + + /** + * The class EventTypeLookup. + */ + static final class EventTypeLookup { + + /** + * The last event. + */ + private AWTEvent lastEvent = null; + + /** + * The last event descriptor. + */ + private EventDescriptor lastEventDescriptor = null; + + /** + * Gets the event descriptor. + * + * @param event + * the event. + * @return the event descriptor. + */ + EventDescriptor getEventDescriptor(AWTEvent event) { + synchronized (this) { + if (event != lastEvent) { + lastEvent = event; + lastEventDescriptor = eventsMap.get(new Integer(event.id)); + } + + return lastEventDescriptor; + } + } + + /** + * Gets the event mask. + * + * @param event + * the event. + * @return the event mask. + */ + long getEventMask(AWTEvent event) { + final EventDescriptor ed = getEventDescriptor(event); + return ed == null ? -1 : ed.eventMask; + } + } + + /** + * The class EventConverter. + */ + static final class EventConverter { + + /** + * The constant OLD_MOD_MASK. + */ + static final int OLD_MOD_MASK = Event.ALT_MASK | Event.CTRL_MASK | Event.META_MASK + | Event.SHIFT_MASK; + + /** + * Convert action event. + * + * @param ae + * the ae. + * @return the event. + */ + Event convertActionEvent(ActionEvent ae) { + Event evt = new Event(ae.getSource(), ae.getID(), ae.getActionCommand()); + evt.when = ae.getWhen(); + evt.modifiers = ae.getModifiers() & OLD_MOD_MASK; + + /* + * if (source instanceof Button) { arg = ((Button) + * source).getLabel(); } else if (source instanceof Checkbox) { arg + * = new Boolean(((Checkbox) source).getState()); } else if (source + * instanceof CheckboxMenuItem) { arg = ((CheckboxMenuItem) + * source).getLabel(); } else if (source instanceof Choice) { arg = + * ((Choice) source).getSelectedItem(); } else if (source instanceof + * List) { arg = ((List) source).getSelectedItem(); } else if + * (source instanceof MenuItem) { arg = ((MenuItem) + * source).getLabel(); } else if (source instanceof TextField) { arg + * = ((TextField) source).getText(); } + */ + return evt; + } + + /** + * Convert adjustment event. + * + * @param ae + * the ae. + * @return the event. + */ + Event convertAdjustmentEvent(AdjustmentEvent ae) { + // TODO: Event.SCROLL_BEGIN/SCROLL_END + return new Event(ae.source, ae.id + ae.getAdjustmentType() - 1, new Integer(ae + .getValue())); + } + + /** + * Convert component event. + * + * @param ce + * the ce. + * @return the event. + */ + Event convertComponentEvent(ComponentEvent ce) { + Component comp = ce.getComponent(); + Event evt = new Event(comp, Event.WINDOW_MOVED, null); + evt.x = comp.getX(); + evt.y = comp.getY(); + return evt; + } + + // ???AWT + /* + * Event convertItemEvent(ItemEvent ie) { int oldId = ie.id + + * ie.getStateChange() - 1; Object source = ie.source; int idx = -1; if + * (source instanceof List) { List list = (List) source; idx = + * list.getSelectedIndex(); } else if (source instanceof Choice) { + * Choice choice = (Choice) source; idx = choice.getSelectedIndex(); } + * Object arg = idx >= 0 ? new Integer(idx) : null; return new + * Event(source, oldId, arg); } + */ + + /** + * Convert key event. + * + * @param ke + * the ke. + * @return the event. + */ + Event convertKeyEvent(KeyEvent ke) { + int oldId = ke.id; + // leave only old Event's modifiers + + int mod = ke.getModifiers() & OLD_MOD_MASK; + Component comp = ke.getComponent(); + char keyChar = ke.getKeyChar(); + int keyCode = ke.getKeyCode(); + int key = convertKey(keyChar, keyCode); + if (key >= Event.HOME && key <= Event.INSERT) { + oldId += 2; // non-ASCII key -> action key + } + return new Event(comp, ke.getWhen(), oldId, 0, 0, key, mod); + } + + /** + * Convert mouse event. + * + * @param me + * the me. + * @return the event. + */ + Event convertMouseEvent(MouseEvent me) { + int id = me.id; + if (id != MouseEvent.MOUSE_CLICKED) { + Event evt = new Event(me.source, id, null); + evt.x = me.getX(); + evt.y = me.getY(); + int mod = me.getModifiers(); + // in Event modifiers mean button number for mouse events: + evt.modifiers = mod & (Event.ALT_MASK | Event.META_MASK); + if (id == MouseEvent.MOUSE_PRESSED) { + evt.clickCount = me.getClickCount(); + } + return evt; + } + return null; + } + + /** + * Convert key. + * + * @param keyChar + * the key char. + * @param keyCode + * the key code. + * @return the int. + */ + int convertKey(char keyChar, int keyCode) { + int key; + // F1 - F12 + if (keyCode >= KeyEvent.VK_F1 && keyCode <= KeyEvent.VK_F12) { + key = Event.F1 + keyCode - KeyEvent.VK_F1; + } else { + switch (keyCode) { + default: // non-action key + key = keyChar; + break; + // action keys: + case KeyEvent.VK_HOME: + key = Event.HOME; + break; + case KeyEvent.VK_END: + key = Event.END; + break; + case KeyEvent.VK_PAGE_UP: + key = Event.PGUP; + break; + case KeyEvent.VK_PAGE_DOWN: + key = Event.PGDN; + break; + case KeyEvent.VK_UP: + key = Event.UP; + break; + case KeyEvent.VK_DOWN: + key = Event.DOWN; + break; + case KeyEvent.VK_LEFT: + key = Event.LEFT; + break; + case KeyEvent.VK_RIGHT: + key = Event.RIGHT; + break; + case KeyEvent.VK_PRINTSCREEN: + key = Event.PRINT_SCREEN; + break; + case KeyEvent.VK_SCROLL_LOCK: + key = Event.SCROLL_LOCK; + break; + case KeyEvent.VK_CAPS_LOCK: + key = Event.CAPS_LOCK; + break; + case KeyEvent.VK_NUM_LOCK: + key = Event.NUM_LOCK; + break; + case KeyEvent.VK_PAUSE: + key = Event.PAUSE; + break; + case KeyEvent.VK_INSERT: + key = Event.INSERT; + break; + } + } + return key; + } + + } + +} diff --git a/awt/java/awt/AWTException.java b/awt/java/awt/AWTException.java new file mode 100644 index 0000000..6590b73 --- /dev/null +++ b/awt/java/awt/AWTException.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ + +package java.awt; + +/** + * The AWTException class is used to provide notification and information about + * AWT errors. + * + * @since Android 1.0 + */ +public class AWTException extends Exception { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -1900414231151323879L; + + /** + * Instantiates a new AWT exception with the specified message. + * + * @param msg + * the specific message for current exception. + */ + public AWTException(String msg) { + super(msg); + } + +} diff --git a/awt/java/awt/AWTKeyStroke.java b/awt/java/awt/AWTKeyStroke.java new file mode 100644 index 0000000..f01f6f0 --- /dev/null +++ b/awt/java/awt/AWTKeyStroke.java @@ -0,0 +1,712 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev + * @version $Revision$ + */ + +package java.awt; + +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The AWTKeyStroke holds all of the information for the complete act of + * typing a character. This includes the events that are generated when + * the key is pressed, released, or typed (pressed and released generating + * a Unicode character result) which are associated with the event + * objects KeyEvent.KEY_PRESSED, KeyEvent.KEY_RELEASED, or KeyEvent.KEY_TYPED. + * It also holds information about which modifiers (such as control or + * shift) were used in conjunction with the keystroke. The following masks + * are available to identify the modifiers: + * <ul> + * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK</li> + * <li>java.awt.event.InputEvent.ALT_DOWN_MASK</li> + * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK</li> + * <li>java.awt.event.InputEvent.META_DOWN_MASK</li> + * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK</li> + * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK</li> + * <li>java.awt.event.InputEvent.ALT_MASK</li> + * <li>java.awt.event.InputEvent.CTRL_MASK</li> + * <li>java.awt.event.InputEvent.META_MASK</li> + * <li>java.awt.event.InputEvent.SHIFT_MASK</li> + * </ul> + * <br> + * The AWTKeyStroke is unique, and applications should not create their own + * instances of AWTKeyStroke. All applications should use getAWTKeyStroke + * methods for obtaining instances of AWTKeyStroke. + * + * @since Android 1.0 + */ +public class AWTKeyStroke implements Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -6430539691155161871L; + + /** + * The Constant cache. + */ + private static final Map<AWTKeyStroke, AWTKeyStroke> cache = new HashMap<AWTKeyStroke, AWTKeyStroke>(); // Map + + // < + // AWTKeyStroke + // , + // ? + // extends + // AWTKeyStroke + // > + + /** + * The Constant keyEventTypesMap. + */ + private static final Map<Integer, String> keyEventTypesMap = new HashMap<Integer, String>(); // Map + + // < + // int + // , + // String + // > + + private static Constructor<?> subConstructor; + + static { + keyEventTypesMap.put(new Integer(KeyEvent.KEY_PRESSED), "pressed"); //$NON-NLS-1$ + keyEventTypesMap.put(new Integer(KeyEvent.KEY_RELEASED), "released"); //$NON-NLS-1$ + keyEventTypesMap.put(new Integer(KeyEvent.KEY_TYPED), "typed"); //$NON-NLS-1$ + } + + /** + * The key char. + */ + private char keyChar; + + /** + * The key code. + */ + private int keyCode; + + /** + * The modifiers. + */ + private int modifiers; + + /** + * The on key release. + */ + private boolean onKeyRelease; + + /** + * Instantiates a new AWTKeyStroke. getAWTKeyStroke method should be used by + * applications code. + * + * @param keyChar + * the key char. + * @param keyCode + * the key code. + * @param modifiers + * the modifiers. + * @param onKeyRelease + * true if AWTKeyStroke is for a key release, false otherwise. + */ + protected AWTKeyStroke(char keyChar, int keyCode, int modifiers, boolean onKeyRelease) { + setAWTKeyStroke(keyChar, keyCode, modifiers, onKeyRelease); + } + + /** + * Sets the AWT key stroke. + * + * @param keyChar + * the key char. + * @param keyCode + * the key code. + * @param modifiers + * the modifiers. + * @param onKeyRelease + * the on key release. + */ + private void setAWTKeyStroke(char keyChar, int keyCode, int modifiers, boolean onKeyRelease) { + this.keyChar = keyChar; + this.keyCode = keyCode; + this.modifiers = modifiers; + this.onKeyRelease = onKeyRelease; + } + + /** + * Instantiates a new AWTKeyStroke with default parameters: + * KeyEvent.CHAR_UNDEFINED key char, KeyEvent.VK_UNDEFINED key code, without + * modifiers and false key realized value. + */ + protected AWTKeyStroke() { + this(KeyEvent.CHAR_UNDEFINED, KeyEvent.VK_UNDEFINED, 0, false); + } + + /** + * Returns the unique number value for AWTKeyStroke object. + * + * @return the integer unique value of the AWTKeyStroke object. + */ + @Override + public int hashCode() { + return modifiers + (keyCode != KeyEvent.VK_UNDEFINED ? keyCode : keyChar) + + (onKeyRelease ? -1 : 0); + } + + /** + * Gets the set of modifiers for the AWTKeyStroke object. + * + * @return the integer value which contains modifiers. + */ + public final int getModifiers() { + return modifiers; + } + + /** + * Compares this AWTKeyStroke object to the specified object. + * + * @param anObject + * the specified AWTKeyStroke object to compare with this + * instance. + * @return true if objects are identical, false otherwise. + */ + @Override + public final boolean equals(Object anObject) { + if (anObject instanceof AWTKeyStroke) { + AWTKeyStroke key = (AWTKeyStroke)anObject; + return ((key.keyCode == keyCode) && (key.keyChar == keyChar) + && (key.modifiers == modifiers) && (key.onKeyRelease == onKeyRelease)); + } + return false; + } + + /** + * Returns the string representation of the AWTKeyStroke. This string should + * contain key stroke properties. + * + * @return the string representation of the AWTKeyStroke. + */ + @Override + public String toString() { + int type = getKeyEventType(); + return InputEvent.getModifiersExText(getModifiers()) + " " + //$NON-NLS-1$ + keyEventTypesMap.get(new Integer(type)) + " " + //$NON-NLS-1$ + (type == KeyEvent.KEY_TYPED ? new String(new char[] { + keyChar + }) : KeyEvent.getKeyText(keyCode)); + } + + /** + * Gets the key code for the AWTKeyStroke object. + * + * @return the key code for the AWTKeyStroke object. + */ + public final int getKeyCode() { + return keyCode; + } + + /** + * Gets the key character for the AWTKeyStroke object. + * + * @return the key character for the AWTKeyStroke object. + */ + public final char getKeyChar() { + return keyChar; + } + + /** + * Gets the AWT key stroke. + * + * @param keyChar + * the key char. + * @param keyCode + * the key code. + * @param modifiers + * the modifiers. + * @param onKeyRelease + * the on key release. + * @return the AWT key stroke. + */ + private static AWTKeyStroke getAWTKeyStroke(char keyChar, int keyCode, int modifiers, + boolean onKeyRelease) { + AWTKeyStroke key = newInstance(keyChar, keyCode, modifiers, onKeyRelease); + + AWTKeyStroke value = cache.get(key); + if (value == null) { + value = key; + cache.put(key, value); + } + return value; + } + + /** + * New instance. + * + * @param keyChar + * the key char. + * @param keyCode + * the key code. + * @param modifiers + * the modifiers. + * @param onKeyRelease + * the on key release. + * @return the AWT key stroke. + */ + private static AWTKeyStroke newInstance(char keyChar, int keyCode, int modifiers, + boolean onKeyRelease) { + AWTKeyStroke key; + // ???AWT + // if (subConstructor == null) { + key = new AWTKeyStroke(); + // ???AWT + // } else { + // try { + // key = (AWTKeyStroke) subConstructor.newInstance(); + // } catch (Exception e) { + // throw new RuntimeException(e); + // } + // } + int allModifiers = getAllModifiers(modifiers); + key.setAWTKeyStroke(keyChar, keyCode, allModifiers, onKeyRelease); + return key; + } + + /** + * Adds the mask. + * + * @param mod + * the mod. + * @param mask + * the mask. + * @return the int. + */ + private static int addMask(int mod, int mask) { + return ((mod & mask) != 0) ? (mod | mask) : mod; + } + + /** + * Return all (old & new) modifiers corresponding to. + * + * @param mod + * old or new modifiers. + * @return old and new modifiers together. + */ + static int getAllModifiers(int mod) { + int allMod = mod; + int shift = (InputEvent.SHIFT_MASK | InputEvent.SHIFT_DOWN_MASK); + int ctrl = (InputEvent.CTRL_MASK | InputEvent.CTRL_DOWN_MASK); + int meta = (InputEvent.META_MASK | InputEvent.META_DOWN_MASK); + int alt = (InputEvent.ALT_MASK | InputEvent.ALT_DOWN_MASK); + int altGr = (InputEvent.ALT_GRAPH_MASK | InputEvent.ALT_GRAPH_DOWN_MASK); + // button modifiers are not converted between old & new + + allMod = addMask(allMod, shift); + allMod = addMask(allMod, ctrl); + allMod = addMask(allMod, meta); + allMod = addMask(allMod, alt); + allMod = addMask(allMod, altGr); + + return allMod; + } + + /** + * Returns an instance of AWTKeyStroke for parsed string. The string must + * have the following syntax: + *<p> + * <modifiers>* (<typedID> | <pressedReleasedID>) + *<p> + * modifiers := shift | control | ctrl | meta | alt | altGraph <br> + * typedID := typed <typedKey> <br> + * typedKey := string of length 1 giving the Unicode character. <br> + * pressedReleasedID := (pressed | released) <key> <br> + * key := KeyEvent key code name, i.e. the name following "VK_". + * <p> + * + * @param s + * the String which contains key stroke parameters. + * @return the AWTKeyStroke for string. + * @throws IllegalArgumentException + * if string has incorrect format or null. + */ + public static AWTKeyStroke getAWTKeyStroke(String s) { + if (s == null) { + // awt.65=null argument + throw new IllegalArgumentException(Messages.getString("awt.65")); //$NON-NLS-1$ + } + + StringTokenizer tokenizer = new StringTokenizer(s); + + Boolean release = null; + int modifiers = 0; + int keyCode = KeyEvent.VK_UNDEFINED; + char keyChar = KeyEvent.CHAR_UNDEFINED; + boolean typed = false; + long modifier = 0; + String token = null; + do { + token = getNextToken(tokenizer); + modifier = parseModifier(token); + modifiers |= modifier; + } while (modifier > 0); + + typed = parseTypedID(token); + + if (typed) { + token = getNextToken(tokenizer); + keyChar = parseTypedKey(token); + + } + if (keyChar == KeyEvent.CHAR_UNDEFINED) { + release = parsePressedReleasedID(token); + if (release != null) { + token = getNextToken(tokenizer); + } + keyCode = parseKey(token); + } + if (tokenizer.hasMoreTokens()) { + // awt.66=Invalid format + throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$ + } + + return getAWTKeyStroke(keyChar, keyCode, modifiers, release == Boolean.TRUE); + } + + /** + * Gets the next token. + * + * @param tokenizer + * the tokenizer. + * @return the next token. + */ + private static String getNextToken(StringTokenizer tokenizer) { + try { + return tokenizer.nextToken(); + } catch (NoSuchElementException exception) { + // awt.66=Invalid format + throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$ + } + } + + /** + * Gets the key code. + * + * @param s + * the s. + * @return the key code. + */ + static int getKeyCode(String s) { + try { + Field vk = KeyEvent.class.getField("VK_" + s); //$NON-NLS-1$ + return vk.getInt(null); + } catch (Exception e) { + if (s.length() != 1) { + // awt.66=Invalid format + throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$ + } + return KeyEvent.VK_UNDEFINED; + } + } + + /** + * Gets an instance of the AWTKeyStroke for specified character. + * + * @param keyChar + * the keyboard character value. + * @return a AWTKeyStroke for specified character. + */ + public static AWTKeyStroke getAWTKeyStroke(char keyChar) { + return getAWTKeyStroke(keyChar, KeyEvent.VK_UNDEFINED, 0, false); + } + + /** + * Returns an instance of AWTKeyStroke for a given key code, set of + * modifiers, and specified key released flag value. The key codes are + * defined in java.awt.event.KeyEvent class. The set of modifiers is given + * as a bitwise combination of masks taken from the following list: + * <ul> + * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK</li> <li> + * java.awt.event.InputEvent.ALT_DOWN_MASK</li> <li> + * java.awt.event.InputEvent.CTRL_DOWN_MASK</li> <li> + * java.awt.event.InputEvent.META_DOWN_MASK</li> <li> + * java.awt.event.InputEvent.SHIFT_DOWN_MASK</li> <li> + * java.awt.event.InputEvent.ALT_GRAPH_MASK</li> <li> + * java.awt.event.InputEvent.ALT_MASK</li> <li> + * java.awt.event.InputEvent.CTRL_MASK</li> <li> + * java.awt.event.InputEvent.META_MASK</li> <li> + * java.awt.event.InputEvent.SHIFT_MASK</li> + * </ul> + * <br> + * + * @param keyCode + * the specified key code of keyboard. + * @param modifiers + * the bit set of modifiers. + * @param onKeyRelease + * the value which represents whether this AWTKeyStroke shall + * represents a key release. + * @return the AWTKeyStroke. + */ + public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers, boolean onKeyRelease) { + return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, keyCode, modifiers, onKeyRelease); + } + + /** + * Returns AWTKeyStroke for a specified character and set of modifiers. The + * set of modifiers is given as a bitwise combination of masks taken from + * the following list: + * <ul> + * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK</li> <li> + * java.awt.event.InputEvent.ALT_DOWN_MASK</li> <li> + * java.awt.event.InputEvent.CTRL_DOWN_MASK</li> <li> + * java.awt.event.InputEvent.META_DOWN_MASK</li> <li> + * java.awt.event.InputEvent.SHIFT_DOWN_MASK</li> <li> + * java.awt.event.InputEvent.ALT_GRAPH_MASK</li> <li> + * java.awt.event.InputEvent.ALT_MASK</li> <li> + * java.awt.event.InputEvent.CTRL_MASK</li> <li> + * java.awt.event.InputEvent.META_MASK</li> <li> + * java.awt.event.InputEvent.SHIFT_MASK</li> + * </ul> + * + * @param keyChar + * the Character object which represents keyboard character + * value. + * @param modifiers + * the bit set of modifiers. + * @return the AWTKeyStroke object. + * @throws IllegalArgumentException + * if keyChar value is null. + */ + public static AWTKeyStroke getAWTKeyStroke(Character keyChar, int modifiers) { + if (keyChar == null) { + // awt.01='{0}' parameter is null + throw new IllegalArgumentException(Messages.getString("awt.01", "keyChar")); //$NON-NLS-1$ //$NON-NLS-2$ + } + return getAWTKeyStroke(keyChar.charValue(), KeyEvent.VK_UNDEFINED, modifiers, false); + } + + /** + * Returns an instance of AWTKeyStroke for a specified key code and set of + * modifiers. The key codes are defined in java.awt.event.KeyEvent class. + * The set of modifiers is given as a bitwise combination of masks taken + * from the following list: + * <ul> + * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK</li> <li> + * java.awt.event.InputEvent.ALT_DOWN_MASK</li> <li> + * java.awt.event.InputEvent.CTRL_DOWN_MASK</li> <li> + * java.awt.event.InputEvent.META_DOWN_MASK</li> <li> + * java.awt.event.InputEvent.SHIFT_DOWN_MASK</li> <li> + * java.awt.event.InputEvent.ALT_GRAPH_MASK</li> <li> + * java.awt.event.InputEvent.ALT_MASK</li> <li> + * java.awt.event.InputEvent.CTRL_MASK</li> <li> + * java.awt.event.InputEvent.META_MASK</li> <li> + * java.awt.event.InputEvent.SHIFT_MASK</li> + * </ul> + * + * @param keyCode + * the specified key code of keyboard. + * @param modifiers + * the bit set of modifiers. + * @return the AWTKeyStroke. + */ + public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers) { + return getAWTKeyStroke(keyCode, modifiers, false); + } + + /** + * Gets the AWTKeyStroke for a key event. This method obtains the key char + * and key code from the specified key event. + * + * @param anEvent + * the key event which identifies the desired AWTKeyStroke. + * @return the AWTKeyStroke for the key event. + */ + public static AWTKeyStroke getAWTKeyStrokeForEvent(KeyEvent anEvent) { + int id = anEvent.getID(); + char undef = KeyEvent.CHAR_UNDEFINED; + char keyChar = (id == KeyEvent.KEY_TYPED ? anEvent.getKeyChar() : undef); + int keyCode = (keyChar == undef ? anEvent.getKeyCode() : KeyEvent.VK_UNDEFINED); + return getAWTKeyStroke(keyChar, keyCode, anEvent.getModifiersEx(), + id == KeyEvent.KEY_RELEASED); + } + + /** + * Gets the key event type for the AWTKeyStroke object. + * + * @return the key event type: KeyEvent.KEY_PRESSED, KeyEvent.KEY_TYPED, or + * KeyEvent.KEY_RELEASED. + */ + public final int getKeyEventType() { + if (keyCode == KeyEvent.VK_UNDEFINED) { + return KeyEvent.KEY_TYPED; + } + return (onKeyRelease ? KeyEvent.KEY_RELEASED : KeyEvent.KEY_PRESSED); + } + + /** + * Returns true if the key event is associated with the AWTKeyStroke is + * KEY_RELEASED, false otherwise. + * + * @return true, if if the key event associated with the AWTKeyStroke is + * KEY_RELEASED, false otherwise. + */ + public final boolean isOnKeyRelease() { + return onKeyRelease; + } + + /** + * Read resolve. + * + * @return the object. + * @throws ObjectStreamException + * the object stream exception. + */ + protected Object readResolve() throws ObjectStreamException { + return getAWTKeyStroke(this.keyChar, this.keyCode, this.modifiers, this.onKeyRelease); + } + + /** + * Register subclass. + * + * @param subclass + * the subclass. + */ + protected static void registerSubclass(Class<?> subclass) { + // ???AWT + /* + * if (subclass == null) { // awt.01='{0}' parameter is null throw new + * IllegalArgumentException(Messages.getString("awt.01", "subclass")); + * //$NON-NLS-1$ //$NON-NLS-2$ } if (! + * AWTKeyStroke.class.isAssignableFrom(subclass)) { // awt.67=subclass + * is not derived from AWTKeyStroke throw new + * ClassCastException(Messages.getString("awt.67")); //$NON-NLS-1$ } try + * { subConstructor = subclass.getDeclaredConstructor(); + * subConstructor.setAccessible(true); } catch (SecurityException e) { + * throw new RuntimeException(e); } catch (NoSuchMethodException e) { // + * awt.68=subclass could not be instantiated throw new + * IllegalArgumentException(Messages.getString("awt.68")); //$NON-NLS-1$ + * } cache.clear(); //flush the cache + */ + } + + /** + * Parses the modifier. + * + * @param strMod + * the str mod. + * @return the long. + */ + private static long parseModifier(String strMod) { + long modifiers = 0l; + if (strMod.equals("shift")) { //$NON-NLS-1$ + modifiers |= InputEvent.SHIFT_DOWN_MASK; + } else if (strMod.equals("control") || strMod.equals("ctrl")) { //$NON-NLS-1$ //$NON-NLS-2$ + modifiers |= InputEvent.CTRL_DOWN_MASK; + } else if (strMod.equals("meta")) { //$NON-NLS-1$ + modifiers |= InputEvent.META_DOWN_MASK; + } else if (strMod.equals("alt")) { //$NON-NLS-1$ + modifiers |= InputEvent.ALT_DOWN_MASK; + } else if (strMod.equals("altGraph")) { //$NON-NLS-1$ + modifiers |= InputEvent.ALT_GRAPH_DOWN_MASK; + } else if (strMod.equals("button1")) { //$NON-NLS-1$ + modifiers |= InputEvent.BUTTON1_DOWN_MASK; + } else if (strMod.equals("button2")) { //$NON-NLS-1$ + modifiers |= InputEvent.BUTTON2_DOWN_MASK; + } else if (strMod.equals("button3")) { //$NON-NLS-1$ + modifiers |= InputEvent.BUTTON3_DOWN_MASK; + } + return modifiers; + } + + /** + * Parses the typed id. + * + * @param strTyped + * the str typed. + * @return true, if successful. + */ + private static boolean parseTypedID(String strTyped) { + if (strTyped.equals("typed")) { //$NON-NLS-1$ + return true; + } + + return false; + } + + /** + * Parses the typed key. + * + * @param strChar + * the str char. + * @return the char. + */ + private static char parseTypedKey(String strChar) { + char keyChar = KeyEvent.CHAR_UNDEFINED; + + if (strChar.length() != 1) { + // awt.66=Invalid format + throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$ + } + keyChar = strChar.charAt(0); + return keyChar; + } + + /** + * Parses the pressed released id. + * + * @param str + * the str. + * @return the boolean. + */ + private static Boolean parsePressedReleasedID(String str) { + + if (str.equals("pressed")) { //$NON-NLS-1$ + return Boolean.FALSE; + } else if (str.equals("released")) { //$NON-NLS-1$ + return Boolean.TRUE; + } + return null; + } + + /** + * Parses the key. + * + * @param strCode + * the str code. + * @return the int. + */ + private static int parseKey(String strCode) { + int keyCode = KeyEvent.VK_UNDEFINED; + + keyCode = getKeyCode(strCode); + + if (keyCode == KeyEvent.VK_UNDEFINED) { + // awt.66=Invalid format + throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$ + } + return keyCode; + } +} diff --git a/awt/java/awt/AWTListenerList.java b/awt/java/awt/AWTListenerList.java new file mode 100644 index 0000000..3327d63 --- /dev/null +++ b/awt/java/awt/AWTListenerList.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.awt; + +import java.util.EventListener; + +import org.apache.harmony.awt.ListenerList; + +final class AWTListenerList<T extends EventListener> extends ListenerList<T> { + private static final long serialVersionUID = -2622077171532840953L; + + private final Component owner; + + AWTListenerList() { + super(); + this.owner = null; + } + + AWTListenerList(Component owner) { + super(); + this.owner = owner; + } + + @Override + public void addUserListener(T listener) { + super.addUserListener(listener); + + if (owner != null) { + owner.deprecatedEventHandler = false; + } + } +} diff --git a/awt/java/awt/AWTPermission.java b/awt/java/awt/AWTPermission.java new file mode 100644 index 0000000..4bd8357 --- /dev/null +++ b/awt/java/awt/AWTPermission.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ + +package java.awt; + +import java.security.BasicPermission; + +/** + * The AWTPermission specifies the name of the permission and the corresponding + * action list. + * + * @since Android 1.0 + */ +public final class AWTPermission extends BasicPermission { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 8890392402588814465L; + + /** + * Instantiates a new AWTPermission with defined name and actions. + * + * @param name + * the name of a new AWTPermission. + * @param actions + * the actions of a new AWTPermission. + */ + public AWTPermission(String name, String actions) { + super(name, actions); + } + + /** + * Instantiates a new AWT permission with the defined name. + * + * @param name + * the name of a new AWTPermission. + */ + public AWTPermission(String name) { + super(name); + } + +} diff --git a/awt/java/awt/ActiveEvent.java b/awt/java/awt/ActiveEvent.java new file mode 100644 index 0000000..7044623 --- /dev/null +++ b/awt/java/awt/ActiveEvent.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ + +package java.awt; + +/** + * This interface defines events that know how to dispatch themselves. Such + * event can be placed upon the event queue and its dispatch method will be + * called when the event is dispatched. + * + * @since Android 1.0 + */ +public interface ActiveEvent { + + /** + * Dispatches the event to the listeners of the event's source, or does + * whatever it is this event is supposed to do. + */ + public void dispatch(); + +} diff --git a/awt/java/awt/Adjustable.java b/awt/java/awt/Adjustable.java new file mode 100644 index 0000000..baf80f7 --- /dev/null +++ b/awt/java/awt/Adjustable.java @@ -0,0 +1,166 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ + +package java.awt; + +import java.awt.event.AdjustmentListener; + +/** + * The Adjustable interface represents an adjustable numeric value contained + * within a bounded range of values, such as the current location in scrollable + * region or the value of a gauge. + * + * @since Android 1.0 + */ +public interface Adjustable { + + /** + * The Constant HORIZONTAL indicates that the Adjustable's orientation is + * horizontal. + */ + public static final int HORIZONTAL = 0; + + /** + * The Constant VERTICAL indicates that the Adjustable's orientation is + * vertical. + */ + public static final int VERTICAL = 1; + + /** + * The Constant NO_ORIENTATION indicates that the Adjustable has no + * orientation. + */ + public static final int NO_ORIENTATION = 2; + + /** + * Gets the value of the Adjustable. + * + * @return the current value of the Adjustable. + */ + public int getValue(); + + /** + * Sets the value to the Adjustable object. + * + * @param a0 + * the new value of the Adjustable object. + */ + public void setValue(int a0); + + /** + * Adds the AdjustmentListener to current Adjustment. + * + * @param a0 + * the AdjustmentListener object. + */ + public void addAdjustmentListener(AdjustmentListener a0); + + /** + * Gets the block increment of the Adjustable. + * + * @return the block increment of the Adjustable. + */ + public int getBlockIncrement(); + + /** + * Gets the maximum value of the Adjustable. + * + * @return the maximum value of the Adjustable. + */ + public int getMaximum(); + + /** + * Gets the minimum value of the Adjustable. + * + * @return the minimum value of the Adjustable. + */ + public int getMinimum(); + + /** + * Gets the orientation of the Adjustable. + * + * @return the orientation of the Adjustable. + */ + public int getOrientation(); + + /** + * Gets the unit increment of the Adjustable. + * + * @return the unit increment of the Adjustable. + */ + public int getUnitIncrement(); + + /** + * Gets the visible amount of the Adjustable. + * + * @return the visible amount of the Adjustable. + */ + public int getVisibleAmount(); + + /** + * Removes the adjustment listener of the Adjustable. + * + * @param a0 + * the specified AdjustmentListener to be removed. + */ + public void removeAdjustmentListener(AdjustmentListener a0); + + /** + * Sets the block increment for the Adjustable. + * + * @param a0 + * the new block increment. + */ + public void setBlockIncrement(int a0); + + /** + * Sets the maximum value of the Adjustable. + * + * @param a0 + * the new maximum of the Adjustable. + */ + public void setMaximum(int a0); + + /** + * Sets the minimum value of the Adjustable. + * + * @param a0 + * the new minimum of the Adjustable. + */ + public void setMinimum(int a0); + + /** + * Sets the unit increment of the Adjustable. + * + * @param a0 + * the new unit increment of the Adjustable. + */ + public void setUnitIncrement(int a0); + + /** + * Sets the visible amount of the Adjustable. + * + * @param a0 + * the new visible amount of the Adjustable. + */ + public void setVisibleAmount(int a0); + +} diff --git a/awt/java/awt/AlphaComposite.java b/awt/java/awt/AlphaComposite.java new file mode 100644 index 0000000..8389eb4 --- /dev/null +++ b/awt/java/awt/AlphaComposite.java @@ -0,0 +1,352 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt; + +import java.awt.Composite; +import java.awt.CompositeContext; +import java.awt.RenderingHints; +import java.awt.image.ColorModel; + +import org.apache.harmony.awt.gl.ICompositeContext; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The AlphaComposite class defines a basic alpha compositing rules for + * combining source and destination colors to achieve blending and transparency + * effects with graphics and images. + * + * @since Android 1.0 + */ +public final class AlphaComposite implements Composite { + + /** + * The Constant CLEAR indicates that both the color and the alpha of the + * destination are cleared (Porter-Duff Clear rule). + */ + public static final int CLEAR = 1; + + /** + * The Constant SRC indicates that the source is copied to the destination + * (Porter-Duff Source rule). + */ + public static final int SRC = 2; + + /** + * The Constant DST indicates that the destination is left untouched + * (Porter-Duff Destination rule). + */ + public static final int DST = 9; + + /** + * The Constant SRC_OVER indicates that the source is composited over the + * destination (Porter-Duff Source Over Destination rule). + */ + public static final int SRC_OVER = 3; + + /** + * The Constant DST_OVER indicates that The destination is composited over + * the source and the result replaces the destination (Porter-Duff + * Destination Over Source rule). + */ + public static final int DST_OVER = 4; + + /** + * The Constant SRC_IN indicates that the part of the source lying inside of + * the destination replaces the destination (Porter-Duff Source In + * Destination rule). + */ + public static final int SRC_IN = 5; + + /** + * The Constant DST_IN indicates that the part of the destination lying + * inside of the source replaces the destination (Porter-Duff Destination In + * Source rule). + */ + public static final int DST_IN = 6; + + /** + * The Constant SRC_OUT indicates that the part of the source lying outside + * of the destination replaces the destination (Porter-Duff Source Held Out + * By Destination rule). + */ + public static final int SRC_OUT = 7; + + /** + * The Constant DST_OUT indicates that the part of the destination lying + * outside of the source replaces the destination (Porter-Duff Destination + * Held Out By Source rule). + */ + public static final int DST_OUT = 8; + + /** + * The Constant SRC_ATOP indicates that the part of the source lying inside + * of the destination is composited onto the destination (Porter-Duff Source + * Atop Destination rule). + */ + public static final int SRC_ATOP = 10; + + /** + * The Constant DST_ATOP indicates that the part of the destination lying + * inside of the source is composited over the source and replaces the + * destination (Porter-Duff Destination Atop Source rule). + */ + public static final int DST_ATOP = 11; + + /** + * The Constant XOR indicates that the part of the source that lies outside + * of the destination is combined with the part of the destination that lies + * outside of the source (Porter-Duff Source Xor Destination rule). + */ + public static final int XOR = 12; + + /** + * AlphaComposite object with the opaque CLEAR rule and an alpha of 1.0f. + */ + public static final AlphaComposite Clear = new AlphaComposite(CLEAR); + + /** + * AlphaComposite object with the opaque SRC rule and an alpha of 1.0f. + */ + public static final AlphaComposite Src = new AlphaComposite(SRC); + + /** + * AlphaComposite object with the opaque DST rule and an alpha of 1.0f. + */ + public static final AlphaComposite Dst = new AlphaComposite(DST); + + /** + * AlphaComposite object with the opaque SRC_OVER rule and an alpha of 1.0f. + */ + public static final AlphaComposite SrcOver = new AlphaComposite(SRC_OVER); + + /** + * AlphaComposite object with the opaque DST_OVER rule and an alpha of 1.0f. + */ + public static final AlphaComposite DstOver = new AlphaComposite(DST_OVER); + + /** + * AlphaComposite object with the opaque SRC_IN rule and an alpha of 1.0f. + */ + public static final AlphaComposite SrcIn = new AlphaComposite(SRC_IN); + + /** + * AlphaComposite object with the opaque DST_IN rule and an alpha of 1.0f. + */ + public static final AlphaComposite DstIn = new AlphaComposite(DST_IN); + + /** + * AlphaComposite object with the opaque SRC_OUT rule and an alpha of 1.0f. + */ + public static final AlphaComposite SrcOut = new AlphaComposite(SRC_OUT); + + /** + * AlphaComposite object with the opaque DST_OUT rule and an alpha of 1.0f. + */ + public static final AlphaComposite DstOut = new AlphaComposite(DST_OUT); + + /** + * AlphaComposite object with the opaque SRC_ATOP rule and an alpha of 1.0f. + */ + public static final AlphaComposite SrcAtop = new AlphaComposite(SRC_ATOP); + + /** + * AlphaComposite object with the opaque DST_ATOP rule and an alpha of 1.0f. + */ + public static final AlphaComposite DstAtop = new AlphaComposite(DST_ATOP); + + /** + * AlphaComposite object with the opaque XOR rule and an alpha of 1.0f. + */ + public static final AlphaComposite Xor = new AlphaComposite(XOR); + + /** + * The rule. + */ + private int rule; + + /** + * The alpha. + */ + private float alpha; + + /** + * Instantiates a new alpha composite. Creates a context for the compositing + * operation. The context contains state that is used in performing the + * compositing operation. + * + * @param rule + * the rule. + * @param alpha + * the alpha. + */ + private AlphaComposite(int rule, float alpha) { + if (rule < CLEAR || rule > XOR) { + // awt.11D=Unknown rule + throw new IllegalArgumentException(Messages.getString("awt.11D")); //$NON-NLS-1$ + } + if (alpha < 0.0f || alpha > 1.0f) { + // awt.11E=Wrong alpha value + throw new IllegalArgumentException(Messages.getString("awt.11E")); //$NON-NLS-1$ + } + + this.rule = rule; + this.alpha = alpha; + } + + /** + * Instantiates a new alpha composite. + * + * @param rule + * the rule. + */ + private AlphaComposite(int rule) { + this(rule, 1.0f); + } + + /** + * Creates a CompositeContext object with the specified source ColorModel, + * destination ColorModel and RenderingHints parameters for a composing + * operation. + * + * @param srcColorModel + * the source's ColorModel. + * @param dstColorModel + * the destination's ColorModel. + * @param hints + * the RenderingHints object. + * @return the CompositeContext object. + * @see java.awt.Composite#createContext(java.awt.image.ColorModel, + * java.awt.image.ColorModel, java.awt.RenderingHints) + */ + public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel, + RenderingHints hints) { + return new ICompositeContext(this, srcColorModel, dstColorModel); + } + + /** + * Compares the AlphaComposite object with the specified object. + * + * @param obj + * the Object to be compared. + * @return true, if the AlphaComposite object is equal to the specified + * object. + */ + @Override + public boolean equals(Object obj) { + if (!(obj instanceof AlphaComposite)) { + return false; + } + AlphaComposite other = (AlphaComposite)obj; + return (this.rule == other.getRule() && this.alpha == other.getAlpha()); + } + + /** + * Returns the hash code of the AlphaComposite object. + * + * @return the hash code of the AlphaComposite object. + */ + @Override + public int hashCode() { + int hash = Float.floatToIntBits(alpha); + int tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= rule; + return hash; + } + + /** + * Gets the compositing rule of this AlphaComposite object. + * + * @return the compositing rule of this AlphaComposite object. + */ + public int getRule() { + return rule; + } + + /** + * Gets the alpha value of this AlphaComposite object; returns 1.0 if this + * AlphaComposite object doesn't have alpha value. + * + * @return the alpha value of this AlphaComposite object or 1.0 if this + * AlphaComposite object doesn't have alpha value. + */ + public float getAlpha() { + return alpha; + } + + /** + * Gets the AlphaComposite instance with the specified rule and alpha value. + * + * @param rule + * the compositing rule. + * @param alpha + * the alpha value. + * @return the AlphaComposite instance. + */ + public static AlphaComposite getInstance(int rule, float alpha) { + if (alpha == 1.0f) { + return getInstance(rule); + } + return new AlphaComposite(rule, alpha); + } + + /** + * Gets the AlphaComposite instance with the specified rule. + * + * @param rule + * the compositing rule. + * @return the AlphaComposite instance. + */ + public static AlphaComposite getInstance(int rule) { + switch (rule) { + case CLEAR: + return Clear; + case SRC: + return Src; + case DST: + return Dst; + case SRC_OVER: + return SrcOver; + case DST_OVER: + return DstOver; + case SRC_IN: + return SrcIn; + case DST_IN: + return DstIn; + case SRC_OUT: + return SrcOut; + case DST_OUT: + return DstOut; + case SRC_ATOP: + return SrcAtop; + case DST_ATOP: + return DstAtop; + case XOR: + return Xor; + default: + // awt.11D=Unknown rule + throw new IllegalArgumentException(Messages.getString("awt.11D")); //$NON-NLS-1$ + } + } + +} diff --git a/awt/java/awt/BasicStroke.java b/awt/java/awt/BasicStroke.java new file mode 100644 index 0000000..2457815 --- /dev/null +++ b/awt/java/awt/BasicStroke.java @@ -0,0 +1,2443 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt; + +import java.awt.geom.GeneralPath; +import java.awt.geom.PathIterator; + +import org.apache.harmony.awt.internal.nls.Messages; +import org.apache.harmony.misc.HashCode; + +/** + * The BasicStroke class specifies a set of rendering attributes for the + * outlines of graphics primitives. The BasicStroke attributes describe the + * shape of the pen which draws the outline of a Shape and the decorations + * applied at the ends and joins of path segments of the Shape. The BasicStroke + * has the following rendering attributes: + * <p> + * <ul> + * <li>line width -the pen width which draws the outlines.</li> + * <li>end caps - indicates the decoration applied to the ends of unclosed + * subpaths and dash segments. The BasicStroke defines three different + * decorations: CAP_BUTT, CAP_ROUND, and CAP_SQUARE.</li> + * <li>line joins - indicates the decoration applied at the intersection of two + * path segments and at the intersection of the endpoints of a subpath. The + * BasicStroke defines three decorations: JOIN_BEVEL, JOIN_MITER, and + * JOIN_ROUND.</li> + * <li>miter limit - the limit to trim a line join that has a JOIN_MITER + * decoration.</li> + * <li>dash attributes - the definition of how to make a dash pattern by + * alternating between opaque and transparent sections</li> + * </ul> + * </p> + * + * @since Android 1.0 + */ +public class BasicStroke implements Stroke { + + /** + * The Constant CAP_BUTT indicates the ends of unclosed subpaths and dash + * segments have no added decoration. + */ + public static final int CAP_BUTT = 0; + + /** + * The Constant CAP_ROUND indicates the ends of unclosed subpaths and dash + * segments have a round decoration. + */ + public static final int CAP_ROUND = 1; + + /** + * The Constant CAP_SQUARE indicates the ends of unclosed subpaths and dash + * segments have a square projection. + */ + public static final int CAP_SQUARE = 2; + + /** + * The Constant JOIN_MITER indicates that path segments are joined by + * extending their outside edges until they meet. + */ + public static final int JOIN_MITER = 0; + + /** + * The Constant JOIN_ROUND indicates that path segments are joined by + * rounding off the corner at a radius of half the line width. + */ + public static final int JOIN_ROUND = 1; + + /** + * The Constant JOIN_BEVEL indicates that path segments are joined by + * connecting the outer corners of their wide outlines with a straight + * segment. + */ + public static final int JOIN_BEVEL = 2; + + /** + * Constants for calculating. + */ + static final int MAX_LEVEL = 20; // Maximal deepness of curve subdivision + + /** + * The Constant CURVE_DELTA. + */ + static final double CURVE_DELTA = 2.0; // Width tolerance + + /** + * The Constant CORNER_ANGLE. + */ + static final double CORNER_ANGLE = 4.0; // Minimum corner angle + + /** + * The Constant CORNER_ZERO. + */ + static final double CORNER_ZERO = 0.01; // Zero angle + + /** + * The Constant CUBIC_ARC. + */ + static final double CUBIC_ARC = 4.0 / 3.0 * (Math.sqrt(2.0) - 1); + + /** + * Stroke width. + */ + float width; + + /** + * Stroke cap type. + */ + int cap; + + /** + * Stroke join type. + */ + int join; + + /** + * Stroke miter limit. + */ + float miterLimit; + + /** + * Stroke dashes array. + */ + float dash[]; + + /** + * Stroke dash phase. + */ + float dashPhase; + + /** + * The temporary pre-calculated values. + */ + double curveDelta; + + /** + * The corner delta. + */ + double cornerDelta; + + /** + * The zero delta. + */ + double zeroDelta; + + /** + * The w2. + */ + double w2; + + /** + * The fmy. + */ + double fmx, fmy; + + /** + * The smy. + */ + double scx, scy, smx, smy; + + /** + * The cy. + */ + double mx, my, cx, cy; + + /** + * The temporary indicators. + */ + boolean isMove; + + /** + * The is first. + */ + boolean isFirst; + + /** + * The check move. + */ + boolean checkMove; + + /** + * The temporary and destination work paths. + */ + BufferedPath dst, lp, rp, sp; + + /** + * Stroke dasher class. + */ + Dasher dasher; + + /** + * Instantiates a new BasicStroke with default width, cap, join, limit, dash + * attributes parameters. The default parameters are a solid line of width + * 1.0, CAP_SQUARE, JOIN_MITER, a miter limit of 10.0, null dash attributes, + * and a dash phase of 0.0f. + */ + public BasicStroke() { + this(1.0f, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f); + } + + /** + * Instantiates a new BasicStroke with the specified width, caps, joins, + * limit, dash attributes, dash phase parameters. + * + * @param width + * the width of BasikStroke. + * @param cap + * the end decoration of BasikStroke. + * @param join + * the join segments decoration. + * @param miterLimit + * the limit to trim the miter join. + * @param dash + * the array with the dashing pattern. + * @param dashPhase + * the offset to start the dashing pattern. + */ + public BasicStroke(float width, int cap, int join, float miterLimit, float[] dash, + float dashPhase) { + if (width < 0.0f) { + // awt.133=Negative width + throw new IllegalArgumentException(Messages.getString("awt.133")); //$NON-NLS-1$ + } + if (cap != CAP_BUTT && cap != CAP_ROUND && cap != CAP_SQUARE) { + // awt.134=Illegal cap + throw new IllegalArgumentException(Messages.getString("awt.134")); //$NON-NLS-1$ + } + if (join != JOIN_MITER && join != JOIN_ROUND && join != JOIN_BEVEL) { + // awt.135=Illegal join + throw new IllegalArgumentException(Messages.getString("awt.135")); //$NON-NLS-1$ + } + if (join == JOIN_MITER && miterLimit < 1.0f) { + // awt.136=miterLimit less than 1.0f + throw new IllegalArgumentException(Messages.getString("awt.136")); //$NON-NLS-1$ + } + if (dash != null) { + if (dashPhase < 0.0f) { + // awt.137=Negative dashPhase + throw new IllegalArgumentException(Messages.getString("awt.137")); //$NON-NLS-1$ + } + if (dash.length == 0) { + // awt.138=Zero dash length + throw new IllegalArgumentException(Messages.getString("awt.138")); //$NON-NLS-1$ + } + ZERO: { + for (int i = 0; i < dash.length; i++) { + if (dash[i] < 0.0) { + // awt.139=Negative dash[{0}] + throw new IllegalArgumentException(Messages.getString("awt.139", i)); //$NON-NLS-1$ + } + if (dash[i] > 0.0) { + break ZERO; + } + } + // awt.13A=All dash lengths zero + throw new IllegalArgumentException(Messages.getString("awt.13A")); //$NON-NLS-1$ + } + } + this.width = width; + this.cap = cap; + this.join = join; + this.miterLimit = miterLimit; + this.dash = dash; + this.dashPhase = dashPhase; + } + + /** + * Instantiates a new BasicStroke with specified width, cap, join, limit and + * default dash attributes parameters. + * + * @param width + * the width of BasikStroke. + * @param cap + * the end decoration of BasikStroke. + * @param join + * the join segments decoration. + * @param miterLimit + * the limit to trim the miter join. + */ + public BasicStroke(float width, int cap, int join, float miterLimit) { + this(width, cap, join, miterLimit, null, 0.0f); + } + + /** + * Instantiates a new BasicStroke with specified width, cap, join and + * default limit and dash attributes parameters. + * + * @param width + * the width of BasikStroke. + * @param cap + * the end decoration of BasikStroke. + * @param join + * the join segments decoration. + */ + public BasicStroke(float width, int cap, int join) { + this(width, cap, join, 10.0f, null, 0.0f); + } + + /** + * Instantiates a new BasicStroke with specified width and default cap, + * join, limit, dash attributes parameters. + * + * @param width + * the width of BasicStroke. + */ + public BasicStroke(float width) { + this(width, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f); + } + + /** + * Gets the line width of the BasicStroke. + * + * @return the line width of the BasicStroke. + */ + public float getLineWidth() { + return width; + } + + /** + * Gets the end cap style of the BasicStroke. + * + * @return the end cap style of the BasicStroke. + */ + public int getEndCap() { + return cap; + } + + /** + * Gets the line join style of the BasicStroke. + * + * @return the line join style of the BasicStroke. + */ + public int getLineJoin() { + return join; + } + + /** + * Gets the miter limit of the BasicStroke (the limit to trim the miter + * join). + * + * @return the miter limit of the BasicStroke. + */ + public float getMiterLimit() { + return miterLimit; + } + + /** + * Gets the dash attributes array of the BasicStroke. + * + * @return the dash attributes array of the BasicStroke. + */ + public float[] getDashArray() { + return dash; + } + + /** + * Gets the dash phase of the BasicStroke. + * + * @return the dash phase of the BasicStroke. + */ + public float getDashPhase() { + return dashPhase; + } + + /** + * Returns hash code of this BasicStroke. + * + * @return the hash code of this BasicStroke. + */ + @Override + public int hashCode() { + HashCode hash = new HashCode(); + hash.append(width); + hash.append(cap); + hash.append(join); + hash.append(miterLimit); + if (dash != null) { + hash.append(dashPhase); + for (float element : dash) { + hash.append(element); + } + } + return hash.hashCode(); + } + + /** + * Compares this BasicStroke object with the specified Object. + * + * @param obj + * the Object to be compared. + * @return true, if the Object is a BasicStroke with the same data values as + * this BasicStroke; false otherwise. + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof BasicStroke) { + BasicStroke bs = (BasicStroke)obj; + return bs.width == width && bs.cap == cap && bs.join == join + && bs.miterLimit == miterLimit && bs.dashPhase == dashPhase + && java.util.Arrays.equals(bs.dash, dash); + } + return false; + } + + /** + * Calculates allowable curve derivation. + * + * @param width + * the width. + * @return the curve delta. + */ + double getCurveDelta(double width) { + double a = width + CURVE_DELTA; + double cos = 1.0 - 2.0 * width * width / (a * a); + double sin = Math.sqrt(1.0 - cos * cos); + return Math.abs(sin / cos); + } + + /** + * Calculates the value to detect a small angle. + * + * @param width + * the width. + * @return the corner delta. + */ + double getCornerDelta(double width) { + return width * width * Math.sin(Math.PI * CORNER_ANGLE / 180.0); + } + + /** + * Calculates value to detect a zero angle. + * + * @param width + * the width. + * @return the zero delta. + */ + double getZeroDelta(double width) { + return width * width * Math.sin(Math.PI * CORNER_ZERO / 180.0); + } + + /** + * Creates a Shape from the outline of the specified shape drawn with this + * BasicStroke. + * + * @param s + * the specified Shape to be stroked. + * @return the Shape of the stroked outline. + * @see java.awt.Stroke#createStrokedShape(java.awt.Shape) + */ + public Shape createStrokedShape(Shape s) { + w2 = width / 2.0; + curveDelta = getCurveDelta(w2); + cornerDelta = getCornerDelta(w2); + zeroDelta = getZeroDelta(w2); + + dst = new BufferedPath(); + lp = new BufferedPath(); + rp = new BufferedPath(); + + if (dash == null) { + createSolidShape(s.getPathIterator(null)); + } else { + createDashedShape(s.getPathIterator(null)); + } + + return dst.createGeneralPath(); + } + + /** + * Generates a shape with a solid (not dashed) outline. + * + * @param p + * the PathIterator of source shape. + */ + void createSolidShape(PathIterator p) { + double coords[] = new double[6]; + mx = my = cx = cy = 0.0; + isMove = false; + isFirst = false; + checkMove = true; + boolean isClosed = true; + + while (!p.isDone()) { + switch (p.currentSegment(coords)) { + case PathIterator.SEG_MOVETO: + if (!isClosed) { + closeSolidShape(); + } + rp.clean(); + mx = cx = coords[0]; + my = cy = coords[1]; + isMove = true; + isClosed = false; + break; + case PathIterator.SEG_LINETO: + addLine(cx, cy, cx = coords[0], cy = coords[1], true); + break; + case PathIterator.SEG_QUADTO: + addQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3]); + break; + case PathIterator.SEG_CUBICTO: + addCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4], + cy = coords[5]); + break; + case PathIterator.SEG_CLOSE: + addLine(cx, cy, mx, my, false); + addJoin(lp, mx, my, lp.xMove, lp.yMove, true); + addJoin(rp, mx, my, rp.xMove, rp.yMove, false); + lp.closePath(); + rp.closePath(); + lp.appendReverse(rp); + isClosed = true; + break; + } + p.next(); + } + if (!isClosed) { + closeSolidShape(); + } + + dst = lp; + } + + /** + * Closes solid shape path. + */ + void closeSolidShape() { + addCap(lp, cx, cy, rp.xLast, rp.yLast); + lp.combine(rp); + addCap(lp, mx, my, lp.xMove, lp.yMove); + lp.closePath(); + } + + /** + * Generates dashed stroked shape. + * + * @param p + * the PathIterator of source shape. + */ + void createDashedShape(PathIterator p) { + double coords[] = new double[6]; + mx = my = cx = cy = 0.0; + smx = smy = scx = scy = 0.0; + isMove = false; + checkMove = false; + boolean isClosed = true; + + while (!p.isDone()) { + switch (p.currentSegment(coords)) { + case PathIterator.SEG_MOVETO: + + if (!isClosed) { + closeDashedShape(); + } + + dasher = new Dasher(dash, dashPhase); + lp.clean(); + rp.clean(); + sp = null; + isFirst = true; + isMove = true; + isClosed = false; + mx = cx = coords[0]; + my = cy = coords[1]; + break; + case PathIterator.SEG_LINETO: + addDashLine(cx, cy, cx = coords[0], cy = coords[1]); + break; + case PathIterator.SEG_QUADTO: + addDashQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3]); + break; + case PathIterator.SEG_CUBICTO: + addDashCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], + cx = coords[4], cy = coords[5]); + break; + case PathIterator.SEG_CLOSE: + addDashLine(cx, cy, cx = mx, cy = my); + + if (dasher.isConnected()) { + // Connect current and head segments + addJoin(lp, fmx, fmy, sp.xMove, sp.yMove, true); + lp.join(sp); + addJoin(lp, fmx, fmy, rp.xLast, rp.yLast, true); + lp.combine(rp); + addCap(lp, smx, smy, lp.xMove, lp.yMove); + lp.closePath(); + dst.append(lp); + sp = null; + } else { + closeDashedShape(); + } + + isClosed = true; + break; + } + p.next(); + } + + if (!isClosed) { + closeDashedShape(); + } + + } + + /** + * Closes dashed shape path. + */ + void closeDashedShape() { + // Add head segment + if (sp != null) { + addCap(sp, fmx, fmy, sp.xMove, sp.yMove); + sp.closePath(); + dst.append(sp); + } + if (lp.typeSize > 0) { + // Close current segment + if (!dasher.isClosed()) { + addCap(lp, scx, scy, rp.xLast, rp.yLast); + lp.combine(rp); + addCap(lp, smx, smy, lp.xMove, lp.yMove); + lp.closePath(); + } + dst.append(lp); + } + } + + /** + * Adds cap to the work path. + * + * @param p + * the BufferedPath object of work path. + * @param x0 + * the x coordinate of the source path. + * @param y0 + * the y coordinate on the source path. + * @param x2 + * the x coordinate of the next point on the work path. + * @param y2 + * the y coordinate of the next point on the work path. + */ + void addCap(BufferedPath p, double x0, double y0, double x2, double y2) { + double x1 = p.xLast; + double y1 = p.yLast; + double x10 = x1 - x0; + double y10 = y1 - y0; + double x20 = x2 - x0; + double y20 = y2 - y0; + + switch (cap) { + case CAP_BUTT: + p.lineTo(x2, y2); + break; + case CAP_ROUND: + double mx = x10 * CUBIC_ARC; + double my = y10 * CUBIC_ARC; + + double x3 = x0 + y10; + double y3 = y0 - x10; + + x10 *= CUBIC_ARC; + y10 *= CUBIC_ARC; + x20 *= CUBIC_ARC; + y20 *= CUBIC_ARC; + + p.cubicTo(x1 + y10, y1 - x10, x3 + mx, y3 + my, x3, y3); + p.cubicTo(x3 - mx, y3 - my, x2 - y20, y2 + x20, x2, y2); + break; + case CAP_SQUARE: + p.lineTo(x1 + y10, y1 - x10); + p.lineTo(x2 - y20, y2 + x20); + p.lineTo(x2, y2); + break; + } + } + + /** + * Adds bevel and miter join to the work path. + * + * @param p + * the BufferedPath object of work path. + * @param x0 + * the x coordinate of the source path. + * @param y0 + * the y coordinate on the source path. + * @param x2 + * the x coordinate of the next point on the work path. + * @param y2 + * the y coordinate of the next point on the work path. + * @param isLeft + * the orientation of work path, true if work path lies to the + * left from source path, false otherwise. + */ + void addJoin(BufferedPath p, double x0, double y0, double x2, double y2, boolean isLeft) { + double x1 = p.xLast; + double y1 = p.yLast; + double x10 = x1 - x0; + double y10 = y1 - y0; + double x20 = x2 - x0; + double y20 = y2 - y0; + double sin0 = x10 * y20 - y10 * x20; + + // Small corner + if (-cornerDelta < sin0 && sin0 < cornerDelta) { + double cos0 = x10 * x20 + y10 * y20; + if (cos0 > 0.0) { + // if zero corner do nothing + if (-zeroDelta > sin0 || sin0 > zeroDelta) { + double x3 = x0 + w2 * w2 * (y20 - y10) / sin0; + double y3 = y0 + w2 * w2 * (x10 - x20) / sin0; + p.setLast(x3, y3); + } + return; + } + // Zero corner + if (-zeroDelta < sin0 && sin0 < zeroDelta) { + p.lineTo(x2, y2); + } + return; + } + + if (isLeft ^ (sin0 < 0.0)) { + // Twisted corner + p.lineTo(x0, y0); + p.lineTo(x2, y2); + } else { + switch (join) { + case JOIN_BEVEL: + p.lineTo(x2, y2); + break; + case JOIN_MITER: + double s1 = x1 * x10 + y1 * y10; + double s2 = x2 * x20 + y2 * y20; + double x3 = (s1 * y20 - s2 * y10) / sin0; + double y3 = (s2 * x10 - s1 * x20) / sin0; + double x30 = x3 - x0; + double y30 = y3 - y0; + double miterLength = Math.sqrt(x30 * x30 + y30 * y30); + if (miterLength < miterLimit * w2) { + p.lineTo(x3, y3); + } + p.lineTo(x2, y2); + break; + case JOIN_ROUND: + addRoundJoin(p, x0, y0, x2, y2, isLeft); + break; + } + } + } + + /** + * Adds round join to the work path. + * + * @param p + * the BufferedPath object of work path. + * @param x0 + * the x coordinate of the source path. + * @param y0 + * the y coordinate on the source path. + * @param x2 + * the x coordinate of the next point on the work path. + * @param y2 + * the y coordinate of the next point on the work path. + * @param isLeft + * the orientation of work path, true if work path lies to the + * left from source path, false otherwise. + */ + void addRoundJoin(BufferedPath p, double x0, double y0, double x2, double y2, boolean isLeft) { + double x1 = p.xLast; + double y1 = p.yLast; + double x10 = x1 - x0; + double y10 = y1 - y0; + double x20 = x2 - x0; + double y20 = y2 - y0; + + double x30 = x10 + x20; + double y30 = y10 + y20; + + double l30 = Math.sqrt(x30 * x30 + y30 * y30); + + if (l30 < 1E-5) { + p.lineTo(x2, y2); + return; + } + + double w = w2 / l30; + + x30 *= w; + y30 *= w; + + double x3 = x0 + x30; + double y3 = y0 + y30; + + double cos = x10 * x20 + y10 * y20; + double a = Math.acos(cos / (w2 * w2)); + if (cos >= 0.0) { + double k = 4.0 / 3.0 * Math.tan(a / 4.0); + if (isLeft) { + k = -k; + } + + x10 *= k; + y10 *= k; + x20 *= k; + y20 *= k; + + p.cubicTo(x1 - y10, y1 + x10, x2 + y20, y2 - x20, x2, y2); + } else { + double k = 4.0 / 3.0 * Math.tan(a / 8.0); + if (isLeft) { + k = -k; + } + + x10 *= k; + y10 *= k; + x20 *= k; + y20 *= k; + x30 *= k; + y30 *= k; + + p.cubicTo(x1 - y10, y1 + x10, x3 + y30, y3 - x30, x3, y3); + p.cubicTo(x3 - y30, y3 + x30, x2 + y20, y2 - x20, x2, y2); + } + + } + + /** + * Adds solid line segment to the work path. + * + * @param x1 + * the x coordinate of the start line point. + * @param y1 + * the y coordinate of the start line point. + * @param x2 + * the x coordinate of the end line point. + * @param y2 + * the y coordinate of the end line point. + * @param zero + * if true it's allowable to add zero length line segment. + */ + void addLine(double x1, double y1, double x2, double y2, boolean zero) { + double dx = x2 - x1; + double dy = y2 - y1; + + if (dx == 0.0 && dy == 0.0) { + if (!zero) { + return; + } + dx = w2; + dy = 0; + } else { + double w = w2 / Math.sqrt(dx * dx + dy * dy); + dx *= w; + dy *= w; + } + + double lx1 = x1 - dy; + double ly1 = y1 + dx; + double rx1 = x1 + dy; + double ry1 = y1 - dx; + + if (checkMove) { + if (isMove) { + isMove = false; + lp.moveTo(lx1, ly1); + rp.moveTo(rx1, ry1); + } else { + addJoin(lp, x1, y1, lx1, ly1, true); + addJoin(rp, x1, y1, rx1, ry1, false); + } + } + + lp.lineTo(x2 - dy, y2 + dx); + rp.lineTo(x2 + dy, y2 - dx); + } + + /** + * Adds solid quad segment to the work path. + * + * @param x1 + * the x coordinate of the first control point. + * @param y1 + * the y coordinate of the first control point. + * @param x2 + * the x coordinate of the second control point. + * @param y2 + * the y coordinate of the second control point. + * @param x3 + * the x coordinate of the third control point. + * @param y3 + * the y coordinate of the third control point. + */ + void addQuad(double x1, double y1, double x2, double y2, double x3, double y3) { + double x21 = x2 - x1; + double y21 = y2 - y1; + double x23 = x2 - x3; + double y23 = y2 - y3; + + double l21 = Math.sqrt(x21 * x21 + y21 * y21); + double l23 = Math.sqrt(x23 * x23 + y23 * y23); + + if (l21 == 0.0 && l23 == 0.0) { + addLine(x1, y1, x3, y3, false); + return; + } + + if (l21 == 0.0) { + addLine(x2, y2, x3, y3, false); + return; + } + + if (l23 == 0.0) { + addLine(x1, y1, x2, y2, false); + return; + } + + double w; + w = w2 / l21; + double mx1 = -y21 * w; + double my1 = x21 * w; + w = w2 / l23; + double mx3 = y23 * w; + double my3 = -x23 * w; + + double lx1 = x1 + mx1; + double ly1 = y1 + my1; + double rx1 = x1 - mx1; + double ry1 = y1 - my1; + + if (checkMove) { + if (isMove) { + isMove = false; + lp.moveTo(lx1, ly1); + rp.moveTo(rx1, ry1); + } else { + addJoin(lp, x1, y1, lx1, ly1, true); + addJoin(rp, x1, y1, rx1, ry1, false); + } + } + + if (x21 * y23 - y21 * x23 == 0.0) { + // On line curve + if (x21 * x23 + y21 * y23 > 0.0) { + // Twisted curve + if (l21 == l23) { + double px = x1 + (x21 + x23) / 4.0; + double py = y1 + (y21 + y23) / 4.0; + lp.lineTo(px + mx1, py + my1); + rp.lineTo(px - mx1, py - my1); + lp.lineTo(px - mx1, py - my1); + rp.lineTo(px + mx1, py + my1); + lp.lineTo(x3 - mx1, y3 - my1); + rp.lineTo(x3 + mx1, y3 + my1); + } else { + double px1, py1; + double k = l21 / (l21 + l23); + double px = x1 + (x21 + x23) * k * k; + double py = y1 + (y21 + y23) * k * k; + px1 = (x1 + px) / 2.0; + py1 = (y1 + py) / 2.0; + lp.quadTo(px1 + mx1, py1 + my1, px + mx1, py + my1); + rp.quadTo(px1 - mx1, py1 - my1, px - mx1, py - my1); + lp.lineTo(px - mx1, py - my1); + rp.lineTo(px + mx1, py + my1); + px1 = (x3 + px) / 2.0; + py1 = (y3 + py) / 2.0; + lp.quadTo(px1 - mx1, py1 - my1, x3 - mx1, y3 - my1); + rp.quadTo(px1 + mx1, py1 + my1, x3 + mx1, y3 + my1); + } + } else { + // Simple curve + lp.quadTo(x2 + mx1, y2 + my1, x3 + mx3, y3 + my3); + rp.quadTo(x2 - mx1, y2 - my1, x3 - mx3, y3 - my3); + } + } else { + addSubQuad(x1, y1, x2, y2, x3, y3, 0); + } + } + + /** + * Subdivides solid quad curve to make outline for source quad segment and + * adds it to work path. + * + * @param x1 + * the x coordinate of the first control point. + * @param y1 + * the y coordinate of the first control point. + * @param x2 + * the x coordinate of the second control point. + * @param y2 + * the y coordinate of the second control point. + * @param x3 + * the x coordinate of the third control point. + * @param y3 + * the y coordinate of the third control point. + * @param level + * the maximum level of subdivision deepness. + */ + void addSubQuad(double x1, double y1, double x2, double y2, double x3, double y3, int level) { + double x21 = x2 - x1; + double y21 = y2 - y1; + double x23 = x2 - x3; + double y23 = y2 - y3; + + double cos = x21 * x23 + y21 * y23; + double sin = x21 * y23 - y21 * x23; + + if (level < MAX_LEVEL && (cos >= 0.0 || (Math.abs(sin / cos) > curveDelta))) { + double c1x = (x2 + x1) / 2.0; + double c1y = (y2 + y1) / 2.0; + double c2x = (x2 + x3) / 2.0; + double c2y = (y2 + y3) / 2.0; + double c3x = (c1x + c2x) / 2.0; + double c3y = (c1y + c2y) / 2.0; + addSubQuad(x1, y1, c1x, c1y, c3x, c3y, level + 1); + addSubQuad(c3x, c3y, c2x, c2y, x3, y3, level + 1); + } else { + double w; + double l21 = Math.sqrt(x21 * x21 + y21 * y21); + double l23 = Math.sqrt(x23 * x23 + y23 * y23); + w = w2 / sin; + double mx2 = (x21 * l23 + x23 * l21) * w; + double my2 = (y21 * l23 + y23 * l21) * w; + w = w2 / l23; + double mx3 = y23 * w; + double my3 = -x23 * w; + lp.quadTo(x2 + mx2, y2 + my2, x3 + mx3, y3 + my3); + rp.quadTo(x2 - mx2, y2 - my2, x3 - mx3, y3 - my3); + } + } + + /** + * Adds solid cubic segment to the work path. + * + * @param x1 + * the x coordinate of the first control point. + * @param y1 + * the y coordinate of the first control point. + * @param x2 + * the x coordinate of the second control point. + * @param y2 + * the y coordinate of the second control point. + * @param x3 + * the x coordinate of the third control point. + * @param y3 + * the y coordinate of the third control point. + * @param x4 + * the x coordinate of the fours control point. + * @param y4 + * the y coordinate of the fours control point. + */ + void addCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, + double y4) { + double x12 = x1 - x2; + double y12 = y1 - y2; + double x23 = x2 - x3; + double y23 = y2 - y3; + double x34 = x3 - x4; + double y34 = y3 - y4; + + double l12 = Math.sqrt(x12 * x12 + y12 * y12); + double l23 = Math.sqrt(x23 * x23 + y23 * y23); + double l34 = Math.sqrt(x34 * x34 + y34 * y34); + + // All edges are zero + if (l12 == 0.0 && l23 == 0.0 && l34 == 0.0) { + addLine(x1, y1, x4, y4, false); + return; + } + + // One zero edge + if (l12 == 0.0 && l23 == 0.0) { + addLine(x3, y3, x4, y4, false); + return; + } + + if (l23 == 0.0 && l34 == 0.0) { + addLine(x1, y1, x2, y2, false); + return; + } + + if (l12 == 0.0 && l34 == 0.0) { + addLine(x2, y2, x3, y3, false); + return; + } + + double w, mx1, my1, mx4, my4; + boolean onLine; + + if (l12 == 0.0) { + w = w2 / l23; + mx1 = y23 * w; + my1 = -x23 * w; + w = w2 / l34; + mx4 = y34 * w; + my4 = -x34 * w; + onLine = -x23 * y34 + y23 * x34 == 0.0; // sin3 + } else if (l34 == 0.0) { + w = w2 / l12; + mx1 = y12 * w; + my1 = -x12 * w; + w = w2 / l23; + mx4 = y23 * w; + my4 = -x23 * w; + onLine = -x12 * y23 + y12 * x23 == 0.0; // sin2 + } else { + w = w2 / l12; + mx1 = y12 * w; + my1 = -x12 * w; + w = w2 / l34; + mx4 = y34 * w; + my4 = -x34 * w; + if (l23 == 0.0) { + onLine = -x12 * y34 + y12 * x34 == 0.0; + } else { + onLine = -x12 * y34 + y12 * x34 == 0.0 && -x12 * y23 + y12 * x23 == 0.0 && // sin2 + -x23 * y34 + y23 * x34 == 0.0; // sin3 + } + } + + double lx1 = x1 + mx1; + double ly1 = y1 + my1; + double rx1 = x1 - mx1; + double ry1 = y1 - my1; + + if (checkMove) { + if (isMove) { + isMove = false; + lp.moveTo(lx1, ly1); + rp.moveTo(rx1, ry1); + } else { + addJoin(lp, x1, y1, lx1, ly1, true); + addJoin(rp, x1, y1, rx1, ry1, false); + } + } + + if (onLine) { + if ((x1 == x2 && y1 < y2) || x1 < x2) { + l12 = -l12; + } + if ((x2 == x3 && y2 < y3) || x2 < x3) { + l23 = -l23; + } + if ((x3 == x4 && y3 < y4) || x3 < x4) { + l34 = -l34; + } + double d = l23 * l23 - l12 * l34; + double roots[] = new double[3]; + int rc = 0; + if (d == 0.0) { + double t = (l12 - l23) / (l12 + l34 - l23 - l23); + if (0.0 < t && t < 1.0) { + roots[rc++] = t; + } + } else if (d > 0.0) { + d = Math.sqrt(d); + double z = l12 + l34 - l23 - l23; + double t; + t = (l12 - l23 + d) / z; + if (0.0 < t && t < 1.0) { + roots[rc++] = t; + } + t = (l12 - l23 - d) / z; + if (0.0 < t && t < 1.0) { + roots[rc++] = t; + } + } + + if (rc > 0) { + // Sort roots + if (rc == 2 && roots[0] > roots[1]) { + double tmp = roots[0]; + roots[0] = roots[1]; + roots[1] = tmp; + } + roots[rc++] = 1.0; + + double ax = -x34 - x12 + x23 + x23; + double ay = -y34 - y12 + y23 + y23; + double bx = 3.0 * (-x23 + x12); + double by = 3.0 * (-y23 + y12); + double cx = 3.0 * (-x12); + double cy = 3.0 * (-y12); + double xPrev = x1; + double yPrev = y1; + for (int i = 0; i < rc; i++) { + double t = roots[i]; + double px = t * (t * (t * ax + bx) + cx) + x1; + double py = t * (t * (t * ay + by) + cy) + y1; + double px1 = (xPrev + px) / 2.0; + double py1 = (yPrev + py) / 2.0; + lp.cubicTo(px1 + mx1, py1 + my1, px1 + mx1, py1 + my1, px + mx1, py + my1); + rp.cubicTo(px1 - mx1, py1 - my1, px1 - mx1, py1 - my1, px - mx1, py - my1); + if (i < rc - 1) { + lp.lineTo(px - mx1, py - my1); + rp.lineTo(px + mx1, py + my1); + } + xPrev = px; + yPrev = py; + mx1 = -mx1; + my1 = -my1; + } + } else { + lp.cubicTo(x2 + mx1, y2 + my1, x3 + mx4, y3 + my4, x4 + mx4, y4 + my4); + rp.cubicTo(x2 - mx1, y2 - my1, x3 - mx4, y3 - my4, x4 - mx4, y4 - my4); + } + } else { + addSubCubic(x1, y1, x2, y2, x3, y3, x4, y4, 0); + } + } + + /** + * Subdivides solid cubic curve to make outline for source quad segment and + * adds it to work path. + * + * @param x1 + * the x coordinate of the first control point. + * @param y1 + * the y coordinate of the first control point. + * @param x2 + * the x coordinate of the second control point. + * @param y2 + * the y coordinate of the second control point. + * @param x3 + * the x coordinate of the third control point. + * @param y3 + * the y coordinate of the third control point. + * @param x4 + * the x coordinate of the fours control point. + * @param y4 + * the y coordinate of the fours control point. + * @param level + * the maximum level of subdivision deepness. + */ + void addSubCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, + double y4, int level) { + double x12 = x1 - x2; + double y12 = y1 - y2; + double x23 = x2 - x3; + double y23 = y2 - y3; + double x34 = x3 - x4; + double y34 = y3 - y4; + + double cos2 = -x12 * x23 - y12 * y23; + double cos3 = -x23 * x34 - y23 * y34; + double sin2 = -x12 * y23 + y12 * x23; + double sin3 = -x23 * y34 + y23 * x34; + double sin0 = -x12 * y34 + y12 * x34; + double cos0 = -x12 * x34 - y12 * y34; + + if (level < MAX_LEVEL + && (sin2 != 0.0 || sin3 != 0.0 || sin0 != 0.0) + && (cos2 >= 0.0 || cos3 >= 0.0 || cos0 >= 0.0 + || (Math.abs(sin2 / cos2) > curveDelta) + || (Math.abs(sin3 / cos3) > curveDelta) || (Math.abs(sin0 / cos0) > curveDelta))) { + double cx = (x2 + x3) / 2.0; + double cy = (y2 + y3) / 2.0; + double lx2 = (x2 + x1) / 2.0; + double ly2 = (y2 + y1) / 2.0; + double rx3 = (x3 + x4) / 2.0; + double ry3 = (y3 + y4) / 2.0; + double lx3 = (cx + lx2) / 2.0; + double ly3 = (cy + ly2) / 2.0; + double rx2 = (cx + rx3) / 2.0; + double ry2 = (cy + ry3) / 2.0; + cx = (lx3 + rx2) / 2.0; + cy = (ly3 + ry2) / 2.0; + addSubCubic(x1, y1, lx2, ly2, lx3, ly3, cx, cy, level + 1); + addSubCubic(cx, cy, rx2, ry2, rx3, ry3, x4, y4, level + 1); + } else { + double w, mx1, my1, mx2, my2, mx3, my3, mx4, my4; + double l12 = Math.sqrt(x12 * x12 + y12 * y12); + double l23 = Math.sqrt(x23 * x23 + y23 * y23); + double l34 = Math.sqrt(x34 * x34 + y34 * y34); + + if (l12 == 0.0) { + w = w2 / l23; + mx1 = y23 * w; + my1 = -x23 * w; + w = w2 / l34; + mx4 = y34 * w; + my4 = -x34 * w; + } else if (l34 == 0.0) { + w = w2 / l12; + mx1 = y12 * w; + my1 = -x12 * w; + w = w2 / l23; + mx4 = y23 * w; + my4 = -x23 * w; + } else { + // Common case + w = w2 / l12; + mx1 = y12 * w; + my1 = -x12 * w; + w = w2 / l34; + mx4 = y34 * w; + my4 = -x34 * w; + } + + if (sin2 == 0.0) { + mx2 = mx1; + my2 = my1; + } else { + w = w2 / sin2; + mx2 = -(x12 * l23 - x23 * l12) * w; + my2 = -(y12 * l23 - y23 * l12) * w; + } + if (sin3 == 0.0) { + mx3 = mx4; + my3 = my4; + } else { + w = w2 / sin3; + mx3 = -(x23 * l34 - x34 * l23) * w; + my3 = -(y23 * l34 - y34 * l23) * w; + } + + lp.cubicTo(x2 + mx2, y2 + my2, x3 + mx3, y3 + my3, x4 + mx4, y4 + my4); + rp.cubicTo(x2 - mx2, y2 - my2, x3 - mx3, y3 - my3, x4 - mx4, y4 - my4); + } + } + + /** + * Adds dashed line segment to the work path. + * + * @param x1 + * the x coordinate of the start line point. + * @param y1 + * the y coordinate of the start line point. + * @param x2 + * the x coordinate of the end line point. + * @param y2 + * the y coordinate of the end line point. + */ + void addDashLine(double x1, double y1, double x2, double y2) { + double x21 = x2 - x1; + double y21 = y2 - y1; + + double l21 = Math.sqrt(x21 * x21 + y21 * y21); + + if (l21 == 0.0) { + return; + } + + double px1, py1; + px1 = py1 = 0.0; + double w = w2 / l21; + double mx = -y21 * w; + double my = x21 * w; + + dasher.init(new DashIterator.Line(l21)); + + while (!dasher.eof()) { + double t = dasher.getValue(); + scx = x1 + t * x21; + scy = y1 + t * y21; + + if (dasher.isOpen()) { + px1 = scx; + py1 = scy; + double lx1 = px1 + mx; + double ly1 = py1 + my; + double rx1 = px1 - mx; + double ry1 = py1 - my; + if (isMove) { + isMove = false; + smx = px1; + smy = py1; + rp.clean(); + lp.moveTo(lx1, ly1); + rp.moveTo(rx1, ry1); + } else { + addJoin(lp, x1, y1, lx1, ly1, true); + addJoin(rp, x1, y1, rx1, ry1, false); + } + } else if (dasher.isContinue()) { + double px2 = scx; + double py2 = scy; + lp.lineTo(px2 + mx, py2 + my); + rp.lineTo(px2 - mx, py2 - my); + if (dasher.close) { + addCap(lp, px2, py2, rp.xLast, rp.yLast); + lp.combine(rp); + if (isFirst) { + isFirst = false; + fmx = smx; + fmy = smy; + sp = lp; + lp = new BufferedPath(); + } else { + addCap(lp, smx, smy, lp.xMove, lp.yMove); + lp.closePath(); + } + isMove = true; + } + } + + dasher.next(); + } + } + + /** + * Adds dashed quad segment to the work path. + * + * @param x1 + * the x coordinate of the first control point. + * @param y1 + * the y coordinate of the first control point. + * @param x2 + * the x coordinate of the second control point. + * @param y2 + * the y coordinate of the second control point. + * @param x3 + * the x coordinate of the third control point. + * @param y3 + * the y coordinate of the third control point. + */ + void addDashQuad(double x1, double y1, double x2, double y2, double x3, double y3) { + + double x21 = x2 - x1; + double y21 = y2 - y1; + double x23 = x2 - x3; + double y23 = y2 - y3; + + double l21 = Math.sqrt(x21 * x21 + y21 * y21); + double l23 = Math.sqrt(x23 * x23 + y23 * y23); + + if (l21 == 0.0 && l23 == 0.0) { + return; + } + + if (l21 == 0.0) { + addDashLine(x2, y2, x3, y3); + return; + } + + if (l23 == 0.0) { + addDashLine(x1, y1, x2, y2); + return; + } + + double ax = x1 + x3 - x2 - x2; + double ay = y1 + y3 - y2 - y2; + double bx = x2 - x1; + double by = y2 - y1; + double cx = x1; + double cy = y1; + + double px1, py1, dx1, dy1; + px1 = py1 = dx1 = dy1 = 0.0; + double prev = 0.0; + + dasher.init(new DashIterator.Quad(x1, y1, x2, y2, x3, y3)); + + while (!dasher.eof()) { + double t = dasher.getValue(); + double dx = t * ax + bx; + double dy = t * ay + by; + scx = t * (dx + bx) + cx; // t^2 * ax + 2.0 * t * bx + cx + scy = t * (dy + by) + cy; // t^2 * ay + 2.0 * t * by + cy + if (dasher.isOpen()) { + px1 = scx; + py1 = scy; + dx1 = dx; + dy1 = dy; + double w = w2 / Math.sqrt(dx1 * dx1 + dy1 * dy1); + double mx1 = -dy1 * w; + double my1 = dx1 * w; + double lx1 = px1 + mx1; + double ly1 = py1 + my1; + double rx1 = px1 - mx1; + double ry1 = py1 - my1; + if (isMove) { + isMove = false; + smx = px1; + smy = py1; + rp.clean(); + lp.moveTo(lx1, ly1); + rp.moveTo(rx1, ry1); + } else { + addJoin(lp, x1, y1, lx1, ly1, true); + addJoin(rp, x1, y1, rx1, ry1, false); + } + } else if (dasher.isContinue()) { + double px3 = scx; + double py3 = scy; + double sx = x2 - x23 * prev; + double sy = y2 - y23 * prev; + double t2 = (t - prev) / (1 - prev); + double px2 = px1 + (sx - px1) * t2; + double py2 = py1 + (sy - py1) * t2; + + addQuad(px1, py1, px2, py2, px3, py3); + if (dasher.isClosed()) { + addCap(lp, px3, py3, rp.xLast, rp.yLast); + lp.combine(rp); + if (isFirst) { + isFirst = false; + fmx = smx; + fmy = smy; + sp = lp; + lp = new BufferedPath(); + } else { + addCap(lp, smx, smy, lp.xMove, lp.yMove); + lp.closePath(); + } + isMove = true; + } + } + + prev = t; + dasher.next(); + } + } + + /** + * Adds dashed cubic segment to the work path. + * + * @param x1 + * the x coordinate of the first control point. + * @param y1 + * the y coordinate of the first control point. + * @param x2 + * the x coordinate of the second control point. + * @param y2 + * the y coordinate of the second control point. + * @param x3 + * the x coordinate of the third control point. + * @param y3 + * the y coordinate of the third control point. + * @param x4 + * the x coordinate of the fours control point. + * @param y4 + * the y coordinate of the fours control point. + */ + void addDashCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, + double y4) { + + double x12 = x1 - x2; + double y12 = y1 - y2; + double x23 = x2 - x3; + double y23 = y2 - y3; + double x34 = x3 - x4; + double y34 = y3 - y4; + + double l12 = Math.sqrt(x12 * x12 + y12 * y12); + double l23 = Math.sqrt(x23 * x23 + y23 * y23); + double l34 = Math.sqrt(x34 * x34 + y34 * y34); + + // All edges are zero + if (l12 == 0.0 && l23 == 0.0 && l34 == 0.0) { + // NOTHING + return; + } + + // One zero edge + if (l12 == 0.0 && l23 == 0.0) { + addDashLine(x3, y3, x4, y4); + return; + } + + if (l23 == 0.0 && l34 == 0.0) { + addDashLine(x1, y1, x2, y2); + return; + } + + if (l12 == 0.0 && l34 == 0.0) { + addDashLine(x2, y2, x3, y3); + return; + } + + double ax = x4 - x1 + 3.0 * (x2 - x3); + double ay = y4 - y1 + 3.0 * (y2 - y3); + double bx = 3.0 * (x1 + x3 - x2 - x2); + double by = 3.0 * (y1 + y3 - y2 - y2); + double cx = 3.0 * (x2 - x1); + double cy = 3.0 * (y2 - y1); + double dx = x1; + double dy = y1; + + double px1 = 0.0; + double py1 = 0.0; + double prev = 0.0; + + dasher.init(new DashIterator.Cubic(x1, y1, x2, y2, x3, y3, x4, y4)); + + while (!dasher.eof()) { + + double t = dasher.getValue(); + scx = t * (t * (t * ax + bx) + cx) + dx; + scy = t * (t * (t * ay + by) + cy) + dy; + if (dasher.isOpen()) { + px1 = scx; + py1 = scy; + double dx1 = t * (t * (ax + ax + ax) + bx + bx) + cx; + double dy1 = t * (t * (ay + ay + ay) + by + by) + cy; + double w = w2 / Math.sqrt(dx1 * dx1 + dy1 * dy1); + double mx1 = -dy1 * w; + double my1 = dx1 * w; + double lx1 = px1 + mx1; + double ly1 = py1 + my1; + double rx1 = px1 - mx1; + double ry1 = py1 - my1; + if (isMove) { + isMove = false; + smx = px1; + smy = py1; + rp.clean(); + lp.moveTo(lx1, ly1); + rp.moveTo(rx1, ry1); + } else { + addJoin(lp, x1, y1, lx1, ly1, true); + addJoin(rp, x1, y1, rx1, ry1, false); + } + } else if (dasher.isContinue()) { + double sx1 = x2 - x23 * prev; + double sy1 = y2 - y23 * prev; + double sx2 = x3 - x34 * prev; + double sy2 = y3 - y34 * prev; + double sx3 = sx1 + (sx2 - sx1) * prev; + double sy3 = sy1 + (sy2 - sy1) * prev; + double t2 = (t - prev) / (1 - prev); + double sx4 = sx3 + (sx2 - sx3) * t2; + double sy4 = sy3 + (sy2 - sy3) * t2; + + double px4 = scx; + double py4 = scy; + double px2 = px1 + (sx3 - px1) * t2; + double py2 = py1 + (sy3 - py1) * t2; + double px3 = px2 + (sx4 - px2) * t2; + double py3 = py2 + (sy4 - py2) * t2; + + addCubic(px1, py1, px2, py2, px3, py3, px4, py4); + if (dasher.isClosed()) { + addCap(lp, px4, py4, rp.xLast, rp.yLast); + lp.combine(rp); + if (isFirst) { + isFirst = false; + fmx = smx; + fmy = smy; + sp = lp; + lp = new BufferedPath(); + } else { + addCap(lp, smx, smy, lp.xMove, lp.yMove); + lp.closePath(); + } + isMove = true; + } + } + + prev = t; + dasher.next(); + } + } + + /** + * Dasher class provides dashing for particular dash style. + */ + class Dasher { + + /** + * The pos. + */ + double pos; + + /** + * The first. + */ + boolean close, visible, first; + + /** + * The dash. + */ + float dash[]; + + /** + * The phase. + */ + float phase; + + /** + * The index. + */ + int index; + + /** + * The iter. + */ + DashIterator iter; + + /** + * Instantiates a new dasher. + * + * @param dash + * the dash. + * @param phase + * the phase. + */ + Dasher(float dash[], float phase) { + this.dash = dash; + this.phase = phase; + index = 0; + pos = phase; + visible = true; + while (pos >= dash[index]) { + visible = !visible; + pos -= dash[index]; + index = (index + 1) % dash.length; + } + pos = -pos; + first = visible; + } + + /** + * Inits the. + * + * @param iter + * the iter. + */ + void init(DashIterator iter) { + this.iter = iter; + close = true; + } + + /** + * Checks if is open. + * + * @return true, if is open. + */ + boolean isOpen() { + return visible && pos < iter.length; + } + + /** + * Checks if is continue. + * + * @return true, if is continue. + */ + boolean isContinue() { + return !visible && pos > 0; + } + + /** + * Checks if is closed. + * + * @return true, if is closed. + */ + boolean isClosed() { + return close; + } + + /** + * Checks if is connected. + * + * @return true, if is connected. + */ + boolean isConnected() { + return first && !close; + } + + /** + * Eof. + * + * @return true, if successful. + */ + boolean eof() { + if (!close) { + pos -= iter.length; + return true; + } + if (pos >= iter.length) { + if (visible) { + pos -= iter.length; + return true; + } + close = pos == iter.length; + } + return false; + } + + /** + * Next. + */ + void next() { + if (close) { + pos += dash[index]; + index = (index + 1) % dash.length; + } else { + // Go back + index = (index + dash.length - 1) % dash.length; + pos -= dash[index]; + } + visible = !visible; + } + + /** + * Gets the value. + * + * @return the value. + */ + double getValue() { + double t = iter.getNext(pos); + return t < 0 ? 0 : (t > 1 ? 1 : t); + } + + } + + /** + * DashIterator class provides dashing for particular segment type. + */ + static abstract class DashIterator { + + /** + * The Constant FLATNESS. + */ + static final double FLATNESS = 1.0; + + /** + * The Class Line. + */ + static class Line extends DashIterator { + + /** + * Instantiates a new line. + * + * @param len + * the len. + */ + Line(double len) { + length = len; + } + + @Override + double getNext(double dashPos) { + return dashPos / length; + } + + } + + /** + * The Class Quad. + */ + static class Quad extends DashIterator { + + /** + * The val size. + */ + int valSize; + + /** + * The val pos. + */ + int valPos; + + /** + * The cur len. + */ + double curLen; + + /** + * The prev len. + */ + double prevLen; + + /** + * The last len. + */ + double lastLen; + + /** + * The values. + */ + double[] values; + + /** + * The step. + */ + double step; + + /** + * Instantiates a new quad. + * + * @param x1 + * the x1. + * @param y1 + * the y1. + * @param x2 + * the x2. + * @param y2 + * the y2. + * @param x3 + * the x3. + * @param y3 + * the y3. + */ + Quad(double x1, double y1, double x2, double y2, double x3, double y3) { + + double nx = x1 + x3 - x2 - x2; + double ny = y1 + y3 - y2 - y2; + + int n = (int)(1 + Math.sqrt(0.75 * (Math.abs(nx) + Math.abs(ny)) * FLATNESS)); + step = 1.0 / n; + + double ax = x1 + x3 - x2 - x2; + double ay = y1 + y3 - y2 - y2; + double bx = 2.0 * (x2 - x1); + double by = 2.0 * (y2 - y1); + + double dx1 = step * (step * ax + bx); + double dy1 = step * (step * ay + by); + double dx2 = step * (step * ax * 2.0); + double dy2 = step * (step * ay * 2.0); + double vx = x1; + double vy = y1; + + valSize = n; + values = new double[valSize]; + double pvx = vx; + double pvy = vy; + length = 0.0; + for (int i = 0; i < n; i++) { + vx += dx1; + vy += dy1; + dx1 += dx2; + dy1 += dy2; + double lx = vx - pvx; + double ly = vy - pvy; + values[i] = Math.sqrt(lx * lx + ly * ly); + length += values[i]; + pvx = vx; + pvy = vy; + } + + valPos = 0; + curLen = 0.0; + prevLen = 0.0; + } + + @Override + double getNext(double dashPos) { + double t = 2.0; + while (curLen <= dashPos && valPos < valSize) { + prevLen = curLen; + curLen += lastLen = values[valPos++]; + } + if (curLen > dashPos) { + t = (valPos - 1 + (dashPos - prevLen) / lastLen) * step; + } + return t; + } + + } + + /** + * The Class Cubic. + */ + static class Cubic extends DashIterator { + + /** + * The val size. + */ + int valSize; + + /** + * The val pos. + */ + int valPos; + + /** + * The cur len. + */ + double curLen; + + /** + * The prev len. + */ + double prevLen; + + /** + * The last len. + */ + double lastLen; + + /** + * The values. + */ + double[] values; + + /** + * The step. + */ + double step; + + /** + * Instantiates a new cubic. + * + * @param x1 + * the x1. + * @param y1 + * the y1. + * @param x2 + * the x2. + * @param y2 + * the y2. + * @param x3 + * the x3. + * @param y3 + * the y3. + * @param x4 + * the x4. + * @param y4 + * the y4. + */ + Cubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, + double y4) { + + double nx1 = x1 + x3 - x2 - x2; + double ny1 = y1 + y3 - y2 - y2; + double nx2 = x2 + x4 - x3 - x3; + double ny2 = y2 + y4 - y3 - y3; + + double max = Math.max(Math.abs(nx1) + Math.abs(ny1), Math.abs(nx2) + Math.abs(ny2)); + int n = (int)(1 + Math.sqrt(0.75 * max) * FLATNESS); + step = 1.0 / n; + + double ax = x4 - x1 + 3.0 * (x2 - x3); + double ay = y4 - y1 + 3.0 * (y2 - y3); + double bx = 3.0 * (x1 + x3 - x2 - x2); + double by = 3.0 * (y1 + y3 - y2 - y2); + double cx = 3.0 * (x2 - x1); + double cy = 3.0 * (y2 - y1); + + double dx1 = step * (step * (step * ax + bx) + cx); + double dy1 = step * (step * (step * ay + by) + cy); + double dx2 = step * (step * (step * ax * 6.0 + bx * 2.0)); + double dy2 = step * (step * (step * ay * 6.0 + by * 2.0)); + double dx3 = step * (step * (step * ax * 6.0)); + double dy3 = step * (step * (step * ay * 6.0)); + double vx = x1; + double vy = y1; + + valSize = n; + values = new double[valSize]; + double pvx = vx; + double pvy = vy; + length = 0.0; + for (int i = 0; i < n; i++) { + vx += dx1; + vy += dy1; + dx1 += dx2; + dy1 += dy2; + dx2 += dx3; + dy2 += dy3; + double lx = vx - pvx; + double ly = vy - pvy; + values[i] = Math.sqrt(lx * lx + ly * ly); + length += values[i]; + pvx = vx; + pvy = vy; + } + + valPos = 0; + curLen = 0.0; + prevLen = 0.0; + } + + @Override + double getNext(double dashPos) { + double t = 2.0; + while (curLen <= dashPos && valPos < valSize) { + prevLen = curLen; + curLen += lastLen = values[valPos++]; + } + if (curLen > dashPos) { + t = (valPos - 1 + (dashPos - prevLen) / lastLen) * step; + } + return t; + } + + } + + /** + * The length. + */ + double length; + + /** + * Gets the next. + * + * @param dashPos + * the dash pos. + * @return the next. + */ + abstract double getNext(double dashPos); + + } + + /** + * BufferedPath class provides work path storing and processing. + */ + static class BufferedPath { + + /** + * The Constant bufCapacity. + */ + private static final int bufCapacity = 10; + + /** + * The point shift. + */ + static int pointShift[] = { + 2, // MOVETO + 2, // LINETO + 4, // QUADTO + 6, // CUBICTO + 0 + }; // CLOSE + + /** + * The types. + */ + byte[] types; + + /** + * The points. + */ + float[] points; + + /** + * The type size. + */ + int typeSize; + + /** + * The point size. + */ + int pointSize; + + /** + * The x last. + */ + float xLast; + + /** + * The y last. + */ + float yLast; + + /** + * The x move. + */ + float xMove; + + /** + * The y move. + */ + float yMove; + + /** + * Instantiates a new buffered path. + */ + public BufferedPath() { + types = new byte[bufCapacity]; + points = new float[bufCapacity * 2]; + } + + /** + * Check buf. + * + * @param typeCount + * the type count. + * @param pointCount + * the point count. + */ + void checkBuf(int typeCount, int pointCount) { + if (typeSize + typeCount > types.length) { + byte tmp[] = new byte[typeSize + Math.max(bufCapacity, typeCount)]; + System.arraycopy(types, 0, tmp, 0, typeSize); + types = tmp; + } + if (pointSize + pointCount > points.length) { + float tmp[] = new float[pointSize + Math.max(bufCapacity * 2, pointCount)]; + System.arraycopy(points, 0, tmp, 0, pointSize); + points = tmp; + } + } + + /** + * Checks if is empty. + * + * @return true, if is empty. + */ + boolean isEmpty() { + return typeSize == 0; + } + + /** + * Clean. + */ + void clean() { + typeSize = 0; + pointSize = 0; + } + + /** + * Move to. + * + * @param x + * the x. + * @param y + * the y. + */ + void moveTo(double x, double y) { + checkBuf(1, 2); + types[typeSize++] = PathIterator.SEG_MOVETO; + points[pointSize++] = xMove = (float)x; + points[pointSize++] = yMove = (float)y; + } + + /** + * Line to. + * + * @param x + * the x. + * @param y + * the y. + */ + void lineTo(double x, double y) { + checkBuf(1, 2); + types[typeSize++] = PathIterator.SEG_LINETO; + points[pointSize++] = xLast = (float)x; + points[pointSize++] = yLast = (float)y; + } + + /** + * Quad to. + * + * @param x1 + * the x1. + * @param y1 + * the y1. + * @param x2 + * the x2. + * @param y2 + * the y2. + */ + void quadTo(double x1, double y1, double x2, double y2) { + checkBuf(1, 4); + types[typeSize++] = PathIterator.SEG_QUADTO; + points[pointSize++] = (float)x1; + points[pointSize++] = (float)y1; + points[pointSize++] = xLast = (float)x2; + points[pointSize++] = yLast = (float)y2; + } + + /** + * Cubic to. + * + * @param x1 + * the x1. + * @param y1 + * the y1. + * @param x2 + * the x2. + * @param y2 + * the y2. + * @param x3 + * the x3. + * @param y3 + * the y3. + */ + void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3) { + checkBuf(1, 6); + types[typeSize++] = PathIterator.SEG_CUBICTO; + points[pointSize++] = (float)x1; + points[pointSize++] = (float)y1; + points[pointSize++] = (float)x2; + points[pointSize++] = (float)y2; + points[pointSize++] = xLast = (float)x3; + points[pointSize++] = yLast = (float)y3; + } + + /** + * Close path. + */ + void closePath() { + checkBuf(1, 0); + types[typeSize++] = PathIterator.SEG_CLOSE; + } + + /** + * Sets the last. + * + * @param x + * the x. + * @param y + * the y. + */ + void setLast(double x, double y) { + points[pointSize - 2] = xLast = (float)x; + points[pointSize - 1] = yLast = (float)y; + } + + /** + * Append. + * + * @param p + * the p. + */ + void append(BufferedPath p) { + checkBuf(p.typeSize, p.pointSize); + System.arraycopy(p.points, 0, points, pointSize, p.pointSize); + System.arraycopy(p.types, 0, types, typeSize, p.typeSize); + pointSize += p.pointSize; + typeSize += p.typeSize; + xLast = points[pointSize - 2]; + yLast = points[pointSize - 1]; + } + + /** + * Append reverse. + * + * @param p + * the p. + */ + void appendReverse(BufferedPath p) { + checkBuf(p.typeSize, p.pointSize); + // Skip last point, beacause it's the first point of the second path + for (int i = p.pointSize - 2; i >= 0; i -= 2) { + points[pointSize++] = p.points[i + 0]; + points[pointSize++] = p.points[i + 1]; + } + // Skip first type, beacuse it's always MOVETO + int closeIndex = 0; + for (int i = p.typeSize - 1; i >= 0; i--) { + byte type = p.types[i]; + if (type == PathIterator.SEG_MOVETO) { + types[closeIndex] = PathIterator.SEG_MOVETO; + types[typeSize++] = PathIterator.SEG_CLOSE; + } else { + if (type == PathIterator.SEG_CLOSE) { + closeIndex = typeSize; + } + types[typeSize++] = type; + } + } + xLast = points[pointSize - 2]; + yLast = points[pointSize - 1]; + } + + /** + * Join. + * + * @param p + * the p. + */ + void join(BufferedPath p) { + // Skip MOVETO + checkBuf(p.typeSize - 1, p.pointSize - 2); + System.arraycopy(p.points, 2, points, pointSize, p.pointSize - 2); + System.arraycopy(p.types, 1, types, typeSize, p.typeSize - 1); + pointSize += p.pointSize - 2; + typeSize += p.typeSize - 1; + xLast = points[pointSize - 2]; + yLast = points[pointSize - 1]; + } + + /** + * Combine. + * + * @param p + * the p. + */ + void combine(BufferedPath p) { + checkBuf(p.typeSize - 1, p.pointSize - 2); + // Skip last point, beacause it's the first point of the second path + for (int i = p.pointSize - 4; i >= 0; i -= 2) { + points[pointSize++] = p.points[i + 0]; + points[pointSize++] = p.points[i + 1]; + } + // Skip first type, beacuse it's always MOVETO + for (int i = p.typeSize - 1; i >= 1; i--) { + types[typeSize++] = p.types[i]; + } + xLast = points[pointSize - 2]; + yLast = points[pointSize - 1]; + } + + /** + * Creates the general path. + * + * @return the general path. + */ + GeneralPath createGeneralPath() { + GeneralPath p = new GeneralPath(); + int j = 0; + for (int i = 0; i < typeSize; i++) { + int type = types[i]; + switch (type) { + case PathIterator.SEG_MOVETO: + p.moveTo(points[j], points[j + 1]); + break; + case PathIterator.SEG_LINETO: + p.lineTo(points[j], points[j + 1]); + break; + case PathIterator.SEG_QUADTO: + p.quadTo(points[j], points[j + 1], points[j + 2], points[j + 3]); + break; + case PathIterator.SEG_CUBICTO: + p.curveTo(points[j], points[j + 1], points[j + 2], points[j + 3], + points[j + 4], points[j + 5]); + break; + case PathIterator.SEG_CLOSE: + p.closePath(); + break; + } + j += pointShift[type]; + } + return p; + } + + } + +} diff --git a/awt/java/awt/BufferCapabilities.java b/awt/java/awt/BufferCapabilities.java new file mode 100644 index 0000000..cd5fe7b --- /dev/null +++ b/awt/java/awt/BufferCapabilities.java @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt; + +/** + * The BufferCapabilities class represents the capabilities and other properties + * of the image buffers. + * + * @since Android 1.0 + */ +public class BufferCapabilities implements Cloneable { + + /** + * The front buffer capabilities. + */ + private final ImageCapabilities frontBufferCapabilities; + + /** + * The back buffer capabilities. + */ + private final ImageCapabilities backBufferCapabilities; + + /** + * The flip contents. + */ + private final FlipContents flipContents; + + /** + * Instantiates a new BufferCapabilities object. + * + * @param frontBufferCapabilities + * the front buffer capabilities, can not be null. + * @param backBufferCapabilities + * the the back and intermediate buffers capabilities, can not be + * null. + * @param flipContents + * the back buffer contents after page flipping, null if page + * flipping is not used. + */ + public BufferCapabilities(ImageCapabilities frontBufferCapabilities, + ImageCapabilities backBufferCapabilities, FlipContents flipContents) { + if (frontBufferCapabilities == null || backBufferCapabilities == null) { + throw new IllegalArgumentException(); + } + + this.frontBufferCapabilities = frontBufferCapabilities; + this.backBufferCapabilities = backBufferCapabilities; + this.flipContents = flipContents; + } + + /** + * Returns a copy of the BufferCapabilities object. + * + * @return a copy of the BufferCapabilities object. + */ + @Override + public Object clone() { + return new BufferCapabilities(frontBufferCapabilities, backBufferCapabilities, flipContents); + } + + /** + * Gets the image capabilities of the front buffer. + * + * @return the ImageCapabilities object represented capabilities of the + * front buffer. + */ + public ImageCapabilities getFrontBufferCapabilities() { + return frontBufferCapabilities; + } + + /** + * Gets the image capabilities of the back buffer. + * + * @return the ImageCapabilities object represented capabilities of the back + * buffer. + */ + public ImageCapabilities getBackBufferCapabilities() { + return backBufferCapabilities; + } + + /** + * Gets the flip contents of the back buffer after page-flipping. + * + * @return the FlipContents of the back buffer after page-flipping. + */ + public FlipContents getFlipContents() { + return flipContents; + } + + /** + * Checks if the buffer strategy uses page flipping. + * + * @return true, if the buffer strategy uses page flipping, false otherwise. + */ + public boolean isPageFlipping() { + return flipContents != null; + } + + /** + * Checks if page flipping is only available in full-screen mode. + * + * @return true, if page flipping is only available in full-screen mode, + * false otherwise. + */ + public boolean isFullScreenRequired() { + return false; + } + + /** + * Checks if page flipping can be performed using more than two buffers. + * + * @return true, if page flipping can be performed using more than two + * buffers, false otherwise. + */ + public boolean isMultiBufferAvailable() { + return false; + } + + /** + * The FlipContents class represents a set of possible back buffer contents + * after page-flipping. + * + * @since Android 1.0 + */ + public static final class FlipContents { + + /** + * The back buffered contents are cleared with the background color + * after flipping. + */ + public static final FlipContents BACKGROUND = new FlipContents(); + + /** + * The back buffered contents are copied to the front buffer before + * flipping. + */ + public static final FlipContents COPIED = new FlipContents(); + + /** + * The back buffer contents are the prior contents of the front buffer. + */ + public static final FlipContents PRIOR = new FlipContents(); + + /** + * The back buffer contents are undefined after flipping + */ + public static final FlipContents UNDEFINED = new FlipContents(); + + /** + * Instantiates a new flip contents. + */ + private FlipContents() { + + } + + /** + * Returns the hash code of the FlipContents object. + * + * @return the hash code of the FlipContents object. + */ + @Override + public int hashCode() { + return super.hashCode(); + } + + /** + * Returns the String representation of the FlipContents object. + * + * @return the string + */ + @Override + public String toString() { + return super.toString(); + } + } +} diff --git a/awt/java/awt/Color.java b/awt/java/awt/Color.java new file mode 100644 index 0000000..93c532d --- /dev/null +++ b/awt/java/awt/Color.java @@ -0,0 +1,990 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt; + +import java.awt.color.ColorSpace; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; +import java.awt.image.DataBufferInt; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; +import java.io.Serializable; +import java.util.Arrays; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Color class defines colors in the default sRGB color space or in the + * specified ColorSpace. Every Color contains alpha value. The alpha value + * defines the transparency of a color and can be represented by a float value + * in the range 0.0 - 1.0 or 0 - 255. + * + * @since Android 1.0 + */ +public class Color implements Paint, Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 118526816881161077L; + + /* + * The values of the following colors are based on 1.5 release behavior + * which can be revealed using the following or similar code: Color c = + * Color.white; System.out.println(c); + */ + + /** + * The color white. + */ + public static final Color white = new Color(255, 255, 255); + + /** + * The color white. + */ + public static final Color WHITE = white; + + /** + * The color light gray. + */ + public static final Color lightGray = new Color(192, 192, 192); + + /** + * The color light gray. + */ + public static final Color LIGHT_GRAY = lightGray; + + /** + * The color gray. + */ + public static final Color gray = new Color(128, 128, 128); + + /** + * The color gray. + */ + public static final Color GRAY = gray; + + /** + * The color dark gray. + */ + public static final Color darkGray = new Color(64, 64, 64); + + /** + * The color dark gray. + */ + public static final Color DARK_GRAY = darkGray; + + /** + * The color black. + */ + public static final Color black = new Color(0, 0, 0); + + /** + * The color black. + */ + public static final Color BLACK = black; + + /** + * The color red. + */ + public static final Color red = new Color(255, 0, 0); + + /** + * The color red. + */ + public static final Color RED = red; + + /** + * The color pink. + */ + public static final Color pink = new Color(255, 175, 175); + + /** + * The color pink. + */ + public static final Color PINK = pink; + + /** + * The color orange. + */ + public static final Color orange = new Color(255, 200, 0); + + /** + * The color orange. + */ + public static final Color ORANGE = orange; + + /** + * The color yellow. + */ + public static final Color yellow = new Color(255, 255, 0); + + /** + * The color yellow. + */ + public static final Color YELLOW = yellow; + + /** + * The color green. + */ + public static final Color green = new Color(0, 255, 0); + + /** + * The color green. + */ + public static final Color GREEN = green; + + /** + * The color magenta. + */ + public static final Color magenta = new Color(255, 0, 255); + + /** + * The color magenta. + */ + public static final Color MAGENTA = magenta; + + /** + * The color cyan. + */ + public static final Color cyan = new Color(0, 255, 255); + + /** + * The color cyan. + */ + public static final Color CYAN = cyan; + + /** + * The color blue. + */ + public static final Color blue = new Color(0, 0, 255); + + /** + * The color blue. + */ + public static final Color BLUE = blue; + + /** + * integer RGB value. + */ + int value; + + /** + * Float sRGB value. + */ + private float[] frgbvalue; + + /** + * Color in an arbitrary color space with <code>float</code> components. If + * null, other value should be used. + */ + private float fvalue[]; + + /** + * Float alpha value. If frgbvalue is null, this is not valid data. + */ + private float falpha; + + /** + * The color's color space if applicable. + */ + private ColorSpace cs; + + /* + * The value of the SCALE_FACTOR is based on 1.5 release behavior which can + * be revealed using the following code: Color c = new Color(100, 100, 100); + * Color bc = c.brighter(); System.out.println("Brighter factor: " + + * ((float)c.getRed())/((float)bc.getRed())); Color dc = c.darker(); + * System.out.println("Darker factor: " + + * ((float)dc.getRed())/((float)c.getRed())); The result is the same for + * brighter and darker methods, so we need only one scale factor for both. + */ + /** + * The Constant SCALE_FACTOR. + */ + private static final double SCALE_FACTOR = 0.7; + + /** + * The Constant MIN_SCALABLE. + */ + private static final int MIN_SCALABLE = 3; // should increase when + + // multiplied by SCALE_FACTOR + + /** + * The current paint context. + */ + transient private PaintContext currentPaintContext; + + /** + * Creates a color in the specified ColorSpace, the specified color + * components and the specified alpha. + * + * @param cspace + * the ColorSpace to be used to define the components. + * @param components + * the components. + * @param alpha + * the alpha. + */ + public Color(ColorSpace cspace, float[] components, float alpha) { + int nComps = cspace.getNumComponents(); + float comp; + fvalue = new float[nComps]; + + for (int i = 0; i < nComps; i++) { + comp = components[i]; + if (comp < 0.0f || comp > 1.0f) { + // awt.107=Color parameter outside of expected range: component + // {0}. + throw new IllegalArgumentException(Messages.getString("awt.107", i)); //$NON-NLS-1$ + } + fvalue[i] = components[i]; + } + + if (alpha < 0.0f || alpha > 1.0f) { + // awt.108=Alpha value outside of expected range. + throw new IllegalArgumentException(Messages.getString("awt.108")); //$NON-NLS-1$ + } + falpha = alpha; + + cs = cspace; + + frgbvalue = cs.toRGB(fvalue); + + value = ((int)(frgbvalue[2] * 255 + 0.5)) | (((int)(frgbvalue[1] * 255 + 0.5)) << 8) + | (((int)(frgbvalue[0] * 255 + 0.5)) << 16) | (((int)(falpha * 255 + 0.5)) << 24); + } + + /** + * Instantiates a new sRGB color with the specified combined RGBA value + * consisting of the alpha component in bits 24-31, the red component in + * bits 16-23, the green component in bits 8-15, and the blue component in + * bits 0-7. If the hasalpha argument is false, the alpha has default value + * - 255. + * + * @param rgba + * the RGBA components. + * @param hasAlpha + * the alpha parameter is true if alpha bits are valid, false + * otherwise. + */ + public Color(int rgba, boolean hasAlpha) { + if (!hasAlpha) { + value = rgba | 0xFF000000; + } else { + value = rgba; + } + } + + /** + * Instantiates a new color with the specified red, green, blue and alpha + * components. + * + * @param r + * the red component. + * @param g + * the green component. + * @param b + * the blue component. + * @param a + * the alpha component. + */ + public Color(int r, int g, int b, int a) { + if ((r & 0xFF) != r || (g & 0xFF) != g || (b & 0xFF) != b || (a & 0xFF) != a) { + // awt.109=Color parameter outside of expected range. + throw new IllegalArgumentException(Messages.getString("awt.109")); //$NON-NLS-1$ + } + value = b | (g << 8) | (r << 16) | (a << 24); + } + + /** + * Instantiates a new opaque sRGB color with the specified red, green, and + * blue values. The Alpha component is set to the default - 1.0. + * + * @param r + * the red component. + * @param g + * the green component. + * @param b + * the blue component. + */ + public Color(int r, int g, int b) { + if ((r & 0xFF) != r || (g & 0xFF) != g || (b & 0xFF) != b) { + // awt.109=Color parameter outside of expected range. + throw new IllegalArgumentException(Messages.getString("awt.109")); //$NON-NLS-1$ + } + // 0xFF for alpha channel + value = b | (g << 8) | (r << 16) | 0xFF000000; + } + + /** + * Instantiates a new sRGB color with the specified RGB value consisting of + * the red component in bits 16-23, the green component in bits 8-15, and + * the blue component in bits 0-7. Alpha has default value - 255. + * + * @param rgb + * the RGB components. + */ + public Color(int rgb) { + value = rgb | 0xFF000000; + } + + /** + * Instantiates a new color with the specified red, green, blue and alpha + * components. + * + * @param r + * the red component. + * @param g + * the green component. + * @param b + * the blue component. + * @param a + * the alpha component. + */ + public Color(float r, float g, float b, float a) { + this((int)(r * 255 + 0.5), (int)(g * 255 + 0.5), (int)(b * 255 + 0.5), (int)(a * 255 + 0.5)); + falpha = a; + fvalue = new float[3]; + fvalue[0] = r; + fvalue[1] = g; + fvalue[2] = b; + frgbvalue = fvalue; + } + + /** + * Instantiates a new color with the specified red, green, and blue + * components and default alpha value - 1.0. + * + * @param r + * the red component. + * @param g + * the green component. + * @param b + * the blue component. + */ + public Color(float r, float g, float b) { + this(r, g, b, 1.0f); + } + + public PaintContext createContext(ColorModel cm, Rectangle r, Rectangle2D r2d, + AffineTransform xform, RenderingHints rhs) { + if (currentPaintContext != null) { + return currentPaintContext; + } + currentPaintContext = new Color.ColorPaintContext(value); + return currentPaintContext; + } + + /** + * Returns a string representation of the Color object. + * + * @return the string representation of the Color object. + */ + @Override + public String toString() { + /* + * The format of the string is based on 1.5 release behavior which can + * be revealed using the following code: Color c = new Color(1, 2, 3); + * System.out.println(c); + */ + + return getClass().getName() + "[r=" + getRed() + //$NON-NLS-1$ + ",g=" + getGreen() + //$NON-NLS-1$ + ",b=" + getBlue() + //$NON-NLS-1$ + "]"; //$NON-NLS-1$ + } + + /** + * Compares the specified Object to the Color. + * + * @param obj + * the Object to be compared. + * @return true, if the specified Object is a Color whose value is equal to + * this Color, false otherwise. + */ + @Override + public boolean equals(Object obj) { + if (obj instanceof Color) { + return ((Color)obj).value == this.value; + } + return false; + } + + /** + * Returns a float array containing the color and alpha components of the + * Color in the specified ColorSpace. + * + * @param colorSpace + * the specified ColorSpace. + * @param components + * the results of this method will be written to this float + * array. If null, a float array will be created. + * @return the color and alpha components in a float array. + */ + public float[] getComponents(ColorSpace colorSpace, float[] components) { + int nComps = colorSpace.getNumComponents(); + if (components == null) { + components = new float[nComps + 1]; + } + + getColorComponents(colorSpace, components); + + if (frgbvalue != null) { + components[nComps] = falpha; + } else { + components[nComps] = getAlpha() / 255f; + } + + return components; + } + + /** + * Returns a float array containing the color components of the Color in the + * specified ColorSpace. + * + * @param colorSpace + * the specified ColorSpace. + * @param components + * the results of this method will be written to this float + * array. If null, a float array will be created. + * @return the color components in a float array. + */ + public float[] getColorComponents(ColorSpace colorSpace, float[] components) { + float[] cieXYZComponents = getColorSpace().toCIEXYZ(getColorComponents(null)); + float[] csComponents = colorSpace.fromCIEXYZ(cieXYZComponents); + + if (components == null) { + return csComponents; + } + + for (int i = 0; i < csComponents.length; i++) { + components[i] = csComponents[i]; + } + + return components; + } + + /** + * Gets the ColorSpace of this Color. + * + * @return the ColorSpace object. + */ + public ColorSpace getColorSpace() { + if (cs == null) { + cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + } + + return cs; + } + + /** + * Creates a new Color which is a darker than this Color according to a + * fixed scale factor. + * + * @return the darker Color. + */ + public Color darker() { + return new Color((int)(getRed() * SCALE_FACTOR), (int)(getGreen() * SCALE_FACTOR), + (int)(getBlue() * SCALE_FACTOR)); + } + + /** + * Creates a new Color which is a brighter than this Color. + * + * @return the brighter Color. + */ + public Color brighter() { + + int r = getRed(); + int b = getBlue(); + int g = getGreen(); + + if (r == 0 && b == 0 && g == 0) { + return new Color(MIN_SCALABLE, MIN_SCALABLE, MIN_SCALABLE); + } + + if (r < MIN_SCALABLE && r != 0) { + r = MIN_SCALABLE; + } else { + r = (int)(r / SCALE_FACTOR); + r = (r > 255) ? 255 : r; + } + + if (b < MIN_SCALABLE && b != 0) { + b = MIN_SCALABLE; + } else { + b = (int)(b / SCALE_FACTOR); + b = (b > 255) ? 255 : b; + } + + if (g < MIN_SCALABLE && g != 0) { + g = MIN_SCALABLE; + } else { + g = (int)(g / SCALE_FACTOR); + g = (g > 255) ? 255 : g; + } + + return new Color(r, g, b); + } + + /** + * Returns a float array containing the color and alpha components of the + * Color in the default sRGB color space. + * + * @param components + * the results of this method will be written to this float + * array. A new float array will be created if this argument is + * null. + * @return the RGB color and alpha components in a float array. + */ + public float[] getRGBComponents(float[] components) { + if (components == null) { + components = new float[4]; + } + + if (frgbvalue != null) { + components[3] = falpha; + } else { + components[3] = getAlpha() / 255f; + } + + getRGBColorComponents(components); + + return components; + } + + /** + * Returns a float array containing the color components of the Color in the + * default sRGB color space. + * + * @param components + * the results of this method will be written to this float + * array. A new float array will be created if this argument is + * null. + * @return the RGB color components in a float array. + */ + public float[] getRGBColorComponents(float[] components) { + if (components == null) { + components = new float[3]; + } + + if (frgbvalue != null) { + components[2] = frgbvalue[2]; + components[1] = frgbvalue[1]; + components[0] = frgbvalue[0]; + } else { + components[2] = getBlue() / 255f; + components[1] = getGreen() / 255f; + components[0] = getRed() / 255f; + } + + return components; + } + + /** + * Returns a float array which contains the color and alpha components of + * the Color in the ColorSpace of the Color. + * + * @param components + * the results of this method will be written to this float + * array. A new float array will be created if this argument is + * null. + * @return the color and alpha components in a float array. + */ + public float[] getComponents(float[] components) { + if (fvalue == null) { + return getRGBComponents(components); + } + + int nColorComps = fvalue.length; + + if (components == null) { + components = new float[nColorComps + 1]; + } + + getColorComponents(components); + + components[nColorComps] = falpha; + + return components; + } + + /** + * Returns a float array which contains the color components of the Color in + * the ColorSpace of the Color. + * + * @param components + * the results of this method will be written to this float + * array. A new float array will be created if this argument is + * null. + * @return the color components in a float array. + */ + public float[] getColorComponents(float[] components) { + if (fvalue == null) { + return getRGBColorComponents(components); + } + + if (components == null) { + components = new float[fvalue.length]; + } + + for (int i = 0; i < fvalue.length; i++) { + components[i] = fvalue[i]; + } + + return components; + } + + /** + * Returns a hash code of this Color object. + * + * @return a hash code of this Color object. + */ + @Override + public int hashCode() { + return value; + } + + public int getTransparency() { + switch (getAlpha()) { + case 0xff: + return Transparency.OPAQUE; + case 0: + return Transparency.BITMASK; + default: + return Transparency.TRANSLUCENT; + } + } + + /** + * Gets the red component of the Color in the range 0-255. + * + * @return the red component of the Color. + */ + public int getRed() { + return (value >> 16) & 0xFF; + } + + /** + * Gets the RGB value that represents the color in the default sRGB + * ColorModel. + * + * @return the RGB color value in the default sRGB ColorModel. + */ + public int getRGB() { + return value; + } + + /** + * Gets the green component of the Color in the range 0-255. + * + * @return the green component of the Color. + */ + public int getGreen() { + return (value >> 8) & 0xFF; + } + + /** + * Gets the blue component of the Color in the range 0-255. + * + * @return the blue component of the Color. + */ + public int getBlue() { + return value & 0xFF; + } + + /** + * Gets the alpha component of the Color in the range 0-255. + * + * @return the alpha component of the Color. + */ + public int getAlpha() { + return (value >> 24) & 0xFF; + } + + /** + * Gets the Color from the specified string, or returns the Color specified + * by the second parameter. + * + * @param nm + * the specified string. + * @param def + * the default Color. + * @return the color from the specified string, or the Color specified by + * the second parameter. + */ + public static Color getColor(String nm, Color def) { + Integer integer = Integer.getInteger(nm); + + if (integer == null) { + return def; + } + + return new Color(integer.intValue()); + } + + /** + * Gets the Color from the specified string, or returns the Color converted + * from the second parameter. + * + * @param nm + * the specified string. + * @param def + * the default Color. + * @return the color from the specified string, or the Color converted from + * the second parameter. + */ + public static Color getColor(String nm, int def) { + Integer integer = Integer.getInteger(nm); + + if (integer == null) { + return new Color(def); + } + + return new Color(integer.intValue()); + } + + /** + * Gets the Color from the specified String. + * + * @param nm + * the specified string. + * @return the Color object, or null. + */ + public static Color getColor(String nm) { + Integer integer = Integer.getInteger(nm); + + if (integer == null) { + return null; + } + + return new Color(integer.intValue()); + } + + /** + * Decodes a String to an integer and returns the specified opaque Color. + * + * @param nm + * the String which represents an opaque color as a 24-bit + * integer. + * @return the Color object from the given String. + * @throws NumberFormatException + * if the specified string can not be converted to an integer. + */ + public static Color decode(String nm) throws NumberFormatException { + Integer integer = Integer.decode(nm); + return new Color(integer.intValue()); + } + + /** + * Gets a Color object using the specified values of the HSB color model. + * + * @param h + * the hue component of the Color. + * @param s + * the saturation of the Color. + * @param b + * the brightness of the Color. + * @return a color object with the specified hue, saturation and brightness + * values. + */ + public static Color getHSBColor(float h, float s, float b) { + return new Color(HSBtoRGB(h, s, b)); + } + + /** + * Converts the Color specified by the RGB model to an equivalent color in + * the HSB model. + * + * @param r + * the red component. + * @param g + * the green component. + * @param b + * the blue component. + * @param hsbvals + * the array of result hue, saturation, brightness values or + * null. + * @return the float array of hue, saturation, brightness values. + */ + public static float[] RGBtoHSB(int r, int g, int b, float[] hsbvals) { + if (hsbvals == null) { + hsbvals = new float[3]; + } + + int V = Math.max(b, Math.max(r, g)); + int temp = Math.min(b, Math.min(r, g)); + + float H, S, B; + + B = V / 255.f; + + if (V == temp) { + H = S = 0; + } else { + S = (V - temp) / ((float)V); + + float Cr = (V - r) / (float)(V - temp); + float Cg = (V - g) / (float)(V - temp); + float Cb = (V - b) / (float)(V - temp); + + if (r == V) { + H = Cb - Cg; + } else if (g == V) { + H = 2 + Cr - Cb; + } else { + H = 4 + Cg - Cr; + } + + H /= 6.f; + if (H < 0) { + H++; + } + } + + hsbvals[0] = H; + hsbvals[1] = S; + hsbvals[2] = B; + + return hsbvals; + } + + /** + * Converts the Color specified by the HSB model to an equivalent color in + * the default RGB model. + * + * @param hue + * the hue component of the Color. + * @param saturation + * the saturation of the Color. + * @param brightness + * the brightness of the Color. + * @return the RGB value of the color with the specified hue, saturation and + * brightness. + */ + public static int HSBtoRGB(float hue, float saturation, float brightness) { + float fr, fg, fb; + + if (saturation == 0) { + fr = fg = fb = brightness; + } else { + float H = (hue - (float)Math.floor(hue)) * 6; + int I = (int)Math.floor(H); + float F = H - I; + float M = brightness * (1 - saturation); + float N = brightness * (1 - saturation * F); + float K = brightness * (1 - saturation * (1 - F)); + + switch (I) { + case 0: + fr = brightness; + fg = K; + fb = M; + break; + case 1: + fr = N; + fg = brightness; + fb = M; + break; + case 2: + fr = M; + fg = brightness; + fb = K; + break; + case 3: + fr = M; + fg = N; + fb = brightness; + break; + case 4: + fr = K; + fg = M; + fb = brightness; + break; + case 5: + fr = brightness; + fg = M; + fb = N; + break; + default: + fr = fb = fg = 0; // impossible, to supress compiler error + } + } + + int r = (int)(fr * 255. + 0.5); + int g = (int)(fg * 255. + 0.5); + int b = (int)(fb * 255. + 0.5); + + return (r << 16) | (g << 8) | b | 0xFF000000; + } + + /** + * The Class ColorPaintContext. + */ + class ColorPaintContext implements PaintContext { + + /** + * The RGB value. + */ + int rgbValue; + + /** + * The saved raster. + */ + WritableRaster savedRaster = null; + + /** + * Instantiates a new color paint context. + * + * @param rgb + * the RGB value. + */ + protected ColorPaintContext(int rgb) { + rgbValue = rgb; + } + + public void dispose() { + savedRaster = null; + } + + public ColorModel getColorModel() { + return ColorModel.getRGBdefault(); + } + + public Raster getRaster(int x, int y, int w, int h) { + if (savedRaster == null || w != savedRaster.getWidth() || h != savedRaster.getHeight()) { + savedRaster = getColorModel().createCompatibleWritableRaster(w, h); + + // Suppose we have here simple INT/RGB color/sample model + DataBufferInt intBuffer = (DataBufferInt)savedRaster.getDataBuffer(); + int rgbValues[] = intBuffer.getData(); + int rgbFillValue = rgbValue; + Arrays.fill(rgbValues, rgbFillValue); + } + + return savedRaster; + } + } +} diff --git a/awt/java/awt/Component.java b/awt/java/awt/Component.java new file mode 100644 index 0000000..c52a9f4 --- /dev/null +++ b/awt/java/awt/Component.java @@ -0,0 +1,6020 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.awt; + +//import java.awt.dnd.DropTarget; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.HierarchyBoundsListener; +import java.awt.event.HierarchyEvent; +import java.awt.event.HierarchyListener; +import java.awt.event.InputMethodEvent; +import java.awt.event.InputMethodListener; +import java.awt.event.InvocationEvent; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.awt.event.PaintEvent; +import java.awt.event.WindowEvent; +import java.awt.im.InputContext; +import java.awt.im.InputMethodRequests; +import java.awt.image.BufferStrategy; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.VolatileImage; +import java.awt.image.WritableRaster; +import java.awt.peer.ComponentPeer; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.Serializable; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Collection; +import java.util.EventListener; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +//???AWT +//import javax.accessibility.Accessible; +//import javax.accessibility.AccessibleComponent; +//import javax.accessibility.AccessibleContext; +//import javax.accessibility.AccessibleRole; +//import javax.accessibility.AccessibleState; +//import javax.accessibility.AccessibleStateSet; + +import org.apache.harmony.awt.ClipRegion; //import org.apache.harmony.awt.FieldsAccessor; +import org.apache.harmony.awt.gl.MultiRectArea; +import org.apache.harmony.awt.internal.nls.Messages; +import org.apache.harmony.awt.state.State; //import org.apache.harmony.awt.text.TextFieldKit; +//import org.apache.harmony.awt.text.TextKit; +import org.apache.harmony.awt.wtk.NativeWindow; +import org.apache.harmony.luni.util.NotImplementedException; + +/** + * The abstract Component class specifies an object with a graphical + * representation that can be displayed on the screen and that can interact with + * the user (for example: scrollbars, buttons, checkboxes). + * + * @since Android 1.0 + */ +public abstract class Component implements ImageObserver, MenuContainer, Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -7644114512714619750L; + + /** + * The Constant TOP_ALIGNMENT indicates the top alignment of the component. + */ + public static final float TOP_ALIGNMENT = 0.0f; + + /** + * The Constant CENTER_ALIGNMENT indicates the center alignment of the + * component. + */ + public static final float CENTER_ALIGNMENT = 0.5f; + + /** + * The Constant BOTTOM_ALIGNMENT indicates the bottom alignment of the + * component. + */ + public static final float BOTTOM_ALIGNMENT = 1.0f; + + /** + * The Constant LEFT_ALIGNMENT indicates the left alignment of the + * component. + */ + public static final float LEFT_ALIGNMENT = 0.0f; + + /** + * The Constant RIGHT_ALIGNMENT indicates the right alignment of the + * component. + */ + public static final float RIGHT_ALIGNMENT = 1.0f; + + /** + * The Constant childClassesFlags. + */ + private static final Hashtable<Class<?>, Boolean> childClassesFlags = new Hashtable<Class<?>, Boolean>(); + + /** + * The Constant peer. + */ + private static final ComponentPeer peer = new ComponentPeer() { + }; + + /** + * The Constant incrementalImageUpdate. + */ + private static final boolean incrementalImageUpdate; + + /** + * The toolkit. + */ + final transient Toolkit toolkit = Toolkit.getDefaultToolkit(); + + // ???AWT + /* + * protected abstract class AccessibleAWTComponent extends AccessibleContext + * implements Serializable, AccessibleComponent { private static final long + * serialVersionUID = 642321655757800191L; protected class + * AccessibleAWTComponentHandler implements ComponentListener { protected + * AccessibleAWTComponentHandler() { } public void + * componentHidden(ComponentEvent e) { if (behaviour.isLightweight()) { + * return; } firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, + * AccessibleState.VISIBLE, null); } public void + * componentMoved(ComponentEvent e) { } public void + * componentResized(ComponentEvent e) { } public void + * componentShown(ComponentEvent e) { if (behaviour.isLightweight()) { + * return; } firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, + * null, AccessibleState.VISIBLE); } } protected class + * AccessibleAWTFocusHandler implements FocusListener { public void + * focusGained(FocusEvent e) { if (behaviour.isLightweight()) { return; } + * firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, null, + * AccessibleState.FOCUSED); } public void focusLost(FocusEvent e) { if + * (behaviour.isLightweight()) { return; } + * firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, + * AccessibleState.FOCUSED, null); } } protected ComponentListener + * accessibleAWTComponentHandler; protected FocusListener + * accessibleAWTFocusHandler; + */ + /* + * Number of registered property change listeners. + */ + /* + * int listenersCount; public void addFocusListener(FocusListener l) { + * Component.this.addFocusListener(l); } + * @Override public void addPropertyChangeListener(PropertyChangeListener + * listener) { toolkit.lockAWT(); try { + * super.addPropertyChangeListener(listener); listenersCount++; if + * (accessibleAWTComponentHandler == null) { accessibleAWTComponentHandler = + * new AccessibleAWTComponentHandler(); + * Component.this.addComponentListener(accessibleAWTComponentHandler); } if + * (accessibleAWTFocusHandler == null) { accessibleAWTFocusHandler = new + * AccessibleAWTFocusHandler(); + * Component.this.addFocusListener(accessibleAWTFocusHandler); } } finally { + * toolkit.unlockAWT(); } } public boolean contains(Point p) { + * toolkit.lockAWT(); try { return Component.this.contains(p); } finally { + * toolkit.unlockAWT(); } } public Accessible getAccessibleAt(Point arg0) { + * toolkit.lockAWT(); try { return null; } finally { toolkit.unlockAWT(); } + * } public Color getBackground() { toolkit.lockAWT(); try { return + * Component.this.getBackground(); } finally { toolkit.unlockAWT(); } } + * public Rectangle getBounds() { toolkit.lockAWT(); try { return + * Component.this.getBounds(); } finally { toolkit.unlockAWT(); } } public + * Cursor getCursor() { toolkit.lockAWT(); try { return + * Component.this.getCursor(); } finally { toolkit.unlockAWT(); } } public + * Font getFont() { toolkit.lockAWT(); try { return + * Component.this.getFont(); } finally { toolkit.unlockAWT(); } } public + * FontMetrics getFontMetrics(Font f) { toolkit.lockAWT(); try { return + * Component.this.getFontMetrics(f); } finally { toolkit.unlockAWT(); } } + * public Color getForeground() { toolkit.lockAWT(); try { return + * Component.this.getForeground(); } finally { toolkit.unlockAWT(); } } + * public Point getLocation() { toolkit.lockAWT(); try { return + * Component.this.getLocation(); } finally { toolkit.unlockAWT(); } } public + * Point getLocationOnScreen() { toolkit.lockAWT(); try { return + * Component.this.getLocationOnScreen(); } finally { toolkit.unlockAWT(); } + * } public Dimension getSize() { toolkit.lockAWT(); try { return + * Component.this.getSize(); } finally { toolkit.unlockAWT(); } } public + * boolean isEnabled() { toolkit.lockAWT(); try { return + * Component.this.isEnabled(); } finally { toolkit.unlockAWT(); } } public + * boolean isFocusTraversable() { toolkit.lockAWT(); try { return + * Component.this.isFocusTraversable(); } finally { toolkit.unlockAWT(); } } + * public boolean isShowing() { toolkit.lockAWT(); try { return + * Component.this.isShowing(); } finally { toolkit.unlockAWT(); } } public + * boolean isVisible() { toolkit.lockAWT(); try { return + * Component.this.isVisible(); } finally { toolkit.unlockAWT(); } } public + * void removeFocusListener(FocusListener l) { + * Component.this.removeFocusListener(l); } + * @Override public void removePropertyChangeListener(PropertyChangeListener + * listener) { toolkit.lockAWT(); try { + * super.removePropertyChangeListener(listener); listenersCount--; if + * (listenersCount > 0) { return; } // if there are no more listeners, + * remove handlers: + * Component.this.removeFocusListener(accessibleAWTFocusHandler); + * Component.this.removeComponentListener(accessibleAWTComponentHandler); + * accessibleAWTComponentHandler = null; accessibleAWTFocusHandler = null; } + * finally { toolkit.unlockAWT(); } } public void requestFocus() { + * toolkit.lockAWT(); try { Component.this.requestFocus(); } finally { + * toolkit.unlockAWT(); } } public void setBackground(Color color) { + * toolkit.lockAWT(); try { Component.this.setBackground(color); } finally { + * toolkit.unlockAWT(); } } public void setBounds(Rectangle r) { + * toolkit.lockAWT(); try { Component.this.setBounds(r); } finally { + * toolkit.unlockAWT(); } } public void setCursor(Cursor cursor) { + * toolkit.lockAWT(); try { Component.this.setCursor(cursor); } finally { + * toolkit.unlockAWT(); } } public void setEnabled(boolean enabled) { + * toolkit.lockAWT(); try { Component.this.setEnabled(enabled); } finally { + * toolkit.unlockAWT(); } } public void setFont(Font f) { toolkit.lockAWT(); + * try { Component.this.setFont(f); } finally { toolkit.unlockAWT(); } } + * public void setForeground(Color color) { toolkit.lockAWT(); try { + * Component.this.setForeground(color); } finally { toolkit.unlockAWT(); } } + * public void setLocation(Point p) { toolkit.lockAWT(); try { + * Component.this.setLocation(p); } finally { toolkit.unlockAWT(); } } + * public void setSize(Dimension size) { toolkit.lockAWT(); try { + * Component.this.setSize(size); } finally { toolkit.unlockAWT(); } } public + * void setVisible(boolean visible) { toolkit.lockAWT(); try { + * Component.this.setVisible(visible); } finally { toolkit.unlockAWT(); } } + * @Override public Accessible getAccessibleParent() { toolkit.lockAWT(); + * try { Accessible aParent = super.getAccessibleParent(); if (aParent != + * null) { return aParent; } Container parent = getParent(); return (parent + * instanceof Accessible ? (Accessible) parent : null); } finally { + * toolkit.unlockAWT(); } } + * @Override public Accessible getAccessibleChild(int i) { + * toolkit.lockAWT(); try { return null; } finally { toolkit.unlockAWT(); } + * } + * @Override public int getAccessibleChildrenCount() { toolkit.lockAWT(); + * try { return 0; } finally { toolkit.unlockAWT(); } } + * @Override public AccessibleComponent getAccessibleComponent() { return + * this; } + * @Override public String getAccessibleDescription() { return + * super.getAccessibleDescription(); // why override? } + * @Override public int getAccessibleIndexInParent() { toolkit.lockAWT(); + * try { if (getAccessibleParent() == null) { return -1; } int count = 0; + * Container parent = getParent(); for (int i = 0; i < + * parent.getComponentCount(); i++) { Component aComp = + * parent.getComponent(i); if (aComp instanceof Accessible) { if (aComp == + * Component.this) { return count; } ++count; } } return -1; } finally { + * toolkit.unlockAWT(); } } + * @Override public AccessibleRole getAccessibleRole() { toolkit.lockAWT(); + * try { return AccessibleRole.AWT_COMPONENT; } finally { + * toolkit.unlockAWT(); } } + * @Override public AccessibleStateSet getAccessibleStateSet() { + * toolkit.lockAWT(); try { AccessibleStateSet set = new + * AccessibleStateSet(); if (isEnabled()) { + * set.add(AccessibleState.ENABLED); } if (isFocusable()) { + * set.add(AccessibleState.FOCUSABLE); } if (hasFocus()) { + * set.add(AccessibleState.FOCUSED); } if (isOpaque()) { + * set.add(AccessibleState.OPAQUE); } if (isShowing()) { + * set.add(AccessibleState.SHOWING); } if (isVisible()) { + * set.add(AccessibleState.VISIBLE); } return set; } finally { + * toolkit.unlockAWT(); } } + * @Override public Locale getLocale() throws IllegalComponentStateException + * { toolkit.lockAWT(); try { return Component.this.getLocale(); } finally { + * toolkit.unlockAWT(); } } } + */ + /** + * The BltBufferStrategy class provides opportunity of blitting offscreen + * surfaces to a component. For more information on blitting, see <a + * href="http://en.wikipedia.org/wiki/Bit_blit">Bit blit</a>. + * + * @since Android 1.0 + */ + protected class BltBufferStrategy extends BufferStrategy { + + /** + * The back buffers. + */ + protected VolatileImage[] backBuffers; + + /** + * The caps. + */ + protected BufferCapabilities caps; + + /** + * The width. + */ + protected int width; + + /** + * The height. + */ + protected int height; + + /** + * The validated contents. + */ + protected boolean validatedContents; + + /** + * Instantiates a new BltBufferStrategy buffer strategy. + * + * @param numBuffers + * the number of buffers. + * @param caps + * the BufferCapabilities. + * @throws NotImplementedException + * the not implemented exception. + */ + protected BltBufferStrategy(int numBuffers, BufferCapabilities caps) + throws org.apache.harmony.luni.util.NotImplementedException { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + } + + /** + * Returns true if the drawing buffer has been lost since the last call + * to getDrawGraphics. + * + * @return true if the drawing buffer has been lost since the last call + * to getDrawGraphics, false otherwise. + * @see java.awt.image.BufferStrategy#contentsLost() + */ + @Override + public boolean contentsLost() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + return false; + } + + /** + * Returns true if the drawing buffer has been restored from a lost + * state and reinitialized to the default background color. + * + * @return true if the drawing buffer has been restored from a lost + * state and reinitialized to the default background color, + * false otherwise. + * @see java.awt.image.BufferStrategy#contentsRestored() + */ + @Override + public boolean contentsRestored() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + return false; + } + + /** + * Creates the back buffers. + * + * @param numBuffers + * the number of buffers. + */ + protected void createBackBuffers(int numBuffers) { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + } + + /** + * Returns the BufferCapabilities of the buffer strategy. + * + * @return the BufferCapabilities. + * @see java.awt.image.BufferStrategy#getCapabilities() + */ + @Override + public BufferCapabilities getCapabilities() { + return (BufferCapabilities)caps.clone(); + } + + /** + * Gets Graphics of current buffer strategy. + * + * @return the Graphics of current buffer strategy. + * @see java.awt.image.BufferStrategy#getDrawGraphics() + */ + @Override + public Graphics getDrawGraphics() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + return null; + } + + /** + * Revalidates the lost drawing buffer. + */ + protected void revalidate() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + } + + /** + * Shows the next available buffer. + * + * @see java.awt.image.BufferStrategy#show() + */ + @Override + public void show() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + } + } + + /** + * The FlipBufferStrategy class is for flipping buffers on a component. + * + * @since Android 1.0 + */ + protected class FlipBufferStrategy extends BufferStrategy { + + /** + * The Buffer Capabilities. + */ + protected BufferCapabilities caps; + + /** + * The drawing buffer. + */ + protected Image drawBuffer; + + /** + * The drawing VolatileImage buffer. + */ + protected VolatileImage drawVBuffer; + + /** + * The number of buffers. + */ + protected int numBuffers; + + /** + * The validated contents indicates if the drawing buffer is restored + * from lost state. + */ + protected boolean validatedContents; + + /** + * Instantiates a new flip buffer strategy. + * + * @param numBuffers + * the number of buffers. + * @param caps + * the BufferCapabilities. + * @throws AWTException + * if the capabilities supplied could not be supported or + * met. + */ + protected FlipBufferStrategy(int numBuffers, BufferCapabilities caps) throws AWTException { + // ???AWT + /* + * if (!(Component.this instanceof Window) && !(Component.this + * instanceof Canvas)) { // awt.14B=Only Canvas or Window is allowed + * throw new ClassCastException(Messages.getString("awt.14B")); + * //$NON-NLS-1$ } + */ + // TODO: throw new AWTException("Capabilities are not supported"); + this.numBuffers = numBuffers; + this.caps = (BufferCapabilities)caps.clone(); + } + + /** + * Returns true if the drawing buffer has been lost since the last call + * to getDrawGraphics. + * + * @return true if the drawing buffer has been lost since the last call + * to getDrawGraphics, false otherwise. + * @see java.awt.image.BufferStrategy#contentsLost() + */ + @Override + public boolean contentsLost() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + return false; + } + + /** + * Returns true if the drawing buffer has been restored from a lost + * state and reinitialized to the default background color. + * + * @return true if the drawing buffer has been restored from a lost + * state and reinitialized to the default background color, + * false otherwise. + * @see java.awt.image.BufferStrategy#contentsRestored() + */ + @Override + public boolean contentsRestored() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + return false; + } + + /** + * Creates flipping buffers with the specified buffer capabilities. + * + * @param numBuffers + * the number of buffers. + * @param caps + * the BufferCapabilities. + * @throws AWTException + * if the capabilities could not be supported or met. + */ + protected void createBuffers(int numBuffers, BufferCapabilities caps) throws AWTException { + if (numBuffers < 2) { + // awt.14C=Number of buffers must be greater than one + throw new IllegalArgumentException(Messages.getString("awt.14C")); //$NON-NLS-1$ + } + if (!caps.isPageFlipping()) { + // awt.14D=Buffer capabilities should support flipping + throw new IllegalArgumentException(Messages.getString("awt.14D")); //$NON-NLS-1$ + } + if (!Component.this.behaviour.isDisplayable()) { + // awt.14E=Component should be displayable + throw new IllegalStateException(Messages.getString("awt.14E")); //$NON-NLS-1$ + } + // TODO: throw new AWTException("Capabilities are not supported"); + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + } + + /** + * Destroy buffers. + */ + protected void destroyBuffers() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + } + + /** + * Flips the contents of the back buffer to the front buffer. + * + * @param flipAction + * the flip action. + */ + protected void flip(BufferCapabilities.FlipContents flipAction) { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + } + + /** + * Gets the back buffer as Image. + * + * @return the back buffer as Image. + */ + protected Image getBackBuffer() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + return null; + } + + /** + * Returns the BufferCapabilities of the buffer strategy. + * + * @return the BufferCapabilities. + * @see java.awt.image.BufferStrategy#getCapabilities() + */ + @Override + public BufferCapabilities getCapabilities() { + return (BufferCapabilities)caps.clone(); + } + + /** + * Gets Graphics of current buffer strategy. + * + * @return the Graphics of current buffer strategy. + * @see java.awt.image.BufferStrategy#getDrawGraphics() + */ + @Override + public Graphics getDrawGraphics() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + return null; + } + + /** + * Revalidates the lost drawing buffer. + */ + protected void revalidate() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + } + + /** + * Shows the next available buffer. + * + * @see java.awt.image.BufferStrategy#show() + */ + @Override + public void show() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + } + } + + /** + * The internal component's state utilized by the visual theme. + */ + class ComponentState implements State { + + /** + * The default minimum size. + */ + private Dimension defaultMinimumSize = new Dimension(); + + /** + * Checks if the component is enabled. + * + * @return true, if the component is enabled. + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Checks if the component is visible. + * + * @return true, if the component is visible. + */ + public boolean isVisible() { + return visible; + } + + /** + * Checks if is focused. + * + * @return true, if is focused. + */ + public boolean isFocused() { + // ???AWT: return isFocusOwner(); + return false; + } + + /** + * Gets the font. + * + * @return the font. + */ + public Font getFont() { + return Component.this.getFont(); + } + + /** + * Checks if the font has been set. + * + * @return true, if the font has been set. + */ + public boolean isFontSet() { + return font != null; + } + + /** + * Gets the background color. + * + * @return the background color. + */ + public Color getBackground() { + Color c = Component.this.getBackground(); + return (c != null) ? c : getDefaultBackground(); + } + + /** + * Checks if the background is set. + * + * @return true, if the background is set. + */ + public boolean isBackgroundSet() { + return backColor != null; + } + + /** + * Gets the text color. + * + * @return the text color. + */ + public Color getTextColor() { + Color c = getForeground(); + return (c != null) ? c : getDefaultForeground(); + } + + /** + * Checks if the text color is set. + * + * @return true, if the text color is set. + */ + public boolean isTextColorSet() { + return foreColor != null; + } + + /** + * Gets the font metrics. + * + * @return the font metrics. + */ + @SuppressWarnings("deprecation") + public FontMetrics getFontMetrics() { + return toolkit.getFontMetrics(Component.this.getFont()); + } + + /** + * Gets the bounding rectangle. + * + * @return the bounding rectangle. + */ + public Rectangle getBounds() { + return new Rectangle(x, y, w, h); + } + + /** + * Gets the size of the bounding rectangle. + * + * @return the size of the bounding rectangle. + */ + public Dimension getSize() { + return new Dimension(w, h); + } + + /** + * Gets the window id. + * + * @return the window id. + */ + public long getWindowId() { + NativeWindow win = getNativeWindow(); + return (win != null) ? win.getId() : 0; + } + + /** + * Gets the default minimum size. + * + * @return the default minimum size. + */ + public Dimension getDefaultMinimumSize() { + if (defaultMinimumSize == null) { + calculate(); + } + return defaultMinimumSize; + } + + /** + * Sets the default minimum size. + * + * @param size + * the new default minimum size. + */ + public void setDefaultMinimumSize(Dimension size) { + defaultMinimumSize = size; + } + + /** + * Reset the default minimum size to null. + */ + public void reset() { + defaultMinimumSize = null; + } + + /** + * Calculate the default minimum size: to be overridden. + */ + public void calculate() { + // to be overridden + } + } + + // ???AWT: private transient AccessibleContext accessibleContext; + + /** + * The behaviour. + */ + final transient ComponentBehavior behaviour; + + // ???AWT: Container parent; + + /** + * The name. + */ + private String name; + + /** + * The auto name. + */ + private boolean autoName = true; + + /** + * The font. + */ + private Font font; + + /** + * The back color. + */ + private Color backColor; + + /** + * The fore color. + */ + private Color foreColor; + + /** + * The deprecated event handler. + */ + boolean deprecatedEventHandler = true; + + /** + * The enabled events. + */ + private long enabledEvents; + + /** + * The enabled AWT events. + */ + private long enabledAWTEvents; + + /** + * The component listeners. + */ + private final AWTListenerList<ComponentListener> componentListeners = new AWTListenerList<ComponentListener>( + this); + + /** + * The focus listeners. + */ + private final AWTListenerList<FocusListener> focusListeners = new AWTListenerList<FocusListener>( + this); + + /** + * The hierarchy listeners. + */ + private final AWTListenerList<HierarchyListener> hierarchyListeners = new AWTListenerList<HierarchyListener>( + this); + + /** + * The hierarchy bounds listeners. + */ + private final AWTListenerList<HierarchyBoundsListener> hierarchyBoundsListeners = new AWTListenerList<HierarchyBoundsListener>( + this); + + /** + * The key listeners. + */ + private final AWTListenerList<KeyListener> keyListeners = new AWTListenerList<KeyListener>(this); + + /** + * The mouse listeners. + */ + private final AWTListenerList<MouseListener> mouseListeners = new AWTListenerList<MouseListener>( + this); + + /** + * The mouse motion listeners. + */ + private final AWTListenerList<MouseMotionListener> mouseMotionListeners = new AWTListenerList<MouseMotionListener>( + this); + + /** + * The mouse wheel listeners. + */ + private final AWTListenerList<MouseWheelListener> mouseWheelListeners = new AWTListenerList<MouseWheelListener>( + this); + + /** + * The input method listeners. + */ + private final AWTListenerList<InputMethodListener> inputMethodListeners = new AWTListenerList<InputMethodListener>( + this); + + /** + * The x. + */ + int x; + + /** + * The y. + */ + int y; + + /** + * The w. + */ + int w; + + /** + * The h. + */ + int h; + + /** + * The maximum size. + */ + private Dimension maximumSize; + + /** + * The minimum size. + */ + private Dimension minimumSize; + + /** + * The preferred size. + */ + private Dimension preferredSize; + + /** + * The bounds mask param. + */ + private int boundsMaskParam; + + /** + * The ignore repaint. + */ + private boolean ignoreRepaint; + + /** + * The enabled. + */ + private boolean enabled = true; + + /** + * The input methods enabled. + */ + private boolean inputMethodsEnabled = true; + + /** + * The dispatch to im. + */ + transient boolean dispatchToIM = true; + + /** + * The focusable. + */ + private boolean focusable = true; // By default, all Components return + + // true from isFocusable() method + /** + * The visible. + */ + boolean visible = true; + + /** + * The called set focusable. + */ + private boolean calledSetFocusable; + + /** + * The overridden is focusable. + */ + private boolean overridenIsFocusable = true; + + /** + * The focus traversal keys enabled. + */ + private boolean focusTraversalKeysEnabled = true; + + /** + * Possible keys are: FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, + * UP_CYCLE_TRAVERSAL_KEYS. + */ + private final Map<Integer, Set<? extends AWTKeyStroke>> traversalKeys = new HashMap<Integer, Set<? extends AWTKeyStroke>>(); + + /** + * The traversal i ds. + */ + int[] traversalIDs; + + /** + * The locale. + */ + private Locale locale; + + /** + * The orientation. + */ + private ComponentOrientation orientation; + + /** + * The property change support. + */ + private PropertyChangeSupport propertyChangeSupport; + + // ???AWT: private ArrayList<PopupMenu> popups; + + /** + * The coalescer. + */ + private boolean coalescer; + + /** + * The events table. + */ + private Hashtable<Integer, LinkedList<AWTEvent>> eventsTable; + + /** + * Cashed reference used during EventQueue.postEvent() + */ + private LinkedList<AWTEvent> eventsList; + + /** + * The hierarchy changing counter. + */ + private int hierarchyChangingCounter; + + /** + * The was showing. + */ + private boolean wasShowing; + + /** + * The was displayable. + */ + private boolean wasDisplayable; + + /** + * The cursor. + */ + Cursor cursor; + + // ???AWT: DropTarget dropTarget; + + /** + * The mouse exited expected. + */ + private boolean mouseExitedExpected; + + /** + * The repaint region. + */ + transient MultiRectArea repaintRegion; + + // ???AWT: transient RedrawManager redrawManager; + /** + * The redraw manager. + */ + transient Object redrawManager; + + /** + * The valid. + */ + private boolean valid; + + /** + * The updated images. + */ + private HashMap<Image, ImageParameters> updatedImages; + + /** + * The lock object for private component's data which don't affect the + * component hierarchy. + */ + private class ComponentLock { + } + + /** + * The component lock. + */ + private final transient Object componentLock = new ComponentLock(); + static { + PrivilegedAction<String[]> action = new PrivilegedAction<String[]>() { + public String[] run() { + String properties[] = new String[2]; + properties[0] = System.getProperty("awt.image.redrawrate", "100"); //$NON-NLS-1$ //$NON-NLS-2$ + properties[1] = System.getProperty("awt.image.incrementaldraw", "true"); //$NON-NLS-1$ //$NON-NLS-2$ + return properties; + } + }; + String properties[] = AccessController.doPrivileged(action); + // FIXME: rate is never used, can this code and the get property above + // be removed? + // int rate; + // + // try { + // rate = Integer.decode(properties[0]).intValue(); + // } catch (NumberFormatException e) { + // rate = 100; + // } + incrementalImageUpdate = properties[1].equals("true"); //$NON-NLS-1$ + } + + /** + * Instantiates a new component. + */ + protected Component() { + toolkit.lockAWT(); + try { + orientation = ComponentOrientation.UNKNOWN; + redrawManager = null; + // ???AWT + /* + * traversalIDs = this instanceof Container ? + * KeyboardFocusManager.contTraversalIDs : + * KeyboardFocusManager.compTraversalIDs; for (int element : + * traversalIDs) { traversalKeys.put(new Integer(element), null); } + * behaviour = createBehavior(); + */ + behaviour = null; + + deriveCoalescerFlag(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Determine that the class inherited from Component declares the method + * coalesceEvents(), and put the results to the childClassesFlags map. + */ + private void deriveCoalescerFlag() { + Class<?> thisClass = getClass(); + boolean flag = true; + synchronized (childClassesFlags) { + Boolean flagWrapper = childClassesFlags.get(thisClass); + if (flagWrapper == null) { + Method coalesceMethod = null; + for (Class<?> c = thisClass; c != Component.class; c = c.getSuperclass()) { + try { + coalesceMethod = c.getDeclaredMethod("coalesceEvents", new Class[] { //$NON-NLS-1$ + Class.forName("java.awt.AWTEvent"), //$NON-NLS-1$ + Class.forName("java.awt.AWTEvent")}); //$NON-NLS-1$ + } catch (Exception e) { + } + if (coalesceMethod != null) { + break; + } + } + flag = (coalesceMethod != null); + childClassesFlags.put(thisClass, Boolean.valueOf(flag)); + } else { + flag = flagWrapper.booleanValue(); + } + } + coalescer = flag; + if (flag) { + eventsTable = new Hashtable<Integer, LinkedList<AWTEvent>>(); + } else { + eventsTable = null; + } + } + + /** + * Sets the name of the Component. + * + * @param name + * the new name of the Component. + */ + public void setName(String name) { + String oldName; + toolkit.lockAWT(); + try { + autoName = false; + oldName = this.name; + this.name = name; + } finally { + toolkit.unlockAWT(); + } + firePropertyChange("name", oldName, name); //$NON-NLS-1$ + } + + /** + * Gets the name of this Component. + * + * @return the name of this Component. + */ + public String getName() { + toolkit.lockAWT(); + try { + if ((name == null) && autoName) { + name = autoName(); + } + return name; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Auto name. + * + * @return the string. + */ + String autoName() { + String name = getClass().getName(); + if (name.indexOf("$") != -1) { //$NON-NLS-1$ + return null; + } + // ???AWT + // int number = toolkit.autoNumber.nextComponent++; + int number = 0; + name = name.substring(name.lastIndexOf(".") + 1) + Integer.toString(number); //$NON-NLS-1$ + return name; + } + + /** + * Returns the string representation of the Component. + * + * @return the string representation of the Component. + */ + @Override + public String toString() { + /* + * The format is based on 1.5 release behavior which can be revealed by + * the following code: Component c = new Component(){}; + * c.setVisible(false); System.out.println(c); + */ + toolkit.lockAWT(); + try { + return getClass().getName() + "[" + paramString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + } finally { + toolkit.unlockAWT(); + } + } + + // ???AWT + /* + * public void add(PopupMenu popup) { toolkit.lockAWT(); try { if + * (popup.getParent() == this) { return; } if (popups == null) { popups = + * new ArrayList<PopupMenu>(); } popup.setParent(this); popups.add(popup); } + * finally { toolkit.unlockAWT(); } } + */ + + /** + * Returns true, if the component contains the specified Point. + * + * @param p + * the Point. + * @return true, if the component contains the specified Point, false + * otherwise. + */ + public boolean contains(Point p) { + toolkit.lockAWT(); + try { + return contains(p.x, p.y); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Returns true, if the component contains the point with the specified + * coordinates. + * + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @return true, if the component contains the point with the specified + * coordinates, false otherwise. + */ + public boolean contains(int x, int y) { + toolkit.lockAWT(); + try { + return inside(x, y); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Deprecated: replaced by replaced by getSize() method. + * + * @return the dimension. + * @deprecated Replaced by getSize() method. + */ + @Deprecated + public Dimension size() { + toolkit.lockAWT(); + try { + return new Dimension(w, h); + } finally { + toolkit.unlockAWT(); + } + } + + // ???AWT + /* + * public Container getParent() { toolkit.lockAWT(); try { return parent; } + * finally { toolkit.unlockAWT(); } } + */ + + /** + * List. + * + * @param out + * the out. + * @param indent + * the indent + * @return the nearest heavyweight ancestor in hierarchy or + * <code>null</code> if not found. + */ + // ???AWT + /* + * Component getHWAncestor() { return (parent != null ? + * parent.getHWSurface() : null); } + */ + + /** + * @return heavyweight component that is equal to or is a nearest + * heavyweight container of the current component, or + * <code>null</code> if not found. + */ + // ???AWT + /* + * Component getHWSurface() { Component parent; for (parent = this; (parent + * != null) && (parent.isLightweight()); parent = parent .getParent()) { ; } + * return parent; } Window getWindowAncestor() { Component par; for (par = + * this; par != null && !(par instanceof Window); par = par.getParent()) { ; + * } return (Window) par; } + */ + + /** + * To be called by container + */ + // ???AWT + /* + * void setParent(Container parent) { this.parent = parent; + * setRedrawManager(); } void setRedrawManager() { redrawManager = + * getRedrawManager(); } public void remove(MenuComponent menu) { + * toolkit.lockAWT(); try { if (menu.getParent() == this) { + * menu.setParent(null); popups.remove(menu); } } finally { + * toolkit.unlockAWT(); } } + */ + /** + * Prints a list of this component with the specified number of leading + * whitespace characters to the specified PrintStream. + * + * @param out + * the output PrintStream object. + * @param indent + * how many leading whitespace characters to prepend. + */ + public void list(PrintStream out, int indent) { + toolkit.lockAWT(); + try { + out.println(getIndentStr(indent) + this); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Prints a list of this component to the specified PrintWriter. + * + * @param out + * the output PrintWriter object. + */ + public void list(PrintWriter out) { + toolkit.lockAWT(); + try { + list(out, 1); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Prints a list of this component with the specified number of leading + * whitespace characters to the specified PrintWriter. + * + * @param out + * the output PrintWriter object. + * @param indent + * how many leading whitespace characters to prepend. + */ + public void list(PrintWriter out, int indent) { + toolkit.lockAWT(); + try { + out.println(getIndentStr(indent) + this); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets a string composed of the desired number of whitespace characters. + * + * @param indent + * the length of the String to return. + * @return the string composed of the desired number of whitespace + * characters. + */ + String getIndentStr(int indent) { + char[] ind = new char[indent]; + for (int i = 0; i < indent; ind[i++] = ' ') { + ; + } + return new String(ind); + } + + /** + * Prints a list of this component to the specified PrintStream. + * + * @param out + * the output PrintStream object. + */ + public void list(PrintStream out) { + toolkit.lockAWT(); + try { + // default indent = 1 + list(out, 1); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Prints a list of this component to the standard system output stream. + */ + public void list() { + toolkit.lockAWT(); + try { + list(System.out); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Prints this component. + * + * @param g + * the Graphics to be used for painting. + */ + public void print(Graphics g) { + toolkit.lockAWT(); + try { + paint(g); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Prints the component and all of its subcomponents. + * + * @param g + * the Graphics to be used for painting. + */ + public void printAll(Graphics g) { + toolkit.lockAWT(); + try { + paintAll(g); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the size of the Component specified by width and height parameters. + * + * @param width + * the width of the Component. + * @param height + * the height of the Component. + */ + public void setSize(int width, int height) { + toolkit.lockAWT(); + try { + resize(width, height); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the size of the Component specified by Dimension object. + * + * @param d + * the new size of the Component. + */ + public void setSize(Dimension d) { + toolkit.lockAWT(); + try { + resize(d); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Deprecated: replaced by setSize(int, int) method. + * + * @param width + * the width. + * @param height + * the height. + * @deprecated Replaced by setSize(int, int) method. + */ + @Deprecated + public void resize(int width, int height) { + toolkit.lockAWT(); + try { + boundsMaskParam = NativeWindow.BOUNDS_NOMOVE; + setBounds(x, y, width, height); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Deprecated: replaced by setSize(int, int) method. + * + * @param size + * the size. + * @deprecated Replaced by setSize(int, int) method. + */ + @Deprecated + public void resize(Dimension size) { + toolkit.lockAWT(); + try { + setSize(size.width, size.height); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not this component is completely opaque. + * + * @return true, if this component is completely opaque, false by default. + */ + public boolean isOpaque() { + toolkit.lockAWT(); + try { + return behaviour.isOpaque(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Disables. + * + * @deprecated Replaced by setEnabled(boolean) method. + */ + @Deprecated + public void disable() { + toolkit.lockAWT(); + try { + setEnabledImpl(false); + } finally { + toolkit.unlockAWT(); + } + // ???AWT: fireAccessibleStateChange(AccessibleState.ENABLED, false); + } + + /** + * Enables this component. + * + * @deprecated Replaced by setEnabled(boolean) method. + */ + @Deprecated + public void enable() { + toolkit.lockAWT(); + try { + setEnabledImpl(true); + } finally { + toolkit.unlockAWT(); + } + // ???AWT: fireAccessibleStateChange(AccessibleState.ENABLED, true); + } + + /** + * Enables or disable this component. + * + * @param b + * the boolean parameter. + * @deprecated Replaced by setEnabled(boolean) method. + */ + @Deprecated + public void enable(boolean b) { + toolkit.lockAWT(); + try { + if (b) { + enable(); + } else { + disable(); + } + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Stores the location of this component to the specified Point object; + * returns the point of the component's top-left corner. + * + * @param rv + * the Point object where the component's top-left corner + * position will be stored. + * @return the Point which specifies the component's top-left corner. + */ + public Point getLocation(Point rv) { + toolkit.lockAWT(); + try { + if (rv == null) { + rv = new Point(); + } + rv.setLocation(getX(), getY()); + return rv; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the location of this component on the form; returns the point of the + * component's top-left corner. + * + * @return the Point which specifies the component's top-left corner. + */ + public Point getLocation() { + toolkit.lockAWT(); + try { + return location(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the size of this Component. + * + * @return the size of this Component. + */ + public Dimension getSize() { + toolkit.lockAWT(); + try { + return size(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Stores the size of this Component to the specified Dimension object. + * + * @param rv + * the Dimension object where the size of the Component will be + * stored. + * @return the Dimension of this Component. + */ + public Dimension getSize(Dimension rv) { + toolkit.lockAWT(); + try { + if (rv == null) { + rv = new Dimension(); + } + rv.setSize(getWidth(), getHeight()); + return rv; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not this Component is valid. A component is valid if it + * is correctly sized and positioned within its parent container and all its + * children are also valid. + * + * @return true, if the Component is valid, false otherwise. + */ + public boolean isValid() { + toolkit.lockAWT(); + try { + return valid && behaviour.isDisplayable(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Deprecated: replaced by getComponentAt(int, int) method. + * + * @return the Point. + * @deprecated Replaced by getComponentAt(int, int) method. + */ + @Deprecated + public Point location() { + toolkit.lockAWT(); + try { + return new Point(x, y); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Connects this Component to a native screen resource and makes it + * displayable. This method not be called directly by user applications. + */ + public void addNotify() { + toolkit.lockAWT(); + try { + prepare4HierarchyChange(); + behaviour.addNotify(); + // ???AWT + // finishHierarchyChange(this, parent, 0); + // if (dropTarget != null) { + // dropTarget.addNotify(peer); + // } + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Map to display. + * + * @param b + * the b. + */ + void mapToDisplay(boolean b) { + // ???AWT + /* + * if (b && !isDisplayable()) { if ((this instanceof Window) || ((parent + * != null) && parent.isDisplayable())) { addNotify(); } } else if (!b + * && isDisplayable()) { removeNotify(); } + */ + } + + /** + * Gets the toolkit. + * + * @return accessible context specific for particular component. + */ + // ???AWT + /* + * AccessibleContext createAccessibleContext() { return null; } public + * AccessibleContext getAccessibleContext() { toolkit.lockAWT(); try { if + * (accessibleContext == null) { accessibleContext = + * createAccessibleContext(); } return accessibleContext; } finally { + * toolkit.unlockAWT(); } } + */ + + /** + * Gets Toolkit for the current Component. + * + * @return the Toolkit of this Component. + */ + public Toolkit getToolkit() { + return toolkit; + } + + /** + * Gets this component's locking object for AWT component tree and layout + * operations. + * + * @return the tree locking object. + */ + public final Object getTreeLock() { + return toolkit.awtTreeLock; + } + + /** + * Handles the event. Use ActionListener instead of this. + * + * @param evt + * the Event. + * @param what + * the event's key. + * @return true, if successful. + * @deprecated Use ActionListener class for registering event listener. + */ + @Deprecated + public boolean action(Event evt, Object what) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Gets the property change support. + * + * @return the property change support. + */ + private PropertyChangeSupport getPropertyChangeSupport() { + synchronized (componentLock) { + if (propertyChangeSupport == null) { + propertyChangeSupport = new PropertyChangeSupport(this); + } + return propertyChangeSupport; + } + } + + // ???AWT + /* + * public void addPropertyChangeListener(PropertyChangeListener listener) { + * getPropertyChangeSupport().addPropertyChangeListener(listener); } public + * void addPropertyChangeListener(String propertyName, + * PropertyChangeListener listener) { + * getPropertyChangeSupport().addPropertyChangeListener(propertyName, + * listener); } public void applyComponentOrientation(ComponentOrientation + * orientation) { toolkit.lockAWT(); try { + * setComponentOrientation(orientation); } finally { toolkit.unlockAWT(); } + * } + */ + + /** + * Returns true if the set of focus traversal keys for the given focus + * traversal operation has been explicitly defined for this Component. + * + * @param id + * the ID of traversal key. + * @return true, if the set of focus traversal keys for the given focus. + * traversal operation has been explicitly defined for this + * Component, false otherwise. + */ + public boolean areFocusTraversalKeysSet(int id) { + toolkit.lockAWT(); + try { + Integer Id = new Integer(id); + if (traversalKeys.containsKey(Id)) { + return traversalKeys.get(Id) != null; + } + // awt.14F=invalid focus traversal key identifier + throw new IllegalArgumentException(Messages.getString("awt.14F")); //$NON-NLS-1$ + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the bounds of the Component. + * + * @return the rectangle bounds of the Component. + * @deprecated Use getBounds() methood. + */ + @Deprecated + public Rectangle bounds() { + toolkit.lockAWT(); + try { + return new Rectangle(x, y, w, h); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Returns the construction status of a specified image with the specified + * width and height that is being created. + * + * @param image + * the image to be checked. + * @param width + * the width of scaled image which status is being checked, or + * -1. + * @param height + * the height of scaled image which status is being checked, or + * -1. + * @param observer + * the ImageObserver object to be notified while the image is + * being prepared. + * @return the ImageObserver flags of the current state of the image data. + */ + public int checkImage(Image image, int width, int height, ImageObserver observer) { + toolkit.lockAWT(); + try { + return toolkit.checkImage(image, width, height, observer); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Returns the construction status of a specified image that is being + * created. + * + * @param image + * the image to be checked. + * @param observer + * the ImageObserver object to be notified while the image is + * being prepared. + * @return the ImageObserver flags of the current state of the image data. + */ + public int checkImage(Image image, ImageObserver observer) { + toolkit.lockAWT(); + try { + return toolkit.checkImage(image, -1, -1, observer); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Coalesces the existed event with new event. + * + * @param existingEvent + * the existing event in the EventQueue. + * @param newEvent + * the new event to be posted to the EventQueue. + * @return the coalesced AWTEvent, or null if there is no coalescing done. + */ + protected AWTEvent coalesceEvents(AWTEvent existingEvent, AWTEvent newEvent) { + toolkit.lockAWT(); + try { + // Nothing to do: + // 1. Mouse events coalesced at WTK level + // 2. Paint events handled by RedrawManager + // This method is for overriding only + return null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks if this Component is a coalescer. + * + * @return true, if is coalescer. + */ + boolean isCoalescer() { + return coalescer; + } + + /** + * Gets the relative event. + * + * @param id + * the id. + * @return the relative event. + */ + AWTEvent getRelativeEvent(int id) { + Integer idWrapper = new Integer(id); + eventsList = eventsTable.get(idWrapper); + if (eventsList == null) { + eventsList = new LinkedList<AWTEvent>(); + eventsTable.put(idWrapper, eventsList); + return null; + } + if (eventsList.isEmpty()) { + return null; + } + return eventsList.getLast(); + } + + /** + * Adds the new event. + * + * @param event + * the event. + */ + void addNewEvent(AWTEvent event) { + eventsList.addLast(event); + } + + /** + * Removes the relative event. + */ + void removeRelativeEvent() { + eventsList.removeLast(); + } + + /** + * Removes the next event. + * + * @param id + * the id. + */ + void removeNextEvent(int id) { + eventsTable.get(new Integer(id)).removeFirst(); + } + + /** + * Creates the image with the specified ImageProducer. + * + * @param producer + * the ImageProducer to be used for image creation. + * @return the image with the specified ImageProducer. + */ + public Image createImage(ImageProducer producer) { + toolkit.lockAWT(); + try { + return toolkit.createImage(producer); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Creates an off-screen drawable image to be used for double buffering. + * + * @param width + * the width of the image. + * @param height + * the height of the image. + * @return the off-screen drawable image or null if the component is not + * displayable or GraphicsEnvironment.isHeadless() method returns + * true. + */ + public Image createImage(int width, int height) { + toolkit.lockAWT(); + try { + if (!isDisplayable()) { + return null; + } + GraphicsConfiguration gc = getGraphicsConfiguration(); + if (gc == null) { + return null; + } + ColorModel cm = gc.getColorModel(Transparency.OPAQUE); + WritableRaster wr = cm.createCompatibleWritableRaster(width, height); + Image image = new BufferedImage(cm, wr, cm.isAlphaPremultiplied(), null); + fillImageBackground(image, width, height); + return image; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Creates an off-screen drawable image with the specified width, height and + * ImageCapabilities. + * + * @param width + * the width. + * @param height + * the height. + * @param caps + * the ImageCapabilities. + * @return the volatile image. + * @throws AWTException + * if an image with the specified capabilities cannot be + * created. + */ + public VolatileImage createVolatileImage(int width, int height, ImageCapabilities caps) + throws AWTException { + toolkit.lockAWT(); + try { + if (!isDisplayable()) { + return null; + } + GraphicsConfiguration gc = getGraphicsConfiguration(); + if (gc == null) { + return null; + } + VolatileImage image = gc.createCompatibleVolatileImage(width, height, caps); + fillImageBackground(image, width, height); + return image; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Creates a volatile off-screen drawable image which is used for double + * buffering. + * + * @param width + * the width of image. + * @param height + * the height of image. + * @return the volatile image a volatile off-screen drawable image which is + * used for double buffering or null if the component is not + * displayable, or GraphicsEnvironment.isHeadless() method returns + * true. + */ + public VolatileImage createVolatileImage(int width, int height) { + toolkit.lockAWT(); + try { + if (!isDisplayable()) { + return null; + } + GraphicsConfiguration gc = getGraphicsConfiguration(); + if (gc == null) { + return null; + } + VolatileImage image = gc.createCompatibleVolatileImage(width, height); + fillImageBackground(image, width, height); + return image; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Fill the image being created by createImage() or createVolatileImage() + * with the component's background color to prepare it for double-buffered + * painting. + * + * @param image + * the image. + * @param width + * the width. + * @param height + * the height. + */ + private void fillImageBackground(Image image, int width, int height) { + Graphics gr = image.getGraphics(); + gr.setColor(getBackground()); + gr.fillRect(0, 0, width, height); + gr.dispose(); + } + + /** + * Delivers event. + * + * @param evt + * the event. + * @deprecated Replaced by dispatchEvent(AWTEvent e) method. + */ + @Deprecated + public void deliverEvent(Event evt) { + postEvent(evt); + } + + /** + * Prompts the layout manager to lay out this component. + */ + public void doLayout() { + toolkit.lockAWT(); + try { + layout(); + } finally { + toolkit.unlockAWT(); + } + // Implemented in Container + } + + /** + * Fire property change impl. + * + * @param propertyName + * the property name. + * @param oldValue + * the old value. + * @param newValue + * the new value. + */ + private void firePropertyChangeImpl(String propertyName, Object oldValue, Object newValue) { + PropertyChangeSupport pcs; + synchronized (componentLock) { + if (propertyChangeSupport == null) { + return; + } + pcs = propertyChangeSupport; + } + pcs.firePropertyChange(propertyName, oldValue, newValue); + } + + /** + * Reports a bound property changes for int properties. + * + * @param propertyName + * the property name. + * @param oldValue + * the old property's value. + * @param newValue + * the new property's value. + */ + protected void firePropertyChange(String propertyName, int oldValue, int newValue) { + firePropertyChangeImpl(propertyName, new Integer(oldValue), new Integer(newValue)); + } + + /** + * Report a bound property change for a boolean-valued property. + * + * @param propertyName + * the property name. + * @param oldValue + * the property's old value. + * @param newValue + * the property's new value. + */ + protected void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { + firePropertyChangeImpl(propertyName, Boolean.valueOf(oldValue), Boolean.valueOf(newValue)); + } + + /** + * Reports a bound property change for an Object-valued property. + * + * @param propertyName + * the property name. + * @param oldValue + * the property's old value. + * @param newValue + * the property's new value. + */ + protected void firePropertyChange(final String propertyName, final Object oldValue, + final Object newValue) { + firePropertyChangeImpl(propertyName, oldValue, newValue); + } + + /** + * Report a bound property change for a byte-valued property. + * + * @param propertyName + * the property name. + * @param oldValue + * the property's old value. + * @param newValue + * the property's new value. + */ + public void firePropertyChange(String propertyName, byte oldValue, byte newValue) { + firePropertyChangeImpl(propertyName, new Byte(oldValue), new Byte(newValue)); + } + + /** + * Report a bound property change for a char-valued property. + * + * @param propertyName + * the property name. + * @param oldValue + * the old property's value. + * @param newValue + * the new property's value. + */ + public void firePropertyChange(String propertyName, char oldValue, char newValue) { + firePropertyChangeImpl(propertyName, new Character(oldValue), new Character(newValue)); + } + + /** + * Report a bound property change for a short-valued property. + * + * @param propertyName + * the property name. + * @param oldValue + * the old property's value. + * @param newValue + * the new property's value. + */ + public void firePropertyChange(String propertyName, short oldValue, short newValue) { + firePropertyChangeImpl(propertyName, new Short(oldValue), new Short(newValue)); + } + + /** + * Report a bound property change for a long-valued property. + * + * @param propertyName + * the property name. + * @param oldValue + * the old property's value. + * @param newValue + * the new property's value. + */ + public void firePropertyChange(String propertyName, long oldValue, long newValue) { + firePropertyChangeImpl(propertyName, new Long(oldValue), new Long(newValue)); + } + + /** + * Report a bound property change for a float-valued property. + * + * @param propertyName + * the property name. + * @param oldValue + * the old property's value. + * @param newValue + * the new property's value. + */ + public void firePropertyChange(String propertyName, float oldValue, float newValue) { + firePropertyChangeImpl(propertyName, new Float(oldValue), new Float(newValue)); + } + + /** + * Report a bound property change for a double-valued property. + * + * @param propertyName + * the property name. + * @param oldValue + * the old property's value. + * @param newValue + * the new property's value. + */ + public void firePropertyChange(String propertyName, double oldValue, double newValue) { + firePropertyChangeImpl(propertyName, new Double(oldValue), new Double(newValue)); + } + + /** + * Gets the alignment along the x axis. + * + * @return the alignment along the x axis. + */ + public float getAlignmentX() { + toolkit.lockAWT(); + try { + return CENTER_ALIGNMENT; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the alignment along the y axis. + * + * @return the alignment along y axis. + */ + public float getAlignmentY() { + toolkit.lockAWT(); + try { + return CENTER_ALIGNMENT; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the background color for this component. + * + * @return the background color for this component. + */ + public Color getBackground() { + toolkit.lockAWT(); + try { + // ???AWT + /* + * if ((backColor == null) && (parent != null)) { return + * parent.getBackground(); } + */ + return backColor; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the bounding rectangle of this component. + * + * @return the bounding rectangle of this component. + */ + public Rectangle getBounds() { + toolkit.lockAWT(); + try { + return bounds(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Writes the data of the bounding rectangle to the specified Rectangle + * object. + * + * @param rv + * the Rectangle object where the bounding rectangle's data is + * stored. + * @return the bounding rectangle. + */ + public Rectangle getBounds(Rectangle rv) { + toolkit.lockAWT(); + try { + if (rv == null) { + rv = new Rectangle(); + } + rv.setBounds(x, y, w, h); + return rv; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the color model of the Component. + * + * @return the color model of the Component. + */ + public ColorModel getColorModel() { + toolkit.lockAWT(); + try { + return getToolkit().getColorModel(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the Component which contains the specified Point. + * + * @param p + * the Point. + * @return the Component which contains the specified Point. + */ + public Component getComponentAt(Point p) { + toolkit.lockAWT(); + try { + return getComponentAt(p.x, p.y); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the Component which contains the point with the specified + * coordinates. + * + * @param x + * the x coordinate of the point. + * @param y + * the y coordinate of the point. + * @return the Component which contains the point with the specified + * coordinates. + */ + public Component getComponentAt(int x, int y) { + toolkit.lockAWT(); + try { + return locate(x, y); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the component's orientation. + * + * @return the component's orientation. + */ + public ComponentOrientation getComponentOrientation() { + toolkit.lockAWT(); + try { + return orientation; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the cursor of the Component. + * + * @return the Cursor. + */ + public Cursor getCursor() { + toolkit.lockAWT(); + try { + if (cursor != null) { + return cursor; + // ???AWT + /* + * } else if (parent != null) { return parent.getCursor(); + */ + } + return Cursor.getDefaultCursor(); + } finally { + toolkit.unlockAWT(); + } + } + + // ???AWT + /* + * public DropTarget getDropTarget() { toolkit.lockAWT(); try { return + * dropTarget; } finally { toolkit.unlockAWT(); } } public Container + * getFocusCycleRootAncestor() { toolkit.lockAWT(); try { for (Container c = + * parent; c != null; c = c.getParent()) { if (c.isFocusCycleRoot()) { + * return c; } } return null; } finally { toolkit.unlockAWT(); } } + * @SuppressWarnings("unchecked") public Set<AWTKeyStroke> + * getFocusTraversalKeys(int id) { toolkit.lockAWT(); try { Integer kId = + * new Integer(id); KeyboardFocusManager.checkTraversalKeysID(traversalKeys, + * kId); Set<? extends AWTKeyStroke> keys = traversalKeys.get(kId); if (keys + * == null && parent != null) { keys = parent.getFocusTraversalKeys(id); } + * if (keys == null) { keys = + * KeyboardFocusManager.getCurrentKeyboardFocusManager() + * .getDefaultFocusTraversalKeys(id); } return (Set<AWTKeyStroke>) keys; } + * finally { toolkit.unlockAWT(); } } + */ + + /** + * Checks if the the focus traversal keys are enabled for this component. + * + * @return true, if the the focus traversal keys are enabled for this + * component, false otherwise. + */ + public boolean getFocusTraversalKeysEnabled() { + toolkit.lockAWT(); + try { + return focusTraversalKeysEnabled; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the font metrics of the specified Font. + * + * @param f + * the Font. + * @return the FontMetrics of the specified Font. + */ + @SuppressWarnings("deprecation") + public FontMetrics getFontMetrics(Font f) { + return toolkit.getFontMetrics(f); + } + + /** + * Gets the foreground color of the Component. + * + * @return the foreground color of the Component. + */ + public Color getForeground() { + toolkit.lockAWT(); + try { + // ???AWT + /* + * if (foreColor == null && parent != null) { return + * parent.getForeground(); } + */ + return foreColor; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the Graphics of the Component or null if this Component is not + * displayable. + * + * @return the Graphics of the Component or null if this Component is not + * displayable. + */ + public Graphics getGraphics() { + toolkit.lockAWT(); + try { + if (!isDisplayable()) { + return null; + } + Graphics g = behaviour.getGraphics(0, 0, w, h); + g.setColor(foreColor); + g.setFont(font); + return g; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the GraphicsConfiguration associated with this Component. + * + * @return the GraphicsConfiguration associated with this Component. + */ + public GraphicsConfiguration getGraphicsConfiguration() { + // ???AWT + /* + * toolkit.lockAWT(); try { Window win = getWindowAncestor(); if (win == + * null) { return null; } return win.getGraphicsConfiguration(); } + * finally { toolkit.unlockAWT(); } + */ + return null; + } + + /** + * Gets the height of the Component. + * + * @return the height of the Component. + */ + public int getHeight() { + toolkit.lockAWT(); + try { + return h; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Returns true if paint messages received from the operating system should + * be ignored. + * + * @return true if paint messages received from the operating system should + * be ignored, false otherwise. + */ + public boolean getIgnoreRepaint() { + toolkit.lockAWT(); + try { + return ignoreRepaint; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the input context of this component for handling the communication + * with input methods when text is entered in this component. + * + * @return the InputContext used by this Component or null if no context is + * specifined. + */ + public InputContext getInputContext() { + toolkit.lockAWT(); + try { + // ???AWT + /* + * Container parent = getParent(); if (parent != null) { return + * parent.getInputContext(); } + */ + return null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the input method request handler which supports requests from input + * methods for this component, or null for default. + * + * @return the input method request handler which supports requests from + * input methods for this component, or null for default. + */ + public InputMethodRequests getInputMethodRequests() { + return null; + } + + /** + * Gets the locale of this Component. + * + * @return the locale of this Component. + */ + public Locale getLocale() { + toolkit.lockAWT(); + try { + // ???AWT + /* + * if (locale == null) { if (parent == null) { if (this instanceof + * Window) { return Locale.getDefault(); } // awt.150=no parent + * throw new + * IllegalComponentStateException(Messages.getString("awt.150")); + * //$NON-NLS-1$ } return getParent().getLocale(); } + */ + return locale; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the location of this component in the form of a point specifying the + * component's top-left corner in the screen's coordinate space. + * + * @return the Point giving the component's location in the screen's + * coordinate space. + * @throws IllegalComponentStateException + * if the component is not shown on the screen. + */ + public Point getLocationOnScreen() throws IllegalComponentStateException { + toolkit.lockAWT(); + try { + Point p = new Point(); + if (isShowing()) { + // ???AWT + /* + * Component comp; for (comp = this; comp != null && !(comp + * instanceof Window); comp = comp .getParent()) { + * p.translate(comp.getX(), comp.getY()); } if (comp instanceof + * Window) { p.translate(comp.getX(), comp.getY()); } + */ + return p; + } + // awt.151=component must be showing on the screen to determine its + // location + throw new IllegalComponentStateException(Messages.getString("awt.151")); //$NON-NLS-1$ + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the peer. This method should not be called directly by user + * applications. + * + * @return the ComponentPeer. + * @deprecated Replaced by isDisplayable(). + */ + @Deprecated + public ComponentPeer getPeer() { + toolkit.lockAWT(); + try { + if (behaviour.isDisplayable()) { + return peer; + } + return null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets an array of the property change listeners registered to this + * Component. + * + * @return an array of the PropertyChangeListeners registered to this + * Component. + */ + public PropertyChangeListener[] getPropertyChangeListeners() { + return getPropertyChangeSupport().getPropertyChangeListeners(); + } + + /** + * Gets an array of PropertyChangeListener objects registered to this + * Component for the specified property. + * + * @param propertyName + * the property name. + * @return an array of PropertyChangeListener objects registered to this + * Component for the specified property. + */ + public PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { + return getPropertyChangeSupport().getPropertyChangeListeners(propertyName); + } + + /** + * Gets the width of the Component. + * + * @return the width of the Component. + */ + public int getWidth() { + toolkit.lockAWT(); + try { + return w; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the x coordinate of the component's top-left corner. + * + * @return the x coordinate of the component's top-left corner. + */ + public int getX() { + toolkit.lockAWT(); + try { + return x; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the y coordinate of the component's top-left corner. + * + * @return the y coordinate of the component's top-left corner. + */ + public int getY() { + toolkit.lockAWT(); + try { + return y; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Got the focus. + * + * @param evt + * the Event. + * @param what + * the Object. + * @return true, if successful. + * @deprecated Replaced by processFocusEvent(FocusEvent) method. + */ + @Deprecated + public boolean gotFocus(Event evt, Object what) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Handles event. + * + * @param evt + * the Event. + * @return true, if successful. + * @deprecated Replaced by processEvent(AWTEvent) method. + */ + @Deprecated + public boolean handleEvent(Event evt) { + switch (evt.id) { + case Event.ACTION_EVENT: + return action(evt, evt.arg); + case Event.GOT_FOCUS: + return gotFocus(evt, null); + case Event.LOST_FOCUS: + return lostFocus(evt, null); + case Event.MOUSE_DOWN: + return mouseDown(evt, evt.x, evt.y); + case Event.MOUSE_DRAG: + return mouseDrag(evt, evt.x, evt.y); + case Event.MOUSE_ENTER: + return mouseEnter(evt, evt.x, evt.y); + case Event.MOUSE_EXIT: + return mouseExit(evt, evt.x, evt.y); + case Event.MOUSE_MOVE: + return mouseMove(evt, evt.x, evt.y); + case Event.MOUSE_UP: + return mouseUp(evt, evt.x, evt.y); + case Event.KEY_ACTION: + case Event.KEY_PRESS: + return keyDown(evt, evt.key); + case Event.KEY_ACTION_RELEASE: + case Event.KEY_RELEASE: + return keyUp(evt, evt.key); + } + return false;// event not handled + } + + /** + * Checks whether the Component is the focus owner or not. + * + * @return true, if the Component is the focus owner, false otherwise. + */ + public boolean hasFocus() { + toolkit.lockAWT(); + try { + // ???AWT: return isFocusOwner(); + return false; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Hides the Component. + * + * @deprecated Replaced by setVisible(boolean) method. + */ + @Deprecated + public void hide() { + toolkit.lockAWT(); + try { + if (!visible) { + return; + } + prepare4HierarchyChange(); + visible = false; + moveFocusOnHide(); + behaviour.setVisible(false); + postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_HIDDEN)); + // ???AWT: finishHierarchyChange(this, parent, 0); + notifyInputMethod(null); + // ???AWT: invalidateRealParent(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not the point with the specified coordinates belongs to + * the Commponent. + * + * @param x + * the x coordinate of the Point. + * @param y + * the y coordinate of the Point. + * @return true, if the point with the specified coordinates belongs to the + * Commponent, false otherwise. + * @deprecated Replaced by contains(int, int) method. + */ + @Deprecated + public boolean inside(int x, int y) { + toolkit.lockAWT(); + try { + return x >= 0 && x < getWidth() && y >= 0 && y < getHeight(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Invalidates the component, this component and all parents above it are + * marked as needing to be laid out. + */ + public void invalidate() { + toolkit.lockAWT(); + try { + valid = false; + resetDefaultSize(); + // ???AWT: invalidateRealParent(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not the background color is set to this Component. + * + * @return true, if the background color is set to this Component, false + * otherwise. + */ + public boolean isBackgroundSet() { + toolkit.lockAWT(); + try { + return backColor != null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not a cursor is set for the Component. + * + * @return true, if a cursor is set for the Component, false otherwise. + */ + public boolean isCursorSet() { + toolkit.lockAWT(); + try { + return cursor != null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not this Component is displayable. + * + * @return true, if this Component is displayable, false otherwise. + */ + public boolean isDisplayable() { + toolkit.lockAWT(); + try { + return behaviour.isDisplayable(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not this component is painted to an buffer which is + * copied to the screen later. + * + * @return true, if this component is painted to an buffer which is copied + * to the screen later, false otherwise. + */ + public boolean isDoubleBuffered() { + toolkit.lockAWT(); + try { + // false by default + return false; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not this Component is enabled. + * + * @return true, if this Component is enabled, false otherwise. + */ + public boolean isEnabled() { + toolkit.lockAWT(); + try { + return enabled; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * "Recursive" isEnabled(). + * + * @return true if not only component itself is enabled but its heavyweight + * parent is also "indirectly" enabled. + */ + boolean isIndirectlyEnabled() { + Component comp = this; + while (comp != null) { + if (!comp.isLightweight() && !comp.isEnabled()) { + return false; + } + // ???AWT: comp = comp.getRealParent(); + } + return true; + } + + /** + * Checks if the component is key enabled. + * + * @return true, if the component is enabled and indirectly enabled. + */ + boolean isKeyEnabled() { + if (!isEnabled()) { + return false; + } + return isIndirectlyEnabled(); + } + + /** + * Gets only parent of a child component, but not owner of a window. + * + * @return parent of child component, null if component is a top-level + * (Window instance). + */ + // ???AWT + /* + * Container getRealParent() { return (!(this instanceof Window) ? + * getParent() : null); } public boolean isFocusCycleRoot(Container + * container) { toolkit.lockAWT(); try { return getFocusCycleRootAncestor() + * == container; } finally { toolkit.unlockAWT(); } } public boolean + * isFocusOwner() { toolkit.lockAWT(); try { return + * KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() == + * this; } finally { toolkit.unlockAWT(); } } + */ + + /** + * Checks whether or not this Component can be focusable. + * + * @return true, if this Component can be focusable, false otherwise. + * @deprecated Replaced by isFocusable(). + */ + @Deprecated + public boolean isFocusTraversable() { + toolkit.lockAWT(); + try { + overridenIsFocusable = false; + return focusable; // a Component must either be both focusable and + // focus traversable, or neither + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks if this Component can be focusable or not. + * + * @return true, if this Component can be focusable, false otherwise. + */ + public boolean isFocusable() { + toolkit.lockAWT(); + try { + return isFocusTraversable(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks if the Font is set for this Component or not. + * + * @return true, if the Font is set, false otherwise. + */ + public boolean isFontSet() { + toolkit.lockAWT(); + try { + return font != null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks if foreground color is set for the Component or not. + * + * @return true, if is foreground color is set for the Component, false + * otherwise. + */ + public boolean isForegroundSet() { + toolkit.lockAWT(); + try { + return foreColor != null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Returns true if this component has a lightweight peer. + * + * @return true, if this component has a lightweight peer, false if it has a + * native peer or no peer. + */ + public boolean isLightweight() { + toolkit.lockAWT(); + try { + return behaviour.isLightweight(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not this Component is shown. + * + * @return true, if this Component is shown, false otherwise. + */ + public boolean isShowing() { + // ???AWT + /* + * toolkit.lockAWT(); try { return (isVisible() && isDisplayable() && + * (parent != null) && parent.isShowing()); } finally { + * toolkit.unlockAWT(); } + */ + return false; + } + + /** + * Checks whether or not this Component is visible. + * + * @return true, if the Component is visible, false otherwise. + */ + public boolean isVisible() { + toolkit.lockAWT(); + try { + return visible; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Deprecated: replaced by processKeyEvent(KeyEvent) method. + * + * @param evt + * the Event. + * @param key + * the key code. + * @return true, if successful. + * @deprecated Replaced by replaced by processKeyEvent(KeyEvent) method. + */ + @Deprecated + public boolean keyDown(Event evt, int key) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Deprecated: replaced by processKeyEvent(KeyEvent) method. + * + * @param evt + * the Event. + * @param key + * the key code. + * @return true, if successful. + * @deprecated Replaced by processKeyEvent(KeyEvent) method. + */ + @Deprecated + public boolean keyUp(Event evt, int key) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Deprecated: Replaced by doLayout() method. + * + * @deprecated Replaced by doLayout() method. + */ + @Deprecated + public void layout() { + toolkit.lockAWT(); + try { + // Implemented in Container + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Deprecated: replaced by getComponentAt(int, int) method. + * + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @return The component. + * @deprecated Replaced by getComponentAt(int, int) method. + */ + @Deprecated + public Component locate(int x, int y) { + toolkit.lockAWT(); + try { + if (contains(x, y)) { + return this; + } + return null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Deprecated: replaced by processFocusEvent(FocusEvent). + * + * @param evt + * the Event. + * @param what + * the Object. + * @return true, if successful. + * @deprecated Replaced by processFocusEvent(FocusEvent). + */ + @Deprecated + public boolean lostFocus(Event evt, Object what) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Deprecated: replaced by processMouseEvent(MouseEvent) method. + * + * @param evt + * the MouseEvent. + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @return true, if successful. + * @deprecated Replaced by processMouseEvent(MouseEvent) method. + */ + @Deprecated + public boolean mouseDown(Event evt, int x, int y) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Deprecated: replaced by getMinimumSize() method. + * + * @param evt + * the Event. + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @return true, if successful. + * @deprecated Replaced by getMinimumSize() method. + */ + @Deprecated + public boolean mouseDrag(Event evt, int x, int y) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Replaced by processMouseEvent(MouseEvent) method. + * + * @param evt + * the Event. + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @return true, if successful. + * @deprecated replaced by processMouseEvent(MouseEvent) method. + */ + @Deprecated + public boolean mouseEnter(Event evt, int x, int y) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Replaced by processMouseEvent(MouseEvent) method. + * + * @param evt + * the Event. + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @return true, if successful. + * @deprecated Replaced by processMouseEvent(MouseEvent) method. + */ + @Deprecated + public boolean mouseExit(Event evt, int x, int y) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Replaced by processMouseEvent(MouseEvent) method. + * + * @param evt + * the Event. + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @deprecated Replaced by processMouseEvent(MouseEvent) method. + * @return true, if successful. + */ + @Deprecated + public boolean mouseMove(Event evt, int x, int y) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Replaced by processMouseEvent(MouseEvent) method. + * + * @param evt + * the Event. + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @return true, if successful. + * @deprecated Replaced by processMouseEvent(MouseEvent) method. + */ + @Deprecated + public boolean mouseUp(Event evt, int x, int y) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Deprecated: replaced by setLocation(int, int) method. + * + * @param x + * the x coordinates. + * @param y + * the y coordinates. + * @deprecated Replaced by setLocation(int, int) method. + */ + @Deprecated + public void move(int x, int y) { + toolkit.lockAWT(); + try { + boundsMaskParam = NativeWindow.BOUNDS_NOSIZE; + setBounds(x, y, w, h); + } finally { + toolkit.unlockAWT(); + } + } + + // ???AWT + /* + * @Deprecated public void nextFocus() { toolkit.lockAWT(); try { + * transferFocus(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); } finally { + * toolkit.unlockAWT(); } } + */ + + /** + * Returns a string representation of the component's state. + * + * @return the string representation of the component's state. + */ + protected String paramString() { + /* + * The format is based on 1.5 release behavior which can be revealed by + * the following code: Component c = new Component(){}; + * c.setVisible(false); System.out.println(c); + */ + toolkit.lockAWT(); + try { + return getName() + "," + getX() + "," + getY() + "," + getWidth() + "x" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + + getHeight() + (!isVisible() ? ",hidden" : ""); //$NON-NLS-1$ //$NON-NLS-2$ + } finally { + toolkit.unlockAWT(); + } + } + + @Deprecated + @SuppressWarnings("deprecation") + public boolean postEvent(Event evt) { + boolean handled = handleEvent(evt); + if (handled) { + return true; + } + // ???AWT + /* + * // propagate non-handled events up to parent Component par = parent; + * // try to call postEvent only on components which // override any of + * deprecated method handlers // while (par != null && + * !par.deprecatedEventHandler) { // par = par.parent; // } // translate + * event coordinates before posting it to parent if (par != null) { + * evt.translate(x, y); par.postEvent(evt); } + */ + return false; + } + + /** + * Prepares an image for rendering on the Component. + * + * @param image + * the Image to be prepared. + * @param observer + * the ImageObserver object to be notified as soon as the image + * is prepared. + * @return true if the image has been fully prepared, false otherwise. + */ + public boolean prepareImage(Image image, ImageObserver observer) { + toolkit.lockAWT(); + try { + return toolkit.prepareImage(image, -1, -1, observer); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Prepares an image for rendering on the Component with the specified + * width, height, and ImageObserver. + * + * @param image + * the Image to be prepared. + * @param width + * the width of scaled image. + * @param height + * the height of scaled height. + * @param observer + * the ImageObserver object to be notified as soon as the image + * is prepared. + * @return true if the image is been fully prepared, false otherwise. + */ + public boolean prepareImage(Image image, int width, int height, ImageObserver observer) { + toolkit.lockAWT(); + try { + return toolkit.prepareImage(image, width, height, observer); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Makes this Component undisplayable. + */ + public void removeNotify() { + toolkit.lockAWT(); + try { + // ???AWT + /* + * if (dropTarget != null) { dropTarget.removeNotify(peer); } + */ + prepare4HierarchyChange(); + // /???AWT: moveFocus(); + behaviour.removeNotify(); + // ???AWT: finishHierarchyChange(this, parent, 0); + removeNotifyInputContext(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Calls InputContext.removeNotify. + */ + private void removeNotifyInputContext() { + if (!inputMethodsEnabled) { + return; + } + InputContext ic = getInputContext(); + if (ic != null) { + // ???AWT: ic.removeNotify(this); + } + } + + /** + * This method is called when some property of a component changes, making + * it unfocusable, e. g. hide(), removeNotify(), setEnabled(false), + * setFocusable(false) is called, and therefore automatic forward focus + * traversal is necessary + */ + // ???AWT + /* + * void moveFocus() { // don't use transferFocus(), but query focus + * traversal policy directly // and if it returns null, transfer focus up + * cycle // and find next focusable component there KeyboardFocusManager kfm + * = KeyboardFocusManager.getCurrentKeyboardFocusManager(); Container root = + * kfm.getCurrentFocusCycleRoot(); Component nextComp = this; boolean + * success = !isFocusOwner(); while (!success) { if (root != + * nextComp.getFocusCycleRootAncestor()) { // component was probably removed + * from container // so focus will be lost in some time return; } nextComp = + * root.getFocusTraversalPolicy().getComponentAfter(root, nextComp); if + * (nextComp == this) { nextComp = null; // avoid looping } if (nextComp != + * null) { success = nextComp.requestFocusInWindow(); } else { nextComp = + * root; root = root.getFocusCycleRootAncestor(); // if no acceptable + * component is found at all - clear global // focus owner if (root == null) + * { if (nextComp instanceof Window) { Window wnd = (Window) nextComp; + * wnd.setFocusOwner(null); wnd.setRequestedFocus(null); } + * kfm.clearGlobalFocusOwner(); return; } } } } + */ + + /** + * For Container there's a difference between moving focus when being made + * invisible or made unfocusable in some other way, because when container + * is made invisible, component still remains visible, i. e. its hide() or + * setVisible() is not called. + */ + void moveFocusOnHide() { + // ???AWT: moveFocus(); + } + + /** + * Removes the property change listener registered for this component. + * + * @param listener + * the PropertyChangeListener. + */ + public void removePropertyChangeListener(PropertyChangeListener listener) { + getPropertyChangeSupport().removePropertyChangeListener(listener); + } + + /** + * Removes the property change listener registered fot this component for + * the specified propertyy. + * + * @param propertyName + * the property name. + * @param listener + * the PropertyChangeListener. + */ + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + getPropertyChangeSupport().removePropertyChangeListener(propertyName, listener); + } + + /** + * Repaints the specified rectangle of this component within tm + * milliseconds. + * + * @param tm + * the time in milliseconds before updating. + * @param x + * the x coordinate of Rectangle. + * @param y + * the y coordinate of Rectangle. + * @param width + * the width of Rectangle. + * @param height + * the height of Rectangle. + */ + public void repaint(long tm, int x, int y, int width, int height) { + // ???AWT + /* + * toolkit.lockAWT(); try { if (width <= 0 || height <= 0 || + * (redrawManager == null) || !isShowing()) { return; } if (behaviour + * instanceof LWBehavior) { if (parent == null || !parent.visible || + * !parent.behaviour.isDisplayable()) { return; } if (repaintRegion == + * null) { repaintRegion = new MultiRectArea(new Rectangle(x, y, width, + * height)); } repaintRegion.intersect(new Rectangle(0, 0, this.w, + * this.h)); repaintRegion.translate(this.x, this.y); + * parent.repaintRegion = repaintRegion; repaintRegion = null; + * parent.repaint(tm, x + this.x, y + this.y, width, height); } else { + * if (repaintRegion != null) { redrawManager.addUpdateRegion(this, + * repaintRegion); repaintRegion = null; } else { + * redrawManager.addUpdateRegion(this, new Rectangle(x, y, width, + * height)); } + * toolkit.getSystemEventQueueCore().notifyEventMonitor(toolkit); } } + * finally { toolkit.unlockAWT(); } + */ + } + + /** + * Post event. + * + * @param e + * the e. + */ + void postEvent(AWTEvent e) { + getToolkit().getSystemEventQueueImpl().postEvent(e); + } + + /** + * Repaints the specified Rectangle of this Component. + * + * @param x + * the x coordinate of Rectangle. + * @param y + * the y coordinate of Rectangle. + * @param width + * the width of Rectangle. + * @param height + * the height of Rectangle. + */ + public void repaint(int x, int y, int width, int height) { + toolkit.lockAWT(); + try { + repaint(0, x, y, width, height); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Repaints this component. + */ + public void repaint() { + toolkit.lockAWT(); + try { + if (w > 0 && h > 0) { + repaint(0, 0, 0, w, h); + } + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Repaints the component within tm milliseconds. + * + * @param tm + * the time in milliseconds before updating. + */ + public void repaint(long tm) { + toolkit.lockAWT(); + try { + repaint(tm, 0, 0, w, h); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Requests that this Component get the input focus temporarily. This + * component must be displayable, visible, and focusable. + * + * @param temporary + * this parameter is true if the focus change is temporary, when + * the window loses the focus. + * @return true if the focus change request is succeeded, false otherwise. + */ + protected boolean requestFocus(boolean temporary) { + toolkit.lockAWT(); + try { + // ???AWT: return requestFocusImpl(temporary, true, false); + } finally { + toolkit.unlockAWT(); + } + // ???AWT + return false; + } + + /** + * Requests that this Component get the input focus. This component must be + * displayable, visible, and focusable. + */ + public void requestFocus() { + toolkit.lockAWT(); + try { + requestFocus(false); + } finally { + toolkit.unlockAWT(); + } + } + + // ???AWT + /* + * protected boolean requestFocusInWindow(boolean temporary) { + * toolkit.lockAWT(); try { Window wnd = getWindowAncestor(); if ((wnd == + * null) || !wnd.isFocused()) { return false; } return + * requestFocusImpl(temporary, false, false); } finally { + * toolkit.unlockAWT(); } } boolean requestFocusImpl(boolean temporary, + * boolean crossWindow, boolean rejectionRecovery) { if (!rejectionRecovery + * && isFocusOwner()) { return true; } Window wnd = getWindowAncestor(); + * Container par = getRealParent(); if ((par != null) && par.isRemoved) { + * return false; } if (!isShowing() || !isFocusable() || + * !wnd.isFocusableWindow()) { return false; } return + * KeyboardFocusManager.getCurrentKeyboardFocusManager().requestFocus(this, + * temporary, crossWindow, true); } public boolean requestFocusInWindow() { + * toolkit.lockAWT(); try { return requestFocusInWindow(false); } finally { + * toolkit.unlockAWT(); } } + */ + + /** + * Deprecated: replaced by setBounds(int, int, int, int) method. + * + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @param w + * the width. + * @param h + * the height. + * @deprecated Replaced by setBounds(int, int, int, int) method. + */ + @Deprecated + public void reshape(int x, int y, int w, int h) { + toolkit.lockAWT(); + try { + setBounds(x, y, w, h, boundsMaskParam, true); + boundsMaskParam = 0; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets rectangle for this Component to be the rectangle with the specified + * x,y coordinates of the top-left corner and the width and height. + * + * @param x + * the x coordinate of the rectangle's top-left corner. + * @param y + * the y coordinate of the rectangle's top-left corner. + * @param w + * the width of rectangle. + * @param h + * the height of rectangle. + */ + public void setBounds(int x, int y, int w, int h) { + toolkit.lockAWT(); + try { + reshape(x, y, w, h); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets rectangle for this Component to be the rectangle with the specified + * x,y coordinates of the top-left corner and the width and height and posts + * the appropriate events. + * + * @param x + * the x coordinate of the rectangle's top-left corner. + * @param y + * the y coordinate of the rectangle's top-left corner. + * @param w + * the width of rectangle. + * @param h + * the height of rectangle. + * @param bMask + * the bitmask of bounds options. + * @param updateBehavior + * the whether to update the behavoir's bounds as well. + */ + void setBounds(int x, int y, int w, int h, int bMask, boolean updateBehavior) { + int oldX = this.x; + int oldY = this.y; + int oldW = this.w; + int oldH = this.h; + setBoundsFields(x, y, w, h, bMask); + // Moved + if ((oldX != this.x) || (oldY != this.y)) { + // ???AWT: invalidateRealParent(); + postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_MOVED)); + spreadHierarchyBoundsEvents(this, HierarchyEvent.ANCESTOR_MOVED); + } + // Resized + if ((oldW != this.w) || (oldH != this.h)) { + invalidate(); + postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_RESIZED)); + spreadHierarchyBoundsEvents(this, HierarchyEvent.ANCESTOR_RESIZED); + } + if (updateBehavior) { + behaviour.setBounds(this.x, this.y, this.w, this.h, bMask); + } + notifyInputMethod(new Rectangle(x, y, w, h)); + } + + /** + * Calls InputContextImpl.notifyClientWindowChanged. + * + * @param bounds + * the bounds. + */ + void notifyInputMethod(Rectangle bounds) { + // only Window actually notifies IM of bounds change + } + + /** + * Sets the bounds fields. + * + * @param x + * the x. + * @param y + * the y. + * @param w + * the w. + * @param h + * the h. + * @param bMask + * the b mask. + */ + private void setBoundsFields(int x, int y, int w, int h, int bMask) { + if ((bMask & NativeWindow.BOUNDS_NOSIZE) == 0) { + this.w = w; + this.h = h; + } + if ((bMask & NativeWindow.BOUNDS_NOMOVE) == 0) { + this.x = x; + this.y = y; + } + } + + /** + * Gets the native insets. + * + * @return the native insets. + */ + Insets getNativeInsets() { + return new Insets(0, 0, 0, 0); + } + + /** + * Gets the insets. + * + * @return the insets. + */ + Insets getInsets() { + return new Insets(0, 0, 0, 0); + } + + /** + * Checks if is mouse exited expected. + * + * @return true, if is mouse exited expected. + */ + boolean isMouseExitedExpected() { + return mouseExitedExpected; + } + + /** + * Sets the mouse exited expected. + * + * @param expected + * the new mouse exited expected. + */ + void setMouseExitedExpected(boolean expected) { + mouseExitedExpected = expected; + } + + /** + * Sets the new bounding rectangle for this Component. + * + * @param r + * the new bounding rectangle. + */ + public void setBounds(Rectangle r) { + toolkit.lockAWT(); + try { + setBounds(r.x, r.y, r.width, r.height); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the component orientation which affects the component's elements and + * text within this component. + * + * @param o + * the ComponentOrientation object. + */ + public void setComponentOrientation(ComponentOrientation o) { + ComponentOrientation oldOrientation; + toolkit.lockAWT(); + try { + oldOrientation = orientation; + orientation = o; + } finally { + toolkit.unlockAWT(); + } + firePropertyChange("componentOrientation", oldOrientation, orientation); //$NON-NLS-1$ + invalidate(); + } + + /** + * Sets the specified cursor for this Component. + * + * @param cursor + * the new Cursor. + */ + public void setCursor(Cursor cursor) { + toolkit.lockAWT(); + try { + this.cursor = cursor; + setCursor(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Set current cursor shape to Component's Cursor. + */ + void setCursor() { + if (isDisplayable() && isShowing()) { + Rectangle absRect = new Rectangle(getLocationOnScreen(), getSize()); + Point absPointerPos = toolkit.dispatcher.mouseDispatcher.getPointerPos(); + // ???AWT + /* + * if (absRect.contains(absPointerPos)) { // set Cursor only on + * top-level Windows(on X11) Window topLevelWnd = + * getWindowAncestor(); if (topLevelWnd != null) { Point pointerPos + * = MouseDispatcher.convertPoint(null, absPointerPos, topLevelWnd); + * Component compUnderCursor = + * topLevelWnd.findComponentAt(pointerPos); // if (compUnderCursor + * == this || // compUnderCursor.getCursorAncestor() == this) { + * NativeWindow wnd = topLevelWnd.getNativeWindow(); if + * (compUnderCursor != null && wnd != null) { + * compUnderCursor.getRealCursor().getNativeCursor() + * .setCursor(wnd.getId()); } // } } } + */ + } + } + + /** + * Gets the ancestor Cursor if Component is disabled (directly or via an + * ancestor) even if Cursor is explicitly set. + * + * @param value + * the value. + * @return the actual Cursor to be displayed. + */ + // ???AWT + /* + * Cursor getRealCursor() { Component cursorAncestor = getCursorAncestor(); + * return cursorAncestor != null ? cursorAncestor.getCursor() : + * Cursor.getDefaultCursor(); } + */ + + /** + * Gets the ancestor(or component itself) whose cursor is set when pointer + * is inside component + * + * @return the actual Cursor to be displayed. + */ + // ???AWT + /* + * Component getCursorAncestor() { Component comp; for (comp = this; comp != + * null; comp = comp.getParent()) { if (comp instanceof Window || + * comp.isCursorSet() && comp.isKeyEnabled()) { return comp; } } return + * null; } public void setDropTarget(DropTarget dt) { toolkit.lockAWT(); try + * { if (dropTarget == dt) { return; } DropTarget oldDropTarget = + * dropTarget; dropTarget = dt; if (oldDropTarget != null) { if + * (behaviour.isDisplayable()) { oldDropTarget.removeNotify(peer); } + * oldDropTarget.setComponent(null); } if (dt != null) { + * dt.setComponent(this); if (behaviour.isDisplayable()) { + * dt.addNotify(peer); } } } finally { toolkit.unlockAWT(); } } + */ + + /** + * Sets this component to the "enabled" or "disabled" state depending on the + * specified boolean parameter. + * + * @param value + * true if this component should be enabled; false if this + * component should be disabled. + */ + public void setEnabled(boolean value) { + toolkit.lockAWT(); + try { + enable(value); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the enabled impl. + * + * @param value + * the new enabled impl. + */ + void setEnabledImpl(boolean value) { + if (enabled != value) { + enabled = value; + setCursor(); + if (!enabled) { + moveFocusOnHide(); + } + behaviour.setEnabled(value); + } + } + + // ???AWT + /* + * private void fireAccessibleStateChange(AccessibleState state, boolean + * value) { if (behaviour.isLightweight()) { return; } AccessibleContext ac + * = getAccessibleContext(); if (ac != null) { AccessibleState oldValue = + * null; AccessibleState newValue = null; if (value) { newValue = state; } + * else { oldValue = state; } + * ac.firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, + * oldValue, newValue); } } + */ + + // ???AWT + /* + * public void setFocusTraversalKeys(int id, Set<? extends AWTKeyStroke> + * keystrokes) { Set<? extends AWTKeyStroke> oldTraversalKeys; String + * propName = "FocusTraversalKeys"; //$NON-NLS-1$ toolkit.lockAWT(); try { + * Integer kId = new Integer(id); + * KeyboardFocusManager.checkTraversalKeysID(traversalKeys, kId); + * Map<Integer, Set<? extends AWTKeyStroke>> keys = new HashMap<Integer, + * Set<? extends AWTKeyStroke>>(); for (int kid : traversalIDs) { Integer + * key = new Integer(kid); keys.put(key, getFocusTraversalKeys(kid)); } + * KeyboardFocusManager.checkKeyStrokes(traversalIDs, keys, kId, + * keystrokes); oldTraversalKeys = traversalKeys.get(new Integer(id)); // + * put a copy of keystrokes object into map: Set<? extends AWTKeyStroke> + * newKeys = keystrokes; if (keystrokes != null) { newKeys = new + * HashSet<AWTKeyStroke>(keystrokes); } traversalKeys.put(kId, newKeys); + * String direction = ""; //$NON-NLS-1$ switch (id) { case + * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS: direction = "forward"; + * //$NON-NLS-1$ break; case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS: + * direction = "backward"; //$NON-NLS-1$ break; case + * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS: direction = "upCycle"; + * //$NON-NLS-1$ break; case KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS: + * direction = "downCycle"; //$NON-NLS-1$ break; } propName = direction + + * propName; } finally { toolkit.unlockAWT(); } firePropertyChange(propName, + * oldTraversalKeys, keystrokes); } + */ + + /** + * Sets the focus traversal keys state for this component. + * + * @param value + * true if the focus traversal keys state is enabled, false if + * the focus traversal keys state is disabled. + */ + public void setFocusTraversalKeysEnabled(boolean value) { + boolean oldFocusTraversalKeysEnabled; + toolkit.lockAWT(); + try { + oldFocusTraversalKeysEnabled = focusTraversalKeysEnabled; + focusTraversalKeysEnabled = value; + } finally { + toolkit.unlockAWT(); + } + firePropertyChange("focusTraversalKeysEnabled", oldFocusTraversalKeysEnabled, //$NON-NLS-1$ + focusTraversalKeysEnabled); + } + + // ???AWT + /* + * public void setFocusable(boolean focusable) { boolean oldFocusable; + * toolkit.lockAWT(); try { calledSetFocusable = true; oldFocusable = + * this.focusable; this.focusable = focusable; if (!focusable) { + * moveFocus(); } } finally { toolkit.unlockAWT(); } + * firePropertyChange("focusable", oldFocusable, focusable); //$NON-NLS-1$ } + * public Font getFont() { toolkit.lockAWT(); try { return (font == null) && + * (parent != null) ? parent.getFont() : font; } finally { + * toolkit.unlockAWT(); } } + */ + + /** + * Sets the font for this Component. + * + * @param f + * the new font of the Component. + */ + public void setFont(Font f) { + Font oldFont; + toolkit.lockAWT(); + try { + oldFont = font; + setFontImpl(f); + } finally { + toolkit.unlockAWT(); + } + firePropertyChange("font", oldFont, font); //$NON-NLS-1$ + } + + /** + * Sets the font impl. + * + * @param f + * the new font impl. + */ + void setFontImpl(Font f) { + font = f; + invalidate(); + if (isShowing()) { + repaint(); + } + } + + /** + * Invalidate the component if it inherits the font from the parent. This + * method is overridden in Container. + * + * @return true if the component was invalidated, false otherwise. + */ + boolean propagateFont() { + if (font == null) { + invalidate(); + return true; + } + return false; + } + + /** + * Sets the foreground color for this Component. + * + * @param c + * the new foreground color. + */ + public void setForeground(Color c) { + Color oldFgColor; + toolkit.lockAWT(); + try { + oldFgColor = foreColor; + foreColor = c; + } finally { + toolkit.unlockAWT(); + } + firePropertyChange("foreground", oldFgColor, foreColor); //$NON-NLS-1$ + repaint(); + } + + /** + * Sets the background color for the Component. + * + * @param c + * the new background color for this component. + */ + public void setBackground(Color c) { + Color oldBkColor; + toolkit.lockAWT(); + try { + oldBkColor = backColor; + backColor = c; + } finally { + toolkit.unlockAWT(); + } + firePropertyChange("background", oldBkColor, backColor); //$NON-NLS-1$ + repaint(); + } + + /** + * Sets the flag for whether paint messages received from the operating + * system should be ignored or not. + * + * @param value + * true if paint messages received from the operating system + * should be ignored, false otherwise. + */ + public void setIgnoreRepaint(boolean value) { + toolkit.lockAWT(); + try { + ignoreRepaint = value; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the locale of the component. + * + * @param locale + * the new Locale. + */ + public void setLocale(Locale locale) { + Locale oldLocale; + toolkit.lockAWT(); + try { + oldLocale = this.locale; + this.locale = locale; + } finally { + toolkit.unlockAWT(); + } + firePropertyChange("locale", oldLocale, locale); //$NON-NLS-1$ + } + + /** + * Sets the location of the Component to the specified point. + * + * @param p + * the new location of the Component. + */ + public void setLocation(Point p) { + toolkit.lockAWT(); + try { + setLocation(p.x, p.y); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the location of the Component to the specified x, y coordinates. + * + * @param x + * the x coordinate. + * @param y + * the y coordinate. + */ + public void setLocation(int x, int y) { + toolkit.lockAWT(); + try { + move(x, y); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the visibility state of the component. + * + * @param b + * true if the component is visible, false if the component is + * not shown. + */ + public void setVisible(boolean b) { + // show() & hide() are not deprecated for Window, + // so have to call them from setVisible() + show(b); + } + + /** + * Deprecated: replaced by setVisible(boolean) method. + * + * @deprecated Replaced by setVisible(boolean) method. + */ + @Deprecated + public void show() { + toolkit.lockAWT(); + try { + if (visible) { + return; + } + prepare4HierarchyChange(); + mapToDisplay(true); + validate(); + visible = true; + behaviour.setVisible(true); + postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_SHOWN)); + // ???AWT: finishHierarchyChange(this, parent, 0); + notifyInputMethod(new Rectangle(x, y, w, h)); + // ???AWT: invalidateRealParent(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Deprecated: replaced by setVisible(boolean) method. + * + * @param b + * the visibility's state. + * @deprecated Replaced by setVisible(boolean) method. + */ + @Deprecated + public void show(boolean b) { + if (b) { + show(); + } else { + hide(); + } + } + + // ???AWT + /* + * void transferFocus(int dir) { Container root = null; if (this instanceof + * Container) { Container cont = (Container) this; if + * (cont.isFocusCycleRoot()) { root = cont.getFocusTraversalRoot(); } } if + * (root == null) { root = getFocusCycleRootAncestor(); } // transfer focus + * up cycle if root is unreachable Component comp = this; while ((root != + * null) && !(root.isFocusCycleRoot() && root.isShowing() && + * root.isEnabled() && root .isFocusable())) { comp = root; root = + * root.getFocusCycleRootAncestor(); } if (root == null) { return; } + * FocusTraversalPolicy policy = root.getFocusTraversalPolicy(); Component + * nextComp = null; switch (dir) { case + * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS: nextComp = + * policy.getComponentAfter(root, comp); break; case + * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS: nextComp = + * policy.getComponentBefore(root, comp); break; } if (nextComp != null) { + * nextComp.requestFocus(false); } } public void transferFocus() { + * toolkit.lockAWT(); try { nextFocus(); } finally { toolkit.unlockAWT(); } + * } public void transferFocusBackward() { toolkit.lockAWT(); try { + * transferFocus(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); } finally { + * toolkit.unlockAWT(); } } public void transferFocusUpCycle() { + * toolkit.lockAWT(); try { KeyboardFocusManager kfm = + * KeyboardFocusManager.getCurrentKeyboardFocusManager(); Container root = + * kfm.getCurrentFocusCycleRoot(); if(root == null) { return; } boolean + * success = false; Component nextComp = null; Container newRoot = root; do + * { nextComp = newRoot instanceof Window ? + * newRoot.getFocusTraversalPolicy() .getDefaultComponent(newRoot) : + * newRoot; newRoot = newRoot.getFocusCycleRootAncestor(); if (nextComp == + * null) { break; } success = nextComp.requestFocusInWindow(); if (newRoot + * == null) { break; } kfm.setGlobalCurrentFocusCycleRoot(newRoot); } while + * (!success); if (!success && root != newRoot) { + * kfm.setGlobalCurrentFocusCycleRoot(root); } } finally { + * toolkit.unlockAWT(); } } + */ + + /** + * Validates that this component has a valid layout. + */ + public void validate() { + toolkit.lockAWT(); + try { + if (!behaviour.isDisplayable()) { + return; + } + validateImpl(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Validate impl. + */ + void validateImpl() { + valid = true; + } + + /** + * Gets the native window. + * + * @return the native window. + */ + NativeWindow getNativeWindow() { + return behaviour.getNativeWindow(); + } + + /** + * Checks whether or not a maximum size is set for the Component. + * + * @return true, if the maximum size is set for the Component, false + * otherwise. + */ + public boolean isMaximumSizeSet() { + toolkit.lockAWT(); + try { + return maximumSize != null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not the minimum size is set for the component. + * + * @return true, if the minimum size is set for the component, false + * otherwise. + */ + public boolean isMinimumSizeSet() { + toolkit.lockAWT(); + try { + return minimumSize != null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not the preferred size is set for the Component. + * + * @return true, if the preferred size is set for the Component, false + * otherwise. + */ + public boolean isPreferredSizeSet() { + toolkit.lockAWT(); + try { + return preferredSize != null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the maximum size of the Component. + * + * @return the maximum size of the Component. + */ + public Dimension getMaximumSize() { + toolkit.lockAWT(); + try { + return isMaximumSizeSet() ? new Dimension(maximumSize) : new Dimension(Short.MAX_VALUE, + Short.MAX_VALUE); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the minimum size of the Component. + * + * @return the minimum size of the Component. + */ + public Dimension getMinimumSize() { + toolkit.lockAWT(); + try { + return minimumSize(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Deprecated: replaced by getMinimumSize() method. + * + * @return the Dimension. + * @deprecated Replaced by getMinimumSize() method. + */ + @Deprecated + public Dimension minimumSize() { + toolkit.lockAWT(); + try { + if (isMinimumSizeSet()) { + return (Dimension)minimumSize.clone(); + } + Dimension defSize = getDefaultMinimumSize(); + if (defSize != null) { + return (Dimension)defSize.clone(); + } + return isDisplayable() ? new Dimension(1, 1) : new Dimension(w, h); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the preferred size of the Component. + * + * @return the preferred size of the Component. + */ + public Dimension getPreferredSize() { + toolkit.lockAWT(); + try { + return preferredSize(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Deprecated: replaced by getPreferredSize() method. + * + * @return the Dimension. + * @deprecated Replaced by getPreferredSize() method. + */ + @Deprecated + public Dimension preferredSize() { + toolkit.lockAWT(); + try { + if (isPreferredSizeSet()) { + return new Dimension(preferredSize); + } + Dimension defSize = getDefaultPreferredSize(); + if (defSize != null) { + return new Dimension(defSize); + } + return new Dimension(getMinimumSize()); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the maximum size of the Component. + * + * @param maximumSize + * the new maximum size of the Component. + */ + public void setMaximumSize(Dimension maximumSize) { + Dimension oldMaximumSize; + toolkit.lockAWT(); + try { + oldMaximumSize = this.maximumSize; + if (oldMaximumSize != null) { + oldMaximumSize = oldMaximumSize.getSize(); + } + if (this.maximumSize == null) { + if (maximumSize != null) { + this.maximumSize = new Dimension(maximumSize); + } + } else { + if (maximumSize != null) { + this.maximumSize.setSize(maximumSize); + } else { + this.maximumSize = null; + } + } + } finally { + toolkit.unlockAWT(); + } + firePropertyChange("maximumSize", oldMaximumSize, this.maximumSize); //$NON-NLS-1$ + toolkit.lockAWT(); + try { + // ???AWT: invalidateRealParent(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the minimum size of the Component. + * + * @param minimumSize + * the new minimum size of the Component. + */ + public void setMinimumSize(Dimension minimumSize) { + Dimension oldMinimumSize; + toolkit.lockAWT(); + try { + oldMinimumSize = this.minimumSize; + if (oldMinimumSize != null) { + oldMinimumSize = oldMinimumSize.getSize(); + } + if (this.minimumSize == null) { + if (minimumSize != null) { + this.minimumSize = new Dimension(minimumSize); + } + } else { + if (minimumSize != null) { + this.minimumSize.setSize(minimumSize); + } else { + this.minimumSize = null; + } + } + } finally { + toolkit.unlockAWT(); + } + firePropertyChange("minimumSize", oldMinimumSize, this.minimumSize); //$NON-NLS-1$ + toolkit.lockAWT(); + try { + // ???AWT: invalidateRealParent(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the preferred size of the Component. + * + * @param preferredSize + * the new preferred size of the Component. + */ + public void setPreferredSize(Dimension preferredSize) { + Dimension oldPreferredSize; + toolkit.lockAWT(); + try { + oldPreferredSize = this.preferredSize; + if (oldPreferredSize != null) { + oldPreferredSize = oldPreferredSize.getSize(); + } + if (this.preferredSize == null) { + if (preferredSize != null) { + this.preferredSize = new Dimension(preferredSize); + } + } else { + if (preferredSize != null) { + this.preferredSize.setSize(preferredSize); + } else { + this.preferredSize = null; + } + } + } finally { + toolkit.unlockAWT(); + } + firePropertyChange("preferredSize", oldPreferredSize, this.preferredSize); //$NON-NLS-1$ + toolkit.lockAWT(); + try { + // ???AWT: invalidateRealParent(); + } finally { + toolkit.unlockAWT(); + } + } + + // ???AWT + /* + * RedrawManager getRedrawManager() { if (parent == null) { return null; } + * return parent.getRedrawManager(); } + */ + + /** + * Checks if is focusability explicitly set. + * + * @return true if component has a focusable peer. + */ + // ???AWT + /* + * boolean isPeerFocusable() { // The recommendations for Windows and Unix + * are that // Canvases, Labels, Panels, Scrollbars, ScrollPanes, Windows, + * // and lightweight Components have non-focusable peers, // and all other + * Components have focusable peers. if (this instanceof Canvas || this + * instanceof Label || this instanceof Panel || this instanceof Scrollbar || + * this instanceof ScrollPane || this instanceof Window || isLightweight()) + * { return false; } return true; } + */ + + /** + * @return true if focusability was explicitly set via a call to + * setFocusable() or via overriding isFocusable() or + * isFocusTraversable(). + */ + boolean isFocusabilityExplicitlySet() { + return calledSetFocusable || overridenIsFocusable; + } + + /** + * Paints the component and all of its subcomponents. + * + * @param g + * the Graphics to be used for painting. + */ + public void paintAll(Graphics g) { + toolkit.lockAWT(); + try { + paint(g); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Updates this Component. + * + * @param g + * the Graphics to be used for updating. + */ + public void update(Graphics g) { + toolkit.lockAWT(); + try { + if (!isLightweight() && !isPrepainter()) { + g.setColor(getBackground()); + g.fillRect(0, 0, w, h); + g.setColor(getForeground()); + } + paint(g); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Paints this component. + * + * @param g + * the Graphics to be used for painting. + */ + public void paint(Graphics g) { + toolkit.lockAWT(); + try { + // Just to nothing + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Prepares the component to be painted. + * + * @param g + * the Graphics to be used for painting. + */ + void prepaint(Graphics g) { + // Just to nothing. For overriding. + } + + /** + * Checks if is prepainter. + * + * @return true, if is prepainter. + */ + boolean isPrepainter() { + return false; + } + + /** + * Prepare4 hierarchy change. + */ + void prepare4HierarchyChange() { + if (hierarchyChangingCounter++ == 0) { + wasShowing = isShowing(); + wasDisplayable = isDisplayable(); + prepareChildren4HierarchyChange(); + } + } + + /** + * Prepare children4 hierarchy change. + */ + void prepareChildren4HierarchyChange() { + // To be inherited by Container + } + + // ???AWT + /* + * void finishHierarchyChange(Component changed, Container changedParent, + * int ancestorFlags) { if (--hierarchyChangingCounter == 0) { int + * changeFlags = ancestorFlags; if (wasShowing != isShowing()) { changeFlags + * |= HierarchyEvent.SHOWING_CHANGED; } if (wasDisplayable != + * isDisplayable()) { changeFlags |= HierarchyEvent.DISPLAYABILITY_CHANGED; + * } if (changeFlags > 0) { postEvent(new HierarchyEvent(this, + * HierarchyEvent.HIERARCHY_CHANGED, changed, changedParent, changeFlags)); + * } finishChildrenHierarchyChange(changed, changedParent, ancestorFlags); } + * } void finishChildrenHierarchyChange(Component changed, Container + * changedParent, int ancestorFlags) { // To be inherited by Container } + * void postHierarchyBoundsEvents(Component changed, int id) { postEvent(new + * HierarchyEvent(this, id, changed, null, 0)); } + */ + + /** + * Spread hierarchy bounds events. + * + * @param changed + * the changed. + * @param id + * the id. + */ + void spreadHierarchyBoundsEvents(Component changed, int id) { + // To be inherited by Container + } + + /** + * Dispatches an event to this component. + * + * @param e + * the Event. + */ + public final void dispatchEvent(AWTEvent e) { + // ???AWT + /* + * if (e.isConsumed()) { return; } if (e instanceof PaintEvent) { + * toolkit.dispatchAWTEvent(e); processPaintEvent((PaintEvent) e); + * return; } KeyboardFocusManager kfm = + * KeyboardFocusManager.getCurrentKeyboardFocusManager(); if + * (!e.dispatchedByKFM && kfm.dispatchEvent(e)) { return; } if (e + * instanceof KeyEvent) { KeyEvent ke = (KeyEvent) e; // consumes + * KeyEvent which represents a focus traversal key if + * (getFocusTraversalKeysEnabled()) { kfm.processKeyEvent(this, ke); if + * (ke.isConsumed()) { return; } } } if (inputMethodsEnabled && + * dispatchToIM && e.isPosted && dispatchEventToIM(e)) { return; } if + * (e.getID() == WindowEvent.WINDOW_ICONIFIED) { + * notifyInputMethod(null); } AWTEvent.EventDescriptor descriptor = + * toolkit.eventTypeLookup.getEventDescriptor(e); + * toolkit.dispatchAWTEvent(e); if (descriptor != null) { if + * (isEventEnabled(descriptor.eventMask) || + * (getListeners(descriptor.listenerType).length > 0)) { + * processEvent(e); } // input events can be consumed by user listeners: + * if (!e.isConsumed() && ((enabledAWTEvents & descriptor.eventMask) != + * 0)) { postprocessEvent(e, descriptor.eventMask); } } + * postDeprecatedEvent(e); + */ + } + + /** + * Post deprecated event. + * + * @param e + * the e. + */ + private void postDeprecatedEvent(AWTEvent e) { + if (deprecatedEventHandler) { + Event evt = e.getEvent(); + if (evt != null) { + postEvent(evt); + } + } + } + + /** + * Postprocess event. + * + * @param e + * the e. + * @param eventMask + * the event mask. + */ + void postprocessEvent(AWTEvent e, long eventMask) { + toolkit.lockAWT(); + try { + // call system listeners under AWT lock + if (eventMask == AWTEvent.FOCUS_EVENT_MASK) { + preprocessFocusEvent((FocusEvent)e); + } else if (eventMask == AWTEvent.KEY_EVENT_MASK) { + preprocessKeyEvent((KeyEvent)e); + } else if (eventMask == AWTEvent.MOUSE_EVENT_MASK) { + preprocessMouseEvent((MouseEvent)e); + } else if (eventMask == AWTEvent.MOUSE_MOTION_EVENT_MASK) { + preprocessMouseMotionEvent((MouseEvent)e); + } else if (eventMask == AWTEvent.COMPONENT_EVENT_MASK) { + preprocessComponentEvent((ComponentEvent)e); + } else if (eventMask == AWTEvent.MOUSE_WHEEL_EVENT_MASK) { + preprocessMouseWheelEvent((MouseWheelEvent)e); + } else if (eventMask == AWTEvent.INPUT_METHOD_EVENT_MASK) { + preprocessInputMethodEvent((InputMethodEvent)e); + } + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Preprocess input method event. + * + * @param e + * the e. + */ + private void preprocessInputMethodEvent(InputMethodEvent e) { + processInputMethodEventImpl(e, inputMethodListeners.getSystemListeners()); + } + + /** + * Preprocess mouse wheel event. + * + * @param e + * the e. + */ + private void preprocessMouseWheelEvent(MouseWheelEvent e) { + processMouseWheelEventImpl(e, mouseWheelListeners.getSystemListeners()); + } + + /** + * Process mouse wheel event impl. + * + * @param e + * the e. + * @param c + * the c. + */ + private void processMouseWheelEventImpl(MouseWheelEvent e, Collection<MouseWheelListener> c) { + for (MouseWheelListener listener : c) { + switch (e.getID()) { + case MouseEvent.MOUSE_WHEEL: + listener.mouseWheelMoved(e); + break; + } + } + } + + /** + * Preprocess component event. + * + * @param e + * the e. + */ + private void preprocessComponentEvent(ComponentEvent e) { + processComponentEventImpl(e, componentListeners.getSystemListeners()); + } + + /** + * Preprocess mouse motion event. + * + * @param e + * the e. + */ + void preprocessMouseMotionEvent(MouseEvent e) { + processMouseMotionEventImpl(e, mouseMotionListeners.getSystemListeners()); + } + + /** + * Preprocess mouse event. + * + * @param e + * the e + */ + void preprocessMouseEvent(MouseEvent e) { + processMouseEventImpl(e, mouseListeners.getSystemListeners()); + } + + /** + * Preprocess key event. + * + * @param e + * the e. + */ + void preprocessKeyEvent(KeyEvent e) { + processKeyEventImpl(e, keyListeners.getSystemListeners()); + } + + /** + * Preprocess focus event. + * + * @param e + * the e. + */ + void preprocessFocusEvent(FocusEvent e) { + processFocusEventImpl(e, focusListeners.getSystemListeners()); + } + + /** + * Processes AWTEvent occurred on this component. + * + * @param e + * the AWTEvent. + */ + protected void processEvent(AWTEvent e) { + long eventMask = toolkit.eventTypeLookup.getEventMask(e); + if (eventMask == AWTEvent.COMPONENT_EVENT_MASK) { + processComponentEvent((ComponentEvent)e); + } else if (eventMask == AWTEvent.FOCUS_EVENT_MASK) { + processFocusEvent((FocusEvent)e); + } else if (eventMask == AWTEvent.KEY_EVENT_MASK) { + processKeyEvent((KeyEvent)e); + } else if (eventMask == AWTEvent.MOUSE_EVENT_MASK) { + processMouseEvent((MouseEvent)e); + } else if (eventMask == AWTEvent.MOUSE_WHEEL_EVENT_MASK) { + processMouseWheelEvent((MouseWheelEvent)e); + } else if (eventMask == AWTEvent.MOUSE_MOTION_EVENT_MASK) { + processMouseMotionEvent((MouseEvent)e); + } else if (eventMask == AWTEvent.HIERARCHY_EVENT_MASK) { + processHierarchyEvent((HierarchyEvent)e); + } else if (eventMask == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) { + processHierarchyBoundsEvent((HierarchyEvent)e); + } else if (eventMask == AWTEvent.INPUT_METHOD_EVENT_MASK) { + processInputMethodEvent((InputMethodEvent)e); + } + } + + /** + * Gets an array of all listener's objects based on the specified listener + * type and registered to this Component. + * + * @param listenerType + * the listener type. + * @return an array of all listener's objects based on the specified + * listener type and registered to this Component. + */ + @SuppressWarnings("unchecked") + public <T extends EventListener> T[] getListeners(Class<T> listenerType) { + if (ComponentListener.class.isAssignableFrom(listenerType)) { + return (T[])getComponentListeners(); + } else if (FocusListener.class.isAssignableFrom(listenerType)) { + return (T[])getFocusListeners(); + } else if (HierarchyBoundsListener.class.isAssignableFrom(listenerType)) { + return (T[])getHierarchyBoundsListeners(); + } else if (HierarchyListener.class.isAssignableFrom(listenerType)) { + return (T[])getHierarchyListeners(); + } else if (InputMethodListener.class.isAssignableFrom(listenerType)) { + return (T[])getInputMethodListeners(); + } else if (KeyListener.class.isAssignableFrom(listenerType)) { + return (T[])getKeyListeners(); + } else if (MouseWheelListener.class.isAssignableFrom(listenerType)) { + return (T[])getMouseWheelListeners(); + } else if (MouseMotionListener.class.isAssignableFrom(listenerType)) { + return (T[])getMouseMotionListeners(); + } else if (MouseListener.class.isAssignableFrom(listenerType)) { + return (T[])getMouseListeners(); + } else if (PropertyChangeListener.class.isAssignableFrom(listenerType)) { + return (T[])getPropertyChangeListeners(); + } + return (T[])Array.newInstance(listenerType, 0); + } + + /** + * Process paint event. + * + * @param event + * the event. + */ + private void processPaintEvent(PaintEvent event) { + if (redrawManager == null) { + return; + } + Rectangle clipRect = event.getUpdateRect(); + if ((clipRect.width <= 0) || (clipRect.height <= 0)) { + return; + } + Graphics g = getGraphics(); + if (g == null) { + return; + } + initGraphics(g, event); + if (!getIgnoreRepaint()) { + if (event.getID() == PaintEvent.PAINT) { + paint(g); + } else { + update(g); + } + } + g.dispose(); + } + + /** + * Inits the graphics. + * + * @param g + * the g. + * @param e + * the e. + */ + void initGraphics(Graphics g, PaintEvent e) { + Rectangle clip = e.getUpdateRect(); + if (clip instanceof ClipRegion) { + g.setClip(((ClipRegion)clip).getClip()); + } else { + g.setClip(clip); + } + if (isPrepainter()) { + prepaint(g); + } else if (!isLightweight() && (e.getID() == PaintEvent.PAINT)) { + g.setColor(getBackground()); + g.fillRect(0, 0, w, h); + } + g.setFont(getFont()); + g.setColor(getForeground()); + } + + /** + * Enables the events with the specified event mask to be delivered to this + * component. + * + * @param eventsToEnable + * the events mask which specifies the types of events to enable. + */ + protected final void enableEvents(long eventsToEnable) { + toolkit.lockAWT(); + try { + enabledEvents |= eventsToEnable; + deprecatedEventHandler = false; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Enable awt events. + * + * @param eventsToEnable + * the events to enable. + */ + private void enableAWTEvents(long eventsToEnable) { + enabledAWTEvents |= eventsToEnable; + } + + /** + * Disables the events with types specified by the specified event mask from + * being delivered to this component. + * + * @param eventsToDisable + * the event mask specifying the event types. + */ + protected final void disableEvents(long eventsToDisable) { + toolkit.lockAWT(); + try { + enabledEvents &= ~eventsToDisable; + } finally { + toolkit.unlockAWT(); + } + } + + /* + * For use in MouseDispatcher only. Really it checks not only mouse events. + */ + /** + * Checks if is mouse event enabled. + * + * @param eventMask + * the event mask. + * @return true, if is mouse event enabled. + */ + boolean isMouseEventEnabled(long eventMask) { + return (isEventEnabled(eventMask) || (enabledAWTEvents & eventMask) != 0); + } + + /** + * Checks if is event enabled. + * + * @param eventMask + * the event mask. + * @return true, if is event enabled. + */ + boolean isEventEnabled(long eventMask) { + return ((enabledEvents & eventMask) != 0); + } + + /** + * Enables or disables input method support for this component. + * + * @param enable + * true to enable input method support, false to disable it. + */ + public void enableInputMethods(boolean enable) { + toolkit.lockAWT(); + try { + if (!enable) { + removeNotifyInputContext(); + } + inputMethodsEnabled = enable; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets an array of all component's listeners registered for this component. + * + * @return an array of all component's listeners registered for this + * component. + */ + public ComponentListener[] getComponentListeners() { + return componentListeners.getUserListeners(new ComponentListener[0]); + } + + /** + * Adds the specified component listener to the Component for receiving + * component's event. + * + * @param l + * the ComponentListener. + */ + public void addComponentListener(ComponentListener l) { + componentListeners.addUserListener(l); + } + + /** + * Removes the component listener registered for this Component. + * + * @param l + * the ComponentListener. + */ + public void removeComponentListener(ComponentListener l) { + componentListeners.removeUserListener(l); + } + + /** + * Processes a component event that has occurred on this component by + * dispatching them to any registered ComponentListener objects. + * + * @param e + * the ComponentEvent. + */ + protected void processComponentEvent(ComponentEvent e) { + processComponentEventImpl(e, componentListeners.getUserListeners()); + } + + /** + * Process component event impl. + * + * @param e + * the e. + * @param c + * the c. + */ + private void processComponentEventImpl(ComponentEvent e, Collection<ComponentListener> c) { + for (ComponentListener listener : c) { + switch (e.getID()) { + case ComponentEvent.COMPONENT_HIDDEN: + listener.componentHidden(e); + break; + case ComponentEvent.COMPONENT_MOVED: + listener.componentMoved(e); + break; + case ComponentEvent.COMPONENT_RESIZED: + listener.componentResized(e); + break; + case ComponentEvent.COMPONENT_SHOWN: + listener.componentShown(e); + break; + } + } + } + + /** + * Gets an array of focus listeners registered for this Component. + * + * @return the array of focus listeners registered for this Component. + */ + public FocusListener[] getFocusListeners() { + return focusListeners.getUserListeners(new FocusListener[0]); + } + + /** + * Adds the specified focus listener to the Component for receiving focus + * events. + * + * @param l + * the FocusListener. + */ + public void addFocusListener(FocusListener l) { + focusListeners.addUserListener(l); + } + + /** + * Adds the awt focus listener. + * + * @param l + * the l. + */ + void addAWTFocusListener(FocusListener l) { + enableAWTEvents(AWTEvent.FOCUS_EVENT_MASK); + focusListeners.addSystemListener(l); + } + + /** + * Removes the focus listener registered for this Component. + * + * @param l + * the FocusListener. + */ + public void removeFocusListener(FocusListener l) { + focusListeners.removeUserListener(l); + } + + /** + * Processes a FocusEvent that has occurred on this component by dispatching + * it to the registered listeners. + * + * @param e + * the FocusEvent. + */ + protected void processFocusEvent(FocusEvent e) { + processFocusEventImpl(e, focusListeners.getUserListeners()); + } + + /** + * Process focus event impl. + * + * @param e + * the e. + * @param c + * the c. + */ + private void processFocusEventImpl(FocusEvent e, Collection<FocusListener> c) { + for (FocusListener listener : c) { + switch (e.getID()) { + case FocusEvent.FOCUS_GAINED: + listener.focusGained(e); + break; + case FocusEvent.FOCUS_LOST: + listener.focusLost(e); + break; + } + } + } + + /** + * Gets an array of registered HierarchyListeners for this Component. + * + * @return an array of registered HierarchyListeners for this Component. + */ + public HierarchyListener[] getHierarchyListeners() { + return hierarchyListeners.getUserListeners(new HierarchyListener[0]); + } + + /** + * Adds the specified hierarchy listener. + * + * @param l + * the HierarchyListener. + */ + public void addHierarchyListener(HierarchyListener l) { + hierarchyListeners.addUserListener(l); + } + + /** + * Removes the hierarchy listener registered for this component. + * + * @param l + * the HierarchyListener. + */ + public void removeHierarchyListener(HierarchyListener l) { + hierarchyListeners.removeUserListener(l); + } + + /** + * Processes a hierarchy event that has occurred on this component by + * dispatching it to the registered listeners. + * + * @param e + * the HierarchyEvent. + */ + protected void processHierarchyEvent(HierarchyEvent e) { + for (HierarchyListener listener : hierarchyListeners.getUserListeners()) { + switch (e.getID()) { + case HierarchyEvent.HIERARCHY_CHANGED: + listener.hierarchyChanged(e); + break; + } + } + } + + /** + * Gets an array of HierarchyBoundsListener objects registered to this + * Component. + * + * @return an array of HierarchyBoundsListener objects. + */ + public HierarchyBoundsListener[] getHierarchyBoundsListeners() { + return hierarchyBoundsListeners.getUserListeners(new HierarchyBoundsListener[0]); + } + + /** + * Adds the specified hierarchy bounds listener. + * + * @param l + * the HierarchyBoundsListener. + */ + public void addHierarchyBoundsListener(HierarchyBoundsListener l) { + hierarchyBoundsListeners.addUserListener(l); + } + + /** + * Removes the hierarchy bounds listener registered for this Component. + * + * @param l + * the HierarchyBoundsListener. + */ + public void removeHierarchyBoundsListener(HierarchyBoundsListener l) { + hierarchyBoundsListeners.removeUserListener(l); + } + + /** + * Processes a hierarchy bounds event that has occurred on this component by + * dispatching it to the registered listeners. + * + * @param e + * the HierarchyBoundsEvent. + */ + protected void processHierarchyBoundsEvent(HierarchyEvent e) { + for (HierarchyBoundsListener listener : hierarchyBoundsListeners.getUserListeners()) { + switch (e.getID()) { + case HierarchyEvent.ANCESTOR_MOVED: + listener.ancestorMoved(e); + break; + case HierarchyEvent.ANCESTOR_RESIZED: + listener.ancestorResized(e); + break; + } + } + } + + /** + * Gets an array of the key listeners registered to the Component. + * + * @return an array of the key listeners registered to the Component. + */ + public KeyListener[] getKeyListeners() { + return keyListeners.getUserListeners(new KeyListener[0]); + } + + /** + * Adds the specified key listener. + * + * @param l + * the KeyListener. + */ + public void addKeyListener(KeyListener l) { + keyListeners.addUserListener(l); + } + + /** + * Adds the awt key listener. + * + * @param l + * the l. + */ + void addAWTKeyListener(KeyListener l) { + enableAWTEvents(AWTEvent.KEY_EVENT_MASK); + keyListeners.addSystemListener(l); + } + + /** + * Removes the key listener registered for this Component. + * + * @param l + * the KeyListener. + */ + public void removeKeyListener(KeyListener l) { + keyListeners.removeUserListener(l); + } + + /** + * Processes a key event that has occurred on this component by dispatching + * it to the registered listeners. + * + * @param e + * the KeyEvent. + */ + protected void processKeyEvent(KeyEvent e) { + processKeyEventImpl(e, keyListeners.getUserListeners()); + } + + /** + * Process key event impl. + * + * @param e + * the e. + * @param c + * the c. + */ + private void processKeyEventImpl(KeyEvent e, Collection<KeyListener> c) { + for (KeyListener listener : c) { + switch (e.getID()) { + case KeyEvent.KEY_PRESSED: + listener.keyPressed(e); + break; + case KeyEvent.KEY_RELEASED: + listener.keyReleased(e); + break; + case KeyEvent.KEY_TYPED: + listener.keyTyped(e); + break; + } + } + } + + /** + * Gets an array of the mouse listeners registered to the Component. + * + * @return an array of the mouse listeners registered to the Component. + */ + public MouseListener[] getMouseListeners() { + return mouseListeners.getUserListeners(new MouseListener[0]); + } + + /** + * Adds the specified mouse listener. + * + * @param l + * the MouseListener. + */ + public void addMouseListener(MouseListener l) { + mouseListeners.addUserListener(l); + } + + /** + * Adds the awt mouse listener. + * + * @param l + * the l. + */ + void addAWTMouseListener(MouseListener l) { + enableAWTEvents(AWTEvent.MOUSE_EVENT_MASK); + mouseListeners.addSystemListener(l); + } + + /** + * Adds the awt mouse motion listener. + * + * @param l + * the l. + */ + void addAWTMouseMotionListener(MouseMotionListener l) { + enableAWTEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK); + mouseMotionListeners.addSystemListener(l); + } + + /** + * Adds the awt component listener. + * + * @param l + * the l. + */ + void addAWTComponentListener(ComponentListener l) { + enableAWTEvents(AWTEvent.COMPONENT_EVENT_MASK); + componentListeners.addSystemListener(l); + } + + /** + * Adds the awt input method listener. + * + * @param l + * the l. + */ + void addAWTInputMethodListener(InputMethodListener l) { + enableAWTEvents(AWTEvent.INPUT_METHOD_EVENT_MASK); + inputMethodListeners.addSystemListener(l); + } + + /** + * Adds the awt mouse wheel listener. + * + * @param l + * the l. + */ + void addAWTMouseWheelListener(MouseWheelListener l) { + enableAWTEvents(AWTEvent.MOUSE_WHEEL_EVENT_MASK); + mouseWheelListeners.addSystemListener(l); + } + + /** + * Removes the mouse listener registered for this Component. + * + * @param l + * the MouseListener. + */ + public void removeMouseListener(MouseListener l) { + mouseListeners.removeUserListener(l); + } + + /** + * Processes a mouse event that has occurred on this component by + * dispatching it to the registered listeners. + * + * @param e + * the MouseEvent. + */ + protected void processMouseEvent(MouseEvent e) { + processMouseEventImpl(e, mouseListeners.getUserListeners()); + } + + /** + * Process mouse event impl. + * + * @param e + * the e. + * @param c + * the c. + */ + private void processMouseEventImpl(MouseEvent e, Collection<MouseListener> c) { + for (MouseListener listener : c) { + switch (e.getID()) { + case MouseEvent.MOUSE_CLICKED: + listener.mouseClicked(e); + break; + case MouseEvent.MOUSE_ENTERED: + listener.mouseEntered(e); + break; + case MouseEvent.MOUSE_EXITED: + listener.mouseExited(e); + break; + case MouseEvent.MOUSE_PRESSED: + listener.mousePressed(e); + break; + case MouseEvent.MOUSE_RELEASED: + listener.mouseReleased(e); + break; + } + } + } + + /** + * Process mouse motion event impl. + * + * @param e + * the e. + * @param c + * the c. + */ + private void processMouseMotionEventImpl(MouseEvent e, Collection<MouseMotionListener> c) { + for (MouseMotionListener listener : c) { + switch (e.getID()) { + case MouseEvent.MOUSE_DRAGGED: + listener.mouseDragged(e); + break; + case MouseEvent.MOUSE_MOVED: + listener.mouseMoved(e); + break; + } + } + } + + /** + * Gets an array of the mouse motion listeners registered to the Component. + * + * @return an array of the MouseMotionListeners registered to the Component. + */ + public MouseMotionListener[] getMouseMotionListeners() { + return mouseMotionListeners.getUserListeners(new MouseMotionListener[0]); + } + + /** + * Adds the specified mouse motion listener. + * + * @param l + * the MouseMotionListener. + */ + public void addMouseMotionListener(MouseMotionListener l) { + mouseMotionListeners.addUserListener(l); + } + + /** + * Removes the mouse motion listener registered for this component. + * + * @param l + * the MouseMotionListener. + */ + public void removeMouseMotionListener(MouseMotionListener l) { + mouseMotionListeners.removeUserListener(l); + } + + /** + * Processes a mouse motion event that has occurred on this component by + * dispatching it to the registered listeners. + * + * @param e + * the MouseEvent. + */ + protected void processMouseMotionEvent(MouseEvent e) { + processMouseMotionEventImpl(e, mouseMotionListeners.getUserListeners()); + } + + /** + * Gets an array of the mouse wheel listeners registered to the Component. + * + * @return an array of the MouseWheelListeners registered to the Component. + */ + public MouseWheelListener[] getMouseWheelListeners() { + return mouseWheelListeners.getUserListeners(new MouseWheelListener[0]); + } + + /** + * Adds the specified mouse wheel listener. + * + * @param l + * the MouseWheelListener. + */ + public void addMouseWheelListener(MouseWheelListener l) { + mouseWheelListeners.addUserListener(l); + } + + /** + * Removes the mouse wheel listener registered for this component. + * + * @param l + * the MouseWheelListener. + */ + public void removeMouseWheelListener(MouseWheelListener l) { + mouseWheelListeners.removeUserListener(l); + } + + /** + * Processes a mouse wheel event that has occurred on this component by + * dispatching it to the registered listeners. + * + * @param e + * the MouseWheelEvent. + */ + protected void processMouseWheelEvent(MouseWheelEvent e) { + processMouseWheelEventImpl(e, mouseWheelListeners.getUserListeners()); + } + + /** + * Gets an array of the InputMethodListener listeners registered to the + * Component. + * + * @return an array of the InputMethodListener listeners registered to the + * Component. + */ + public InputMethodListener[] getInputMethodListeners() { + return inputMethodListeners.getUserListeners(new InputMethodListener[0]); + } + + /** + * Adds the specified input method listener. + * + * @param l + * the InputMethodListener. + */ + public void addInputMethodListener(InputMethodListener l) { + inputMethodListeners.addUserListener(l); + } + + /** + * Removes the input method listener registered for this component. + * + * @param l + * the InputMethodListener. + */ + public void removeInputMethodListener(InputMethodListener l) { + inputMethodListeners.removeUserListener(l); + } + + /** + * Processes an input method event that has occurred on this component by + * dispatching it to the registered listeners. + * + * @param e + * the InputMethodEvent. + */ + protected void processInputMethodEvent(InputMethodEvent e) { + processInputMethodEventImpl(e, inputMethodListeners.getUserListeners()); + } + + /** + * Process input method event impl. + * + * @param e + * the e. + * @param c + * the c. + */ + private void processInputMethodEventImpl(InputMethodEvent e, Collection<InputMethodListener> c) { + for (InputMethodListener listener : c) { + switch (e.getID()) { + case InputMethodEvent.CARET_POSITION_CHANGED: + listener.caretPositionChanged(e); + break; + case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED: + listener.inputMethodTextChanged(e); + break; + } + } + } + + // ???AWT + /* + * public Point getMousePosition() throws HeadlessException { Point + * absPointerPos = MouseInfo.getPointerInfo().getLocation(); Window + * winUnderPtr = + * toolkit.dispatcher.mouseDispatcher.findWindowAt(absPointerPos); Point + * pointerPos = MouseDispatcher.convertPoint(null, absPointerPos, + * winUnderPtr); boolean isUnderPointer = false; if (winUnderPtr == null) { + * return null; } isUnderPointer = winUnderPtr.isComponentAt(this, + * pointerPos); if (isUnderPointer) { return + * MouseDispatcher.convertPoint(null, absPointerPos, this); } return null; } + */ + + /** + * Set native caret at the given position <br> + * Note: this method takes AWT lock inside because it walks through the + * component hierarchy. + * + * @param x + * the x. + * @param y + * the y. + */ + void setCaretPos(final int x, final int y) { + Runnable r = new Runnable() { + public void run() { + toolkit.lockAWT(); + try { + setCaretPosImpl(x, y); + } finally { + toolkit.unlockAWT(); + } + } + }; + if (Thread.currentThread() instanceof EventDispatchThread) { + r.run(); + } else { + toolkit.getSystemEventQueueImpl().postEvent(new InvocationEvent(this, r)); + } + } + + /** + * This method should be called only at event dispatch thread. + * + * @param x + * the x. + * @param y + * the y. + */ + void setCaretPosImpl(int x, int y) { + Component c = this; + while ((c != null) && c.behaviour.isLightweight()) { + x += c.x; + y += c.y; + // ???AWT: c = c.getParent(); + } + if (c == null) { + return; + } + // ???AWT + /* + * if (c instanceof Window) { Insets insets = c.getNativeInsets(); x -= + * insets.left; y -= insets.top; } + * toolkit.getWindowFactory().setCaretPosition(x, y); + */ + } + + // to be overridden in standard components such as Button and List + /** + * Gets the default minimum size. + * + * @return the default minimum size. + */ + Dimension getDefaultMinimumSize() { + return null; + } + + // to be overridden in standard components such as Button and List + /** + * Gets the default preferred size. + * + * @return the default preferred size. + */ + Dimension getDefaultPreferredSize() { + return null; + } + + // to be overridden in standard components such as Button and List + /** + * Reset default size. + */ + void resetDefaultSize() { + } + + // ???AWT + /* + * ComponentBehavior createBehavior() { return new LWBehavior(this); } + */ + + /** + * Gets the default background. + * + * @return the default background. + */ + Color getDefaultBackground() { + // ???AWT: return getWindowAncestor().getDefaultBackground(); + return getBackground(); + } + + /** + * Gets the default foreground. + * + * @return the default foreground. + */ + Color getDefaultForeground() { + // ???AWT return getWindowAncestor().getDefaultForeground(); + return getForeground(); + } + + /** + * Called when native resource for this component is created (for + * heavyweights only). + * + * @param win + * the win. + */ + void nativeWindowCreated(NativeWindow win) { + // to be overridden + } + + /** + * Determine the component's area hidden behind the windows that have higher + * Z-order, including windows of other applications. + * + * @param image + * the image. + * @param destLocation + * the dest location. + * @param destSize + * the dest size. + * @param source + * the source. + * @return the calculated region, or null if it cannot be determined. + */ + // ???AWT + /* + * MultiRectArea getObscuredRegion(Rectangle part) { if (!visible || parent + * == null || !parent.visible) { return null; } Rectangle r = new + * Rectangle(0, 0, w, h); if (part != null) { r = r.intersection(part); } if + * (r.isEmpty()) { return null; } r.translate(x, y); MultiRectArea ret = + * parent.getObscuredRegion(r); if (ret != null) { + * parent.addObscuredRegions(ret, this); ret.translate(-x, -y); + * ret.intersect(new Rectangle(0, 0, w, h)); } return ret; } + */ + + // ???AWT + /* + * private void readObject(ObjectInputStream stream) throws IOException, + * ClassNotFoundException { stream.defaultReadObject(); FieldsAccessor + * accessor = new FieldsAccessor(Component.class, this); + * accessor.set("toolkit", Toolkit.getDefaultToolkit()); //$NON-NLS-1$ + * accessor.set("behaviour", createBehavior()); //$NON-NLS-1$ + * accessor.set("componentLock", new Object()); // $NON-LOCK-1$ + * //$NON-NLS-1$ } + */ + + final void onDrawImage(Image image, Point destLocation, Dimension destSize, Rectangle source) { + ImageParameters imageParams; + if (updatedImages == null) { + updatedImages = new HashMap<Image, ImageParameters>(); + } + imageParams = updatedImages.get(image); + if (imageParams == null) { + imageParams = new ImageParameters(); + updatedImages.put(image, imageParams); + } + imageParams.addDrawing(destLocation, destSize, source); + } + + public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) { + toolkit.lockAWT(); + try { + boolean done = false; + if ((infoflags & (ALLBITS | FRAMEBITS)) != 0) { + done = true; + } else if ((infoflags & SOMEBITS) != 0 && incrementalImageUpdate) { + done = true; + } + if (done) { + repaint(); + } + return (infoflags & (ABORT | ALLBITS)) == 0; + } finally { + toolkit.unlockAWT(); + } + } + + // ???AWT + /* + * private void invalidateRealParent() { Container realParent = + * getRealParent(); if ((realParent != null) && realParent.isValid()) { + * realParent.invalidate(); } } + */ + + /** + * The Class ImageParameters. + */ + private class ImageParameters { + + /** + * The drawing params. + */ + private final LinkedList<DrawingParameters> drawingParams = new LinkedList<DrawingParameters>(); + + /** + * The size. + */ + Dimension size = new Dimension(Component.this.w, Component.this.h); + + /** + * Adds the drawing. + * + * @param destLocation + * the dest location. + * @param destSize + * the dest size. + * @param source + * the source. + */ + void addDrawing(Point destLocation, Dimension destSize, Rectangle source) { + drawingParams.add(new DrawingParameters(destLocation, destSize, source)); + } + + /** + * Drawing parameters iterator. + * + * @return the iterator< drawing parameters>. + */ + Iterator<DrawingParameters> drawingParametersIterator() { + return drawingParams.iterator(); + } + + /** + * The Class DrawingParameters. + */ + class DrawingParameters { + + /** + * The dest location. + */ + Point destLocation; + + /** + * The dest size. + */ + Dimension destSize; + + /** + * The source. + */ + Rectangle source; + + /** + * Instantiates a new drawing parameters. + * + * @param destLocation + * the dest location. + * @param destSize + * the dest size. + * @param source + * the source. + */ + DrawingParameters(Point destLocation, Dimension destSize, Rectangle source) { + this.destLocation = new Point(destLocation); + if (destSize != null) { + this.destSize = new Dimension(destSize); + } else { + this.destSize = null; + } + if (source != null) { + this.source = new Rectangle(source); + } else { + this.source = null; + } + } + } + } + + /** + * TextComponent support. + * + * @param e + * the e. + * @return true, if dispatch event to im. + */ + // ???AWT + /* + * private TextKit textKit = null; TextKit getTextKit() { return textKit; } + * void setTextKit(TextKit kit) { textKit = kit; } + */ + + /** + * TextField support. + */ + // ???AWT + /* + * private TextFieldKit textFieldKit = null; TextFieldKit getTextFieldKit() + * { return textFieldKit; } void setTextFieldKit(TextFieldKit kit) { + * textFieldKit = kit; } + */ + + /** + * Dispatches input & focus events to input method context. + * + * @param e + * event to pass to InputContext.dispatchEvent(). + * @return true if event was consumed by IM, false otherwise. + */ + private boolean dispatchEventToIM(AWTEvent e) { + InputContext ic = getInputContext(); + if (ic == null) { + return false; + } + int id = e.getID(); + boolean isInputEvent = ((id >= KeyEvent.KEY_FIRST) && (id <= KeyEvent.KEY_LAST)) + || ((id >= MouseEvent.MOUSE_FIRST) && (id <= MouseEvent.MOUSE_LAST)); + if (((id >= FocusEvent.FOCUS_FIRST) && (id <= FocusEvent.FOCUS_LAST)) || isInputEvent) { + ic.dispatchEvent(e); + } + return e.isConsumed(); + } +} diff --git a/awt/java/awt/ComponentBehavior.java b/awt/java/awt/ComponentBehavior.java new file mode 100644 index 0000000..f4e8ffb --- /dev/null +++ b/awt/java/awt/ComponentBehavior.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev + * @version $Revision$ + */ +package java.awt; + +import org.apache.harmony.awt.wtk.NativeWindow; + +/** + * The interface of the helper object that encapsulates the difference + * between lightweight and heavyweight components. + */ +interface ComponentBehavior { + + void addNotify(); + + void setBounds(int x, int y, int w, int h, int bMask); + + void setVisible(boolean b); + + Graphics getGraphics(int translationX, int translationY, int width, int height); + + NativeWindow getNativeWindow(); + + boolean isLightweight(); + + void onMove(int x, int y); + + boolean isOpaque(); + + boolean isDisplayable(); + + void setEnabled(boolean value); + + void removeNotify(); + + void setZOrder(int newIndex, int oldIndex); + + boolean setFocus(boolean focus, Component opposite); +} diff --git a/awt/java/awt/ComponentOrientation.java b/awt/java/awt/ComponentOrientation.java new file mode 100644 index 0000000..5acc11a --- /dev/null +++ b/awt/java/awt/ComponentOrientation.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov, Dmitry A. Durnev + * @version $Revision$ + */ + +package java.awt; + +import java.io.Serializable; +import java.util.*; + +/** + * The ComponentOrientation class specifies the language-sensitive orientation + * of component's elements or text. It is used to reflect the differences in + * this ordering between different writing systems. The ComponentOrientation + * class indicates the orientation of the elements/text in the horizontal + * direction ("left to right" or "right to left") and in the vertical direction + * ("top to bottom" or "bottom to top"). + * + * @since Android 1.0 + */ +public final class ComponentOrientation implements Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -4113291392143563828L; + + /** + * The Constant LEFT_TO_RIGHT indicates that items run left to right. + */ + public static final ComponentOrientation LEFT_TO_RIGHT = new ComponentOrientation(true, true); + + /** + * The Constant RIGHT_TO_LEFT indicates that items run right to left. + */ + public static final ComponentOrientation RIGHT_TO_LEFT = new ComponentOrientation(true, false); + + /** + * The Constant UNKNOWN indicates that a component's orientation is not set. + */ + public static final ComponentOrientation UNKNOWN = new ComponentOrientation(true, true); + + /** + * The Constant rlLangs. + */ + private static final Set<String> rlLangs = new HashSet<String>(); // RIGHT_TO_LEFT + + // languages + + /** + * The horizontal. + */ + private final boolean horizontal; + + /** + * The left2right. + */ + private final boolean left2right; + + static { + rlLangs.add("ar"); //$NON-NLS-1$ + rlLangs.add("fa"); //$NON-NLS-1$ + rlLangs.add("iw"); //$NON-NLS-1$ + rlLangs.add("ur"); //$NON-NLS-1$ + } + + /** + * Gets the orientation for the given ResourceBundle's localization. + * + * @param bdl + * the ResourceBundle. + * @return the ComponentOrientation. + * @deprecated Use getOrientation(java.util.Locale) method. + */ + @Deprecated + public static ComponentOrientation getOrientation(ResourceBundle bdl) { + Object obj = null; + try { + obj = bdl.getObject("Orientation"); //$NON-NLS-1$ + } catch (MissingResourceException mre) { + obj = null; + } + if (obj instanceof ComponentOrientation) { + return (ComponentOrientation)obj; + } + Locale locale = bdl.getLocale(); + if (locale == null) { + locale = Locale.getDefault(); + } + return getOrientation(locale); + } + + /** + * Gets the orientation for the specified locale. + * + * @param locale + * the specified Locale. + * @return the ComponentOrientation. + */ + public static ComponentOrientation getOrientation(Locale locale) { + String lang = locale.getLanguage(); + return rlLangs.contains(lang) ? RIGHT_TO_LEFT : LEFT_TO_RIGHT; + } + + /** + * Instantiates a new component orientation. + * + * @param hor + * whether the items should be arranged horizontally. + * @param l2r + * whether this orientation specifies a left-to-right flow. + */ + private ComponentOrientation(boolean hor, boolean l2r) { + horizontal = hor; + left2right = l2r; + } + + /** + * Returns true if the text of the of writing systems arranged horizontally. + * + * @return true, if the text is written horizontally, false for a vertical + * arrangement. + */ + public boolean isHorizontal() { + return horizontal; + } + + /** + * Returns true if the text is arranged from left to right. + * + * @return true, for writing systems written from left to right; false for + * right-to-left. + */ + public boolean isLeftToRight() { + return left2right; + } + +} diff --git a/awt/java/awt/Composite.java b/awt/java/awt/Composite.java new file mode 100644 index 0000000..d1730fe --- /dev/null +++ b/awt/java/awt/Composite.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt; + +import java.awt.image.ColorModel; + +/** + * The Composite interface allows the methods to compose a draw primitive on the + * graphics area. The classes implementing this interface provides the rules and + * a method to create the context for a particular operation. + * + * @since Android 1.0 + */ +public interface Composite { + + /** + * Creates a CompositeContext which defines the encapsulated and optimized + * environment for a compositing operation. Several contexts can exist for a + * single Composite object. + * + * @param srcColorModel + * the source's ColorModel. + * @param dstColorModel + * the destination's ColorModel. + * @param hints + * the RenderingHints. + * @return the CompositeContext object. + */ + public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel, + RenderingHints hints); + +} diff --git a/awt/java/awt/CompositeContext.java b/awt/java/awt/CompositeContext.java new file mode 100644 index 0000000..795640d --- /dev/null +++ b/awt/java/awt/CompositeContext.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt; + +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +/** + * The CompositeContext interface specifies the encapsulated and optimized + * environment for a compositing operation. + * + * @since Android 1.0 + */ +public interface CompositeContext { + + /** + * Composes the two source Raster objects and places the result in the + * destination WritableRaster. + * + * @param src + * the source Raster. + * @param dstIn + * the destination Raster. + * @param dstOut + * the WritableRaster object where the result of composing + * operation is stored. + */ + public void compose(Raster src, Raster dstIn, WritableRaster dstOut); + + /** + * Releases resources allocated for a context. + */ + public void dispose(); + +} diff --git a/awt/java/awt/Cursor.java b/awt/java/awt/Cursor.java new file mode 100644 index 0000000..0a0cc84 --- /dev/null +++ b/awt/java/awt/Cursor.java @@ -0,0 +1,427 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev + * @version $Revision$ + */ + +package java.awt; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.apache.harmony.awt.internal.nls.Messages; +import org.apache.harmony.awt.wtk.NativeCursor; + +/** + * The Cursor class represents the bitmap of the mouse cursor. + * + * @since Android 1.0 + */ +public class Cursor implements Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 8028237497568985504L; + + /** + * The Constant DEFAULT_CURSOR indicates the default cursor type. + */ + public static final int DEFAULT_CURSOR = 0; + + /** + * The Constant CROSSHAIR_CURSOR cursor type. + */ + public static final int CROSSHAIR_CURSOR = 1; + + /** + * The Constant TEXT_CURSOR cursor type. + */ + public static final int TEXT_CURSOR = 2; + + /** + * The Constant WAIT_CURSOR cursor type. + */ + public static final int WAIT_CURSOR = 3; + + /** + * The Constant SW_RESIZE_CURSOR cursor type. + */ + public static final int SW_RESIZE_CURSOR = 4; + + /** + * The Constant SE_RESIZE_CURSOR cursor type. + */ + public static final int SE_RESIZE_CURSOR = 5; + + /** + * The Constant NW_RESIZE_CURSOR cursor type. + */ + public static final int NW_RESIZE_CURSOR = 6; + + /** + * The Constant NE_RESIZE_CURSOR cursor type. + */ + public static final int NE_RESIZE_CURSOR = 7; + + /** + * The Constant N_RESIZE_CURSOR cursor type. + */ + public static final int N_RESIZE_CURSOR = 8; + + /** + * The Constant S_RESIZE_CURSOR cursor type. + */ + public static final int S_RESIZE_CURSOR = 9; + + /** + * The Constant W_RESIZE_CURSOR cursor type. + */ + public static final int W_RESIZE_CURSOR = 10; + + /** + * The Constant E_RESIZE_CURSOR cursor type. + */ + public static final int E_RESIZE_CURSOR = 11; + + /** + * The Constant HAND_CURSOR cursor type. + */ + public static final int HAND_CURSOR = 12; + + /** + * The Constant MOVE_CURSOR cursor type. + */ + public static final int MOVE_CURSOR = 13; + + /** + * A mapping from names to system custom cursors. + */ + static Map<String, Cursor> systemCustomCursors; + + /** + * The cursor props. + */ + static Properties cursorProps; + + /** + * The Constant predefinedNames. + */ + static final String[] predefinedNames = { + "Default", "Crosshair", "Text", "Wait", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + "Southwest Resize", "Southeast Resize", //$NON-NLS-1$ //$NON-NLS-2$ + "Northwest Resize", "Northeast Resize", //$NON-NLS-1$ //$NON-NLS-2$ + "North Resize", "South Resize", "West Resize", "East Resize", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + "Hand", "Move" //$NON-NLS-1$ //$NON-NLS-2$ + + }; + + /** + * The predefined set of cursors. + */ + protected static Cursor[] predefined = { + new Cursor(DEFAULT_CURSOR), null, null, null, null, null, null, null, null, null, null, + null, null, null + }; + + /** + * The Constant CUSTOM_CURSOR is associated with all custom cursor types. + * (Those which are not predefined) + */ + public static final int CUSTOM_CURSOR = -1; + + /** + * The name of the cursor. + */ + protected String name; + + /** + * The type of the cursor, chosen from the list of cursor type constants. + */ + private final int type; + + /** + * The native cursor. + */ + private transient NativeCursor nativeCursor; + + /** + * The exact point on the cursor image that indicates which point the cursor + * is selecting (pointing to). The coordinates are given with respect the + * origin of the Image (its upper left corner). + */ + private Point hotSpot; + + /** + * The image to draw on the screen representing the cursor. + */ + private Image image; + + /** + * Instantiates a new cursor with the specified name. + * + * @param name + * the name of cursor. + */ + protected Cursor(String name) { + this(name, null, new Point()); + } + + /** + * Instantiates a new cursor of the specified type. + * + * @param type + * the type of cursor. + */ + public Cursor(int type) { + checkType(type); + this.type = type; + if ((type >= 0) && (type < predefinedNames.length)) { + name = predefinedNames[type] + " Cursor"; //$NON-NLS-1$ + } + } + + /** + * Instantiates a new cursor. + * + * @param name + * the name. + * @param img + * the img. + * @param hotSpot + * the hot spot. + */ + Cursor(String name, Image img, Point hotSpot) { + this.name = name; + type = CUSTOM_CURSOR; + this.hotSpot = hotSpot; + image = img; + } + + /** + * Finalize method overrides the finalize method from Object class. + * + * @throws Throwable + * if the native cursor is not null and throws a Throwable when + * destroyed. + */ + @Override + protected void finalize() throws Throwable { + if (nativeCursor != null) { + nativeCursor.destroyCursor(); + } + } + + /** + * Gets the name of the cursor. + * + * @return the name of the cursor. + */ + public String getName() { + return name; + } + + /** + * Returns the String representation of the cursor. + * + * @return the String representation of the cursor. + */ + @Override + public String toString() { + return getClass().getName() + "[" + name + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * Gets the cursor type. + * + * @return the cursor type. + */ + public int getType() { + return type; + } + + /** + * Gets the predefined cursor with the specified type. + * + * @param type + * the type of cursor. + * @return the predefined cursor with the specified type. + */ + public static Cursor getPredefinedCursor(int type) { + checkType(type); + Cursor cursor = predefined[type]; + if (cursor == null) { + cursor = new Cursor(type); + predefined[type] = cursor; + } + return cursor; + } + + /** + * Gets the default cursor. + * + * @return the default cursor. + */ + public static Cursor getDefaultCursor() { + return getPredefinedCursor(DEFAULT_CURSOR); + } + + /** + * Gets the specified system custom cursor. + * + * @param name + * the name of the desired system cursor. + * @return the specific system cursor with the specified name. + * @throws AWTException + * if the desired cursor has malformed data such as an + * incorrectly defined hot spot. + * @throws HeadlessException + * if the isHeadless method of the GraphicsEnvironment returns + * true. + */ + public static Cursor getSystemCustomCursor(String name) throws AWTException, HeadlessException { + Toolkit.checkHeadless(); + return getSystemCustomCursorFromMap(name); + } + + /** + * Gets the specified system custom cursor from the map of system custom + * cursors. + * + * @param name + * the name of the desired cursor. + * @return the desired system custom cursor from the map of system custom + * cursors. + * @throws AWTException + * the AWT exception. + */ + private static Cursor getSystemCustomCursorFromMap(String name) throws AWTException { + loadCursorProps(); + if (systemCustomCursors == null) { + systemCustomCursors = new HashMap<String, Cursor>(); + } + Cursor cursor = systemCustomCursors.get(name); + if (cursor != null) { + return cursor; + } + // awt.141=failed to parse hotspot property for cursor: + String exMsg = Messages.getString("awt.141") + name; //$NON-NLS-1$ + String nm = "Cursor." + name; //$NON-NLS-1$ + String nameStr = cursorProps.getProperty(nm + ".Name"); //$NON-NLS-1$ + String hotSpotStr = cursorProps.getProperty(nm + ".HotSpot"); //$NON-NLS-1$ + String fileStr = cursorProps.getProperty(nm + ".File"); //$NON-NLS-1$ + int idx = hotSpotStr.indexOf(','); + if (idx < 0) { + throw new AWTException(exMsg); + } + int x, y; + try { + x = new Integer(hotSpotStr.substring(0, idx)).intValue(); + y = new Integer(hotSpotStr.substring(idx + 1, hotSpotStr.length())).intValue(); + } catch (NumberFormatException nfe) { + throw new AWTException(exMsg); + } + Image img = Toolkit.getDefaultToolkit().createImage(fileStr); + cursor = new Cursor(nameStr, img, new Point(x, y)); + systemCustomCursors.put(name, cursor); + + return cursor; + } + + /** + * Load cursor props. + * + * @throws AWTException + * the AWT exception. + */ + private static void loadCursorProps() throws AWTException { + if (cursorProps != null) { + return; + } + String sep = File.separator; + String cursorsDir = "lib" + sep + "images" + sep + "cursors"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + String cursorsAbsDir = System.getProperty("java.home") + sep + //$NON-NLS-1$ + cursorsDir; + String cursorPropsFileName = "cursors.properties"; //$NON-NLS-1$ + String cursorPropsFullFileName = (cursorsAbsDir + sep + cursorPropsFileName); + cursorProps = new Properties(); + try { + cursorProps.load(new FileInputStream(new File(cursorPropsFullFileName))); + } catch (FileNotFoundException e) { + // awt.142=Exception: class {0} {1} occurred while loading: {2} + throw new AWTException(Messages.getString("awt.142",//$NON-NLS-1$ + new Object[] { + e.getClass(), e.getMessage(), cursorPropsFullFileName + })); + } catch (IOException e) { + throw new AWTException(e.getMessage()); + } + + } + + /** + * Check type. + * + * @param type + * the type. + */ + static void checkType(int type) { + // can't use predefined array here because it may not have been + // initialized yet + if ((type < 0) || (type >= predefinedNames.length)) { + // awt.143=illegal cursor type + throw new IllegalArgumentException(Messages.getString("awt.143")); //$NON-NLS-1$ + } + } + + // "lazily" create native cursors: + /** + * Gets the native cursor. + * + * @return the native cursor. + */ + NativeCursor getNativeCursor() { + if (nativeCursor != null) { + return nativeCursor; + } + Toolkit toolkit = Toolkit.getDefaultToolkit(); + if (type != CUSTOM_CURSOR) { + nativeCursor = toolkit.createNativeCursor(type); + } else { + nativeCursor = toolkit.createCustomNativeCursor(image, hotSpot, name); + } + return nativeCursor; + } + + /** + * Sets the native cursor. + * + * @param nativeCursor + * the new native cursor. + */ + void setNativeCursor(NativeCursor nativeCursor) { + this.nativeCursor = nativeCursor; + } +} diff --git a/awt/java/awt/Dimension.java b/awt/java/awt/Dimension.java new file mode 100644 index 0000000..6777962 --- /dev/null +++ b/awt/java/awt/Dimension.java @@ -0,0 +1,201 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt; + +import java.awt.geom.Dimension2D; +import java.io.Serializable; + +import org.apache.harmony.misc.HashCode; + +/** + * The Dimension represents the size (width and height) of a component. The + * width and height values can be negative, but in that case the behavior of + * some methods is unexpected. + * + * @since Android 1.0 + */ +public class Dimension extends Dimension2D implements Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 4723952579491349524L; + + /** + * The width dimension. + */ + public int width; + + /** + * The height dimension. + */ + public int height; + + /** + * Instantiates a new Dimension with the same data as the specified + * Dimension. + * + * @param d + * the Dimension to copy the data from when creating the new + * Dimension object. + */ + public Dimension(Dimension d) { + this(d.width, d.height); + } + + /** + * Instantiates a new Dimension with zero width and height. + */ + public Dimension() { + this(0, 0); + } + + /** + * Instantiates a new Dimension with the specified width and height. + * + * @param width + * the width of the new Dimension. + * @param height + * the height of the new Dimension. + */ + public Dimension(int width, int height) { + setSize(width, height); + } + + /** + * Returns the hash code of the Dimension. + * + * @return the hash code of the Dimension. + */ + @Override + public int hashCode() { + HashCode hash = new HashCode(); + hash.append(width); + hash.append(height); + return hash.hashCode(); + } + + /** + * Compares this Dimension object with the specified object. + * + * @param obj + * the Object to be compared. + * @return true, if the specified Object is a Dimension with the same width + * and height data as this Dimension. + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Dimension) { + Dimension d = (Dimension)obj; + return (d.width == width && d.height == height); + } + return false; + } + + /** + * Returns the String associated to this Dimension object. + * + * @return the String associated to this Dimension object. + */ + @Override + public String toString() { + // The output format based on 1.5 release behaviour. It could be + // obtained in the following way + // System.out.println(new Dimension().toString()) + return getClass().getName() + "[width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + /** + * Sets the size of this Dimension object with the specified width and + * height. + * + * @param width + * the width of the Dimension. + * @param height + * the height of the Dimension. + */ + public void setSize(int width, int height) { + this.width = width; + this.height = height; + } + + /** + * Sets the size of this Dimension object by copying the data from the + * specified Dimension object. + * + * @param d + * the Dimension that gives the new size values. + */ + public void setSize(Dimension d) { + setSize(d.width, d.height); + } + + /** + * Sets the size of this Dimension object with the specified double width + * and height. + * + * @param width + * the width of the Dimension. + * @param height + * the height of the Dimension. + * @see java.awt.geom.Dimension2D#setSize(double, double) + */ + @Override + public void setSize(double width, double height) { + setSize((int)Math.ceil(width), (int)Math.ceil(height)); + } + + /** + * Gets the size of the Dimension. + * + * @return the size of the Dimension. + */ + public Dimension getSize() { + return new Dimension(width, height); + } + + /** + * Gets the height of the Dimension. + * + * @return the height of the Dimension. + * @see java.awt.geom.Dimension2D#getHeight() + */ + @Override + public double getHeight() { + return height; + } + + /** + * Gets the width of the Dimension. + * + * @return the width of the Dimension. + * @see java.awt.geom.Dimension2D#getWidth() + */ + @Override + public double getWidth() { + return width; + } + +} diff --git a/awt/java/awt/Dispatcher.java b/awt/java/awt/Dispatcher.java new file mode 100644 index 0000000..d457af4 --- /dev/null +++ b/awt/java/awt/Dispatcher.java @@ -0,0 +1,723 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov, Dmitry A. Durnev + * @version $Revision$ + */ +package java.awt; + +import java.awt.event.ComponentEvent; +import java.awt.event.FocusEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.PaintEvent; +import java.awt.event.WindowEvent; + +import org.apache.harmony.awt.internal.nls.Messages; +import org.apache.harmony.awt.wtk.NativeEvent; +import org.apache.harmony.awt.wtk.NativeWindow; + + +/** + * Helper package-private class for managing lightweight components & + * dispatching events from heavyweight source + */ +class Dispatcher { + + //???AWT: final PopupDispatcher popupDispatcher = new PopupDispatcher(); + + //???AWT: final FocusDispatcher focusDispatcher; + + final MouseGrabManager mouseGrabManager = new MouseGrabManager(); + + final MouseDispatcher mouseDispatcher; + + private final ComponentDispatcher componentDispatcher = new ComponentDispatcher(); + + private final KeyDispatcher keyDispatcher = new KeyDispatcher(); + + private final Toolkit toolkit; + + int clickInterval = 250; + + /** + * @param toolkit - AWT toolkit + */ + Dispatcher(Toolkit toolkit) { + this.toolkit = toolkit; + + //???AWT: focusDispatcher = new FocusDispatcher(toolkit); + mouseDispatcher = new MouseDispatcher(mouseGrabManager, toolkit); + } + + /** + * Dispatch native event: produce appropriate AWT events, + * update component's fields when needed + * @param event - native event to dispatch + * @return - true means default processing by OS is not needed + */ + public boolean onEvent(NativeEvent event) { + int eventId = event.getEventId(); + + if (eventId == NativeEvent.ID_CREATED) { + return toolkit.onWindowCreated(event.getWindowId()); + } else if (eventId == NativeEvent.ID_MOUSE_GRAB_CANCELED) { + return mouseGrabManager.onGrabCanceled(); + //???AWT +// } else if (popupDispatcher.onEvent(event)) { +// return false; + } else { + Component src = toolkit.getComponentById(event.getWindowId()); + + if (src != null) { + if (((eventId >= ComponentEvent.COMPONENT_FIRST) && (eventId <= ComponentEvent.COMPONENT_LAST)) + || ((eventId >= WindowEvent.WINDOW_FIRST) && (eventId <= WindowEvent.WINDOW_LAST)) + || (eventId == NativeEvent.ID_INSETS_CHANGED) + || (eventId == NativeEvent.ID_BOUNDS_CHANGED) + || (eventId == NativeEvent.ID_THEME_CHANGED)) { + return componentDispatcher.dispatch(src, event); + } else if ((eventId >= MouseEvent.MOUSE_FIRST) + && (eventId <= MouseEvent.MOUSE_LAST)) { + return mouseDispatcher.dispatch(src, event); + } else if (eventId == PaintEvent.PAINT) { + //???AWT: src.redrawManager.addPaintRegion(src, event.getClipRects()); + return true; + } + } + if ((eventId >= FocusEvent.FOCUS_FIRST) + && (eventId <= FocusEvent.FOCUS_LAST)) { + + //???AWT: return focusDispatcher.dispatch(src, event); + return false; + } else if ((eventId >= KeyEvent.KEY_FIRST) + && (eventId <= KeyEvent.KEY_LAST)) { + return keyDispatcher.dispatch(src, event); + } + } + + return false; + } + + /** + * The dispatcher of native events that affect + * component's state or bounds + */ + final class ComponentDispatcher { + + /** + * Handle native event that affects component's state or bounds + * @param src - the component updated by the event + * @param event - the native event + * @return - as in Dispatcher.onEvent() + * @see Dispatcher#onEvent(NativeEvent) + */ + boolean dispatch(Component src, NativeEvent event) { + int id = event.getEventId(); + + if ((id == NativeEvent.ID_INSETS_CHANGED) + || (id == NativeEvent.ID_THEME_CHANGED)) { + return dispatchInsets(event, src); + } else if ((id >= WindowEvent.WINDOW_FIRST) + && (id <= WindowEvent.WINDOW_LAST)) { + return dispatchWindow(event, src); + } else { + return dispatchPureComponent(event, src); + } + } + + /** + * Handle the change of top-level window's native decorations + * @param event - the native event + * @param src - the component updated by the event + * @return - as in Dispatcher.onEvent() + * @see Dispatcher#onEvent(NativeEvent) + */ + boolean dispatchInsets(NativeEvent event, Component src) { + //???AWT + /* + if (src instanceof Window) { + ((Window) src).setNativeInsets(event.getInsets()); + } + */ + return false; + } + + /** + * Handle the change of top-level window's state + * @param event - the native event + * @param src - the component updated by the event + * @return - as in Dispatcher.onEvent() + * @see Dispatcher#onEvent(NativeEvent) + */ + boolean dispatchWindow(NativeEvent event, Component src) { + //???AWT + /* + Window window = (Window) src; + int id = event.getEventId(); + + if (id == WindowEvent.WINDOW_CLOSING) { + toolkit.getSystemEventQueueImpl().postEvent( + new WindowEvent(window, WindowEvent.WINDOW_CLOSING)); + + return true; + } else if (id == WindowEvent.WINDOW_STATE_CHANGED) { + if (window instanceof Frame) { + ((Frame) window) + .updateExtendedState(event.getWindowState()); + } + } + */ + + return false; + } + + /** + * Handle the change of component's size and/or position + * @param event - the native event + * @param src - the component updated by the event + * @return - as in Dispatcher.onEvent() + * @see Dispatcher#onEvent(NativeEvent) + */ + private boolean dispatchPureComponent(NativeEvent event, Component src) { + Rectangle rect = event.getWindowRect(); + Point loc = rect.getLocation(); + int mask; + + switch (event.getEventId()) { + case NativeEvent.ID_BOUNDS_CHANGED: + mask = 0; + break; + case ComponentEvent.COMPONENT_MOVED: + mask = NativeWindow.BOUNDS_NOSIZE; + break; + case ComponentEvent.COMPONENT_RESIZED: + mask = NativeWindow.BOUNDS_NOMOVE; + break; + default: + // awt.12E=Unknown component event id. + throw new RuntimeException(Messages.getString("awt.12E")); //$NON-NLS-1$ + } + + //???AWT + /* + if (!(src instanceof Window)) { + Component compTo = src.getParent(); + Component compFrom = src.getHWAncestor(); + + if ((compTo != null) && (compFrom != null)) { + loc = MouseDispatcher.convertPoint(compFrom, loc, compTo); + } + } else { + int windowState = event.getWindowState(); + + if ((windowState >= 0) && (src instanceof Frame)) { + ((Frame) src).updateExtendedState(windowState); + } + } + src.setBounds(loc.x, loc.y, rect.width, rect.height, mask, false); + */ + + return false; + } + + } + + /** + * The dispatcher of the keyboard events + */ + final class KeyDispatcher { + + /** + * Handle the keyboard event using the KeyboardFocusManager + * @param src - the component receiving the event + * @param event - the native event + * @return - as in Dispatcher.onEvent() + * @see Dispatcher#onEvent(NativeEvent) + */ + boolean dispatch(Component src, NativeEvent event) { + int id = event.getEventId(); + int modifiers = event.getInputModifiers(); + int location = event.getKeyLocation(); + int code = event.getVKey(); + StringBuffer chars = event.getKeyChars(); + int charsLength = chars.length(); + long time = event.getTime(); + char keyChar = event.getLastChar(); + + //???AWT + /* + if (src == null) { + //retarget focus proxy key events to focusOwner: + Window focusProxyOwner = toolkit.getFocusProxyOwnerById(event + .getWindowId()); + if (focusProxyOwner == null) { + return false; + } + src = KeyboardFocusManager.actualFocusOwner; + } + */ + + EventQueue eventQueue = toolkit.getSystemEventQueueImpl(); + + if (src != null) { + eventQueue.postEvent(new KeyEvent(src, id, time, modifiers, + code, keyChar, location)); + // KEY_TYPED goes after KEY_PRESSED + if (id == KeyEvent.KEY_PRESSED) { + for (int i = 0; i < charsLength; i++) { + keyChar = chars.charAt(i); + if (keyChar != KeyEvent.CHAR_UNDEFINED) { + eventQueue.postEvent(new KeyEvent(src, + KeyEvent.KEY_TYPED, time, modifiers, + KeyEvent.VK_UNDEFINED, keyChar, + KeyEvent.KEY_LOCATION_UNKNOWN)); + } + } + } + } + + return false; + } + + } + + /** + * Retargets the mouse events to the grab owner when mouse is grabbed, + * grab and ungrab mouse when mouse buttons are pressed and released + */ + + static final class MouseGrabManager { + + /** + * The top-level window holding the mouse grab + * that was explicitly started by startGrab() method + */ + //???AWT: private Window nativeGrabOwner = null; + /** + * The component that owns the synthetic + * mouse grab while at least one of the + * mouse buttons is pressed + */ + private Component syntheticGrabOwner = null; + + /** + * Previous value of syntheticGrabOwner + */ + private Component lastSyntheticGrabOwner = null; + + /** + * Number of mouse buttons currently pressed + */ + private int syntheticGrabDepth = 0; + + /** + * The callback to be called when the explicit mouse grab ends + */ + private Runnable whenCanceled; + + /** + * Explicitly start the mouse grab + * @param grabWindow - the window that will own the grab + * @param whenCanceled - the callback to call when the grab ends. + * This parameter can be null + */ + //???AWT + /* + void startGrab(Window grabWindow, Runnable whenCanceled) { + + if (nativeGrabOwner != null) { + // awt.12F=Attempt to start nested mouse grab + throw new RuntimeException(Messages.getString("awt.12F")); //$NON-NLS-1$ + } + + NativeWindow win = grabWindow.getNativeWindow(); + if (win == null) { + // awt.130=Attempt to grab mouse in not displayable window + throw new RuntimeException(Messages.getString("awt.130")); //$NON-NLS-1$ + } + + nativeGrabOwner = grabWindow; + this.whenCanceled = whenCanceled; + win.grabMouse(); + } + */ + + /** + * Ends the explicit mouse grab. If the non-null callback was provided + * in the startGrab() method, this callback is called + */ + void endGrab() { + //???AWT + /* + if (nativeGrabOwner == null) { + return; + } + + Window grabWindow = nativeGrabOwner; + nativeGrabOwner = null; + NativeWindow win = grabWindow.getNativeWindow(); + + if (win != null) { + win.ungrabMouse(); + if (whenCanceled != null) { + whenCanceled.run(); + whenCanceled = null; + } + } + */ + } + + /** + * Ends both explicit and synthetic grans + * @return - always returns false + */ + boolean onGrabCanceled() { + endGrab(); + resetSyntheticGrab(); + + return false; + } + + /** + * Starts the synthetic mouse grab, increases the counter + * of currently pressed mouse buttons + * @param source - the component where mouse press event occured + * @return - the component that owns the synthetic grab + */ + Component onMousePressed(Component source) { + if (syntheticGrabDepth == 0) { + syntheticGrabOwner = source; + lastSyntheticGrabOwner = source; + } + syntheticGrabDepth++; + + return syntheticGrabOwner; + } + + /** + * Decreases the counter of currently pressed mouse buttons, + * ends the synthetic mouse grab, when this counter becomes zero + * @param source - the component where mouse press event occured + * @return - the component that owns the synthetic grab, + * or source parameter if mouse grab was released + */ + Component onMouseReleased(Component source) { + Component ret = source; + + //???AWT + /* + if (syntheticGrabOwner != null && nativeGrabOwner == null) { + ret = syntheticGrabOwner; + } + */ + syntheticGrabDepth--; + if (syntheticGrabDepth <= 0) { + resetSyntheticGrab(); + lastSyntheticGrabOwner = null; + } + + return ret; + } + + /** + * Update the state of synthetic ouse gram + * when the mouse is moved/dragged + * @param event - the native event + */ + void preprocessEvent(NativeEvent event) { + int id = event.getEventId(); + switch (id) { + case MouseEvent.MOUSE_MOVED: + if (syntheticGrabOwner != null) { + syntheticGrabOwner = null; + syntheticGrabDepth = 0; + } + if (lastSyntheticGrabOwner != null) { + lastSyntheticGrabOwner = null; + } + case MouseEvent.MOUSE_DRAGGED: + if (syntheticGrabOwner == null + && lastSyntheticGrabOwner != null) { + syntheticGrabOwner = lastSyntheticGrabOwner; + syntheticGrabDepth = 0; + int mask = event.getInputModifiers(); + syntheticGrabDepth += (mask & InputEvent.BUTTON1_DOWN_MASK) != 0 ? 1 + : 0; + syntheticGrabDepth += (mask & InputEvent.BUTTON2_DOWN_MASK) != 0 ? 1 + : 0; + syntheticGrabDepth += (mask & InputEvent.BUTTON3_DOWN_MASK) != 0 ? 1 + : 0; + } + } + } + + /** + * @return the component that currently owns the synthetic grab + */ + Component getSyntheticGrabOwner() { + return syntheticGrabOwner; + } + + /** + * ends synthetic grab + */ + private void resetSyntheticGrab() { + syntheticGrabOwner = null; + syntheticGrabDepth = 0; + } + + } + + /** + * Dispatches native events related to the pop-up boxes + * (the non-component windows such as menus and drop lists) + */ +// final class PopupDispatcher { +// +// private PopupBox activePopup; +// +// private PopupBox underCursor; +// +// private final MouseGrab grab = new MouseGrab(); +// +// /** +// * Handles the mouse grab for pop-up boxes +// */ +// private final class MouseGrab { +// private int depth; +// +// private PopupBox owner; +// +// private final Point start = new Point(); +// +// /** +// * Starts the grab when mouse is pressed +// * @param src - the pop-up box where mouse event has occured +// * @param where - the mouse pointer location +// * @return - the grab owner +// */ +// PopupBox mousePressed(PopupBox src, Point where) { +// if (depth == 0) { +// owner = src; +// start.setLocation(where); +// } +// depth++; +// return owner; +// } +// +// /** +// * Ends the grab when all mousebuttons are released +// * @param src - the pop-up box where mouse event has occured +// * @param where - the mouse pointer location +// * @return - the grab owner, or src parameter if the grab has ended +// */ +// PopupBox mouseReleased(PopupBox src, Point where) { +// PopupBox ret = (owner != null) ? owner : src; +// if (depth == 0) { +// return ret; +// } +// depth--; +// if (depth == 0) { +// PopupBox tgt = owner; +// owner = null; +// if (tgt != null && src == null) { +// Point a = new Point(start); +// Point b = new Point(where); +// Point pos = tgt.getScreenLocation(); +// a.translate(-pos.x, -pos.y); +// b.translate(-pos.x, -pos.y); +// if (tgt.closeOnUngrab(a, b)) { +// return null; +// } +// } +// } +// return ret; +// } +// +// /** +// * Set the grab owner to null +// */ +// void reset() { +// depth = 0; +// owner = null; +// start.setLocation(0, 0); +// } +// +// /** +// * @return - the pop-up box currently owning the grab +// */ +// public PopupBox getOwner() { +// return owner; +// } +// } +// +// /** +// * Call the mouse event handler of the pop-up box +// * @param src - the pop-up box where the mouse event occured +// * @param eventId - the event ID, one of MouseEvent.MOUSE_* constants +// * @param where - the mouse pointer location +// * @param event - native event +// */ +// private void mouseEvent(PopupBox src, int eventId, Point where, +// NativeEvent event) { +// Point pos = src.getScreenLocation(); +// pos.setLocation(where.x - pos.x, where.y - pos.y); +// +// src.onMouseEvent(eventId, pos, event.getMouseButton(), event +// .getTime(), event.getInputModifiers(), event +// .getWheelRotation()); +// } +// +// /** +// * Handle the native event targeted by a pop-up box. This could be +// * paint event, mouse or keyboard event. +// * @param event - the native event +// * @return - false if the event was handled and doesn't +// * need the further processing; true when the further +// * processing is needed +// */ +// boolean onEvent(NativeEvent event) { +// PopupBox src = toolkit.getPopupBoxById(event.getWindowId()); +// int id = event.getEventId(); +// +// if ((id == PaintEvent.PAINT)) { +// if (src != null) { +// src.paint(event.getClipRects()); +// return true; +// } +// Component c = toolkit.getComponentById(event.getWindowId()); +// if ((c != null) && (c instanceof Frame)) { +// ((Frame) c).paintMenuBar(event.getClipRects()); +// } +// return false; +// } +// +// if ((id >= MouseEvent.MOUSE_FIRST) && (id <= MouseEvent.MOUSE_LAST)) { +// Point where = event.getScreenPos(); +// +// if (src != underCursor) { +// if (underCursor != null) { +// mouseEvent(underCursor, MouseEvent.MOUSE_EXITED, where, +// event); +// } +// underCursor = src; +// if (underCursor != null) { +// mouseEvent(underCursor, MouseEvent.MOUSE_ENTERED, +// where, event); +// underCursor.setDefaultCursor(); +// } +// } +// if (id == MouseEvent.MOUSE_EXITED) { +// underCursor = null; +// } +// +// if ((activePopup == null) && (src == null || !src.isMenuBar())) { +// return false; +// } +// +// if (id == MouseEvent.MOUSE_PRESSED) { +// src = grab.mousePressed(src, where); +// } else if (id == MouseEvent.MOUSE_RELEASED) { +// src = grab.mouseReleased(src, where); +// } else if (src == null) { +// src = grab.getOwner(); +// } +// +// PopupBox wasActive = activePopup; +// +// if (src != null) { +// mouseEvent(src, id, where, event); +// return src.isMenu() || src.contains(where); +// } +// +// if (wasActive != null && activePopup == null) { +// return wasActive.isMenu(); +// } +// +// if ((id == MouseEvent.MOUSE_PRESSED) +// || (id == MouseEvent.MOUSE_RELEASED)) { +// boolean isMenu = activePopup.isMenu(); +// deactivateAll(); +// return !isMenu; +// } +// return true; +// } +// +// if (activePopup == null) { +// return false; +// } +// +// if ((id >= KeyEvent.KEY_FIRST) && (id <= KeyEvent.KEY_LAST)) { +// boolean isMenu = activePopup.isMenu(); +// activePopup.dispatchKeyEvent(id, event.getVKey(), event +// .getTime(), event.getInputModifiers()); +// +// return isMenu; +// } +// +// return false; +// } +// +// /** +// * Remember the pop-up as active and grab the mouse on it +// * @param popup - the pop-up box to activate +// */ +// void activate(final PopupBox popup) { +// if (activePopup == null) { +// +// activePopup = popup; +// mouseGrabManager.startGrab(popup.getOwner(), new Runnable() { +// public void run() { +// deactivate(popup); +// } +// }); +// } +// } +// +// /** +// * Deactivate the currently active pop-up box +// */ +// void deactivateAll() { +// deactivate(activePopup); +// } +// +// /** +// * Deactivate the pop-up box, end the mouse grab +// */ +// void deactivate(PopupBox popup) { +// grab.reset(); +// +// if (activePopup != null && activePopup == popup) { +// activePopup = null; +// mouseGrabManager.endGrab(); +// popup.hide(); +// underCursor = null; +// } +// } +// +// /** +// * Check that the pop-up box is currently active +// * @param popup - the pop-up box to check +// * @return - true if active +// */ +// boolean isActive(PopupBox popup) { +// return (popup == activePopup) && (popup != null); +// } +// } + +}
\ No newline at end of file diff --git a/awt/java/awt/DisplayMode.java b/awt/java/awt/DisplayMode.java new file mode 100644 index 0000000..8021010 --- /dev/null +++ b/awt/java/awt/DisplayMode.java @@ -0,0 +1,165 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt; + +/** + * The DisplayMode class contains the bit depth, height, width and refresh rate + * of a GraphicsDevice. + * + * @since Android 1.0 + */ +public final class DisplayMode { + + /** + * The width. + */ + private final int width; + + /** + * The height. + */ + private final int height; + + /** + * The bit depth. + */ + private final int bitDepth; + + /** + * The refresh rate. + */ + private final int refreshRate; + + /** + * The Constant Value BIT_DEPTH_MULTI indicates the bit depth + */ + + public static final int BIT_DEPTH_MULTI = -1; + + /** + * The Constant REFRESH_RATE_UNKNOWN indicates the refresh rate. + */ + public static final int REFRESH_RATE_UNKNOWN = 0; + + /** + * Creates a new DisplayMode object with the specified parameters. + * + * @param width + * the width of the display. + * @param height + * the height of the display. + * @param bitDepth + * the bit depth of the display. + * @param refreshRate + * the refresh rate of the display. + */ + + public DisplayMode(int width, int height, int bitDepth, int refreshRate) { + this.width = width; + this.height = height; + this.bitDepth = bitDepth; + this.refreshRate = refreshRate; + } + + /** + * Compares if this DisplayMode is equal to the specified object or not. + * + * @param dm + * the Object to be compared. + * @return true, if the specified object is a DisplayMode with the same data + * values as this DisplayMode, false otherwise. + */ + + @Override + public boolean equals(Object dm) { + if (dm instanceof DisplayMode) { + return equals((DisplayMode)dm); + } + return false; + } + + /** + * Compares if this DisplayMode is equal to the specified DisplayMode object + * or not. + * + * @param dm + * the DisplayMode to be compared. + * @return true, if all of the data values of this DisplayMode are equal to + * the values of the specified DisplayMode object, false otherwise. + */ + public boolean equals(DisplayMode dm) { + if (dm == null) { + return false; + } + if (dm.bitDepth != bitDepth) { + return false; + } + if (dm.refreshRate != refreshRate) { + return false; + } + if (dm.width != width) { + return false; + } + if (dm.height != height) { + return false; + } + return true; + } + + /** + * Gets the bit depth of the DisplayMode, returns BIT_DEPTH_MULTI value if + * multiple bit depths are supported in this display mode. + * + * @return the bit depth of the DisplayMode. + */ + public int getBitDepth() { + return bitDepth; + } + + /** + * Gets the height of the DisplayMode. + * + * @return the height of the DisplayMode. + */ + public int getHeight() { + return height; + } + + /** + * Gets the refresh rate of the DisplayMode, returns REFRESH_RATE_UNKNOWN + * value if the information is not available. + * + * @return the refresh rate of the DisplayMode. + */ + public int getRefreshRate() { + return refreshRate; + } + + /** + * Gets the width of the DisplayMode. + * + * @return the width of the DisplayMode. + */ + public int getWidth() { + return width; + } +} diff --git a/awt/java/awt/Event.java b/awt/java/awt/Event.java new file mode 100644 index 0000000..226a61f --- /dev/null +++ b/awt/java/awt/Event.java @@ -0,0 +1,596 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev + * @version $Revision$ + */ + +package java.awt; + +import java.io.Serializable; + +/** + * The Event class is obsolete and has been replaced by AWTEvent class. + * + * @since Android 1.0 + */ +public class Event implements Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 5488922509400504703L; + + /** + * The Constant SHIFT_MASK indicates that the Shift key is down when the + * event occurred. + */ + public static final int SHIFT_MASK = 1; + + /** + * The Constant CTRL_MASK indicates that the Control key is down when the + * event occurred. + */ + public static final int CTRL_MASK = 2; + + /** + * The Constant META_MASK indicates that the Meta key is down when t he + * event occurred (or the right mouse button). + */ + public static final int META_MASK = 4; + + /** + * The Constant ALT_MASK indicates that the Alt key is down when the event + * occurred (or the middle mouse button). + */ + public static final int ALT_MASK = 8; + + /** + * The Constant HOME indicates Home key. + */ + public static final int HOME = 1000; + + /** + * The Constant END indicates End key. + */ + public static final int END = 1001; + + /** + * The Constant PGUP indicates Page Up key. + */ + public static final int PGUP = 1002; + + /** + * The Constant PGDN indicates Page Down key. + */ + public static final int PGDN = 1003; + + /** + * The Constant UP indicates Up key. + */ + public static final int UP = 1004; + + /** + * The Constant DOWN indicates Down key. + */ + public static final int DOWN = 1005; + + /** + * The Constant LEFT indicates Left key. + */ + public static final int LEFT = 1006; + + /** + * The Constant RIGHT indicates Right key. + */ + public static final int RIGHT = 1007; + + /** + * The Constant F1 indicates F1 key. + */ + public static final int F1 = 1008; + + /** + * The Constant F2 indicates F2 key. + */ + public static final int F2 = 1009; + + /** + * The Constant F3 indicates F3 key. + */ + public static final int F3 = 1010; + + /** + * The Constant F4 indicates F4 key. + */ + public static final int F4 = 1011; + + /** + * The Constant F5 indicates F5 key. + */ + public static final int F5 = 1012; + + /** + * The Constant F6 indicates F6 key. + */ + public static final int F6 = 1013; + + /** + * The Constant F7 indicates F7 key. + */ + public static final int F7 = 1014; + + /** + * The Constant F8 indicates F8 key. + */ + public static final int F8 = 1015; + + /** + * The Constant F9 indicates F9 key. + */ + public static final int F9 = 1016; + + /** + * The Constant F10 indicates F10 key. + */ + public static final int F10 = 1017; + + /** + * The Constant F11 indicates F11 key. + */ + public static final int F11 = 1018; + + /** + * The Constant F12 indicates F12 key. + */ + public static final int F12 = 1019; + + /** + * The Constant PRINT_SCREEN indicates Print Screen key. + */ + public static final int PRINT_SCREEN = 1020; + + /** + * The Constant SCROLL_LOCK indicates Scroll Lock key. + */ + public static final int SCROLL_LOCK = 1021; + + /** + * The Constant CAPS_LOCK indicates Caps Lock key. + */ + public static final int CAPS_LOCK = 1022; + + /** + * The Constant NUM_LOCK indicates Num Lock key. + */ + public static final int NUM_LOCK = 1023; + + /** + * The Constant PAUSE indicates Pause key. + */ + public static final int PAUSE = 1024; + + /** + * The Constant INSERT indicates Insert key. + */ + public static final int INSERT = 1025; + + /** + * The Constant ENTER indicates Enter key. + */ + public static final int ENTER = 10; + + /** + * The Constant BACK_SPACE indicates Back Space key. + */ + public static final int BACK_SPACE = 8; + + /** + * The Constant TAB indicates TAb key. + */ + public static final int TAB = 9; + + /** + * The Constant ESCAPE indicates Escape key. + */ + public static final int ESCAPE = 27; + + /** + * The Constant DELETE indicates Delete key. + */ + public static final int DELETE = 127; + + /** + * The Constant WINDOW_DESTROY indicates an event when the user has asked + * the window manager to kill the window. + */ + public static final int WINDOW_DESTROY = 201; + + /** + * The Constant WINDOW_EXPOSE indicates an event when the user has asked the + * window manager to expose the window. + */ + public static final int WINDOW_EXPOSE = 202; + + /** + * The Constant WINDOW_ICONIFY indicates an event when the user has asked + * the window manager to iconify the window. + */ + public static final int WINDOW_ICONIFY = 203; + + /** + * The Constant WINDOW_DEICONIFY indicates an event when the user has asked + * the window manager to deiconify the window. + */ + public static final int WINDOW_DEICONIFY = 204; + + /** + * The Constant WINDOW_MOVED indicates an event when the user has asked the + * window manager to move the window. + */ + public static final int WINDOW_MOVED = 205; + + /** + * The Constant KEY_PRESS indicates an event when the user presses a normal + * key. + */ + public static final int KEY_PRESS = 401; + + /** + * The Constant KEY_RELEASE indicates an event when the user releases a + * normal key. + */ + public static final int KEY_RELEASE = 402; + + /** + * The Constant KEY_ACTION indicates an event when the user pressed a + * non-ASCII action key. + */ + public static final int KEY_ACTION = 403; + + /** + * The Constant KEY_ACTION_RELEASE indicates an event when the user released + * a non-ASCII action key. + */ + public static final int KEY_ACTION_RELEASE = 404; + + /** + * The Constant MOUSE_DOWN indicates an event when the user has pressed the + * mouse button. + */ + public static final int MOUSE_DOWN = 501; + + /** + * The Constant MOUSE_UP indicates an event when the user has released the + * mouse button. + */ + public static final int MOUSE_UP = 502; + + /** + * The Constant MOUSE_MOVE indicates an event when the user has moved the + * mouse with no button pressed. + */ + public static final int MOUSE_MOVE = 503; + + /** + * The Constant MOUSE_ENTER indicates an event when the mouse has entered a + * component. + */ + public static final int MOUSE_ENTER = 504; + + /** + * The Constant MOUSE_EXIT indicates an event when the mouse has exited a + * component. + */ + public static final int MOUSE_EXIT = 505; + + /** + * The Constant MOUSE_DRAG indicates an event when the user has moved a + * mouse with the pressed button. + */ + public static final int MOUSE_DRAG = 506; + + /** + * The Constant SCROLL_LINE_UP indicates an event when the user has + * activated line-up area of scrollbar. + */ + public static final int SCROLL_LINE_UP = 601; + + /** + * The Constant SCROLL_LINE_DOWN indicates an event when the user has + * activated line-down area of scrollbar. + */ + public static final int SCROLL_LINE_DOWN = 602; + + /** + * The Constant SCROLL_PAGE_UP indicates an event when the user has + * activated page up area of scrollbar. + */ + public static final int SCROLL_PAGE_UP = 603; + + /** + * The Constant SCROLL_PAGE_DOWN indicates an event when the user has + * activated page down area of scrollbar. + */ + public static final int SCROLL_PAGE_DOWN = 604; + + /** + * The Constant SCROLL_ABSOLUTE indicates an event when the user has moved + * the bubble in a scroll bar. + */ + public static final int SCROLL_ABSOLUTE = 605; + + /** + * The Constant SCROLL_BEGIN indicates a scroll begin event. + */ + public static final int SCROLL_BEGIN = 606; + + /** + * The Constant SCROLL_END indicates a scroll end event. + */ + public static final int SCROLL_END = 607; + + /** + * The Constant LIST_SELECT indicates that an item in a list has been + * selected. + */ + public static final int LIST_SELECT = 701; + + /** + * The Constant LIST_DESELECT indicates that an item in a list has been + * unselected. + */ + public static final int LIST_DESELECT = 702; + + /** + * The Constant ACTION_EVENT indicates that the user wants some action to + * occur. + */ + public static final int ACTION_EVENT = 1001; + + /** + * The Constant LOAD_FILE indicates a file loading event. + */ + public static final int LOAD_FILE = 1002; + + /** + * The Constant SAVE_FILE indicates a file saving event. + */ + public static final int SAVE_FILE = 1003; + + /** + * The Constant GOT_FOCUS indicates that a component got the focus. + */ + public static final int GOT_FOCUS = 1004; + + /** + * The Constant LOST_FOCUS indicates that the component lost the focus. + */ + public static final int LOST_FOCUS = 1005; + + /** + * The target is the component with which the event is associated. + */ + public Object target; + + /** + * The when is timestamp when event has occured. + */ + public long when; + + /** + * The id indicates the type of the event. + */ + public int id; + + /** + * The x coordinate of event. + */ + public int x; + + /** + * The y coordinate of event. + */ + public int y; + + /** + * The key code of key event. + */ + public int key; + + /** + * The state of the modifier keys (given by a bitmask). + */ + public int modifiers; + + /** + * The click count indicates the number of consecutive clicks. + */ + public int clickCount; + + /** + * The argument of the event. + */ + public Object arg; + + /** + * The next event. + */ + public Event evt; + + /** + * Instantiates a new event with the specified target component, event type, + * and argument. + * + * @param target + * the target component. + * @param id + * the event type. + * @param arg + * the argument. + */ + public Event(Object target, int id, Object arg) { + this(target, 0l, id, 0, 0, 0, 0, arg); + } + + /** + * Instantiates a new event with the specified target component, time stamp, + * event type, x and y coordinates, keyboard key, state of the modifier + * keys, and an argument set to null. + * + * @param target + * the target component. + * @param when + * the time stamp. + * @param id + * the event type. + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @param key + * the key. + * @param modifiers + * the modifier keys state. + */ + public Event(Object target, long when, int id, int x, int y, int key, int modifiers) { + this(target, when, id, x, y, key, modifiers, null); + } + + /** + * Instantiates a new event with the specified target component, time stamp, + * event type, x and y coordinates, keyboard key, state of the modifier + * keys, and an argument. + * + * @param target + * the target component. + * @param when + * the time stamp. + * @param id + * the event type. + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @param key + * the key. + * @param modifiers + * the modifier keys state. + * @param arg + * the specified argument. + */ + public Event(Object target, long when, int id, int x, int y, int key, int modifiers, Object arg) { + this.target = target; + this.when = when; + this.id = id; + this.x = x; + this.y = y; + this.key = key; + this.modifiers = modifiers; + this.arg = arg; + } + + /** + * Returns a string representation of this Event. + * + * @return a string representation of this Event. + */ + @Override + public String toString() { + /* + * The format is based on 1.5 release behavior which can be revealed by + * the following code: Event e = new Event(new Button(), 0l, + * Event.KEY_PRESS, 0, 0, Event.TAB, Event.SHIFT_MASK, "arg"); + * System.out.println(e); + */ + + return getClass().getName() + "[" + paramString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * Returns a string representing the state of this Event. + * + * @return a string representing the state of this Event. + */ + protected String paramString() { + return "id=" + id + ",x=" + x + ",y=" + y + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + (key != 0 ? ",key=" + key + getModifiersString() : "") + //$NON-NLS-1$ //$NON-NLS-2$ + ",target=" + target + //$NON-NLS-1$ + (arg != null ? ",arg=" + arg : ""); //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * Gets a string representation of the modifiers. + * + * @return a string representation of the modifiers. + */ + private String getModifiersString() { + String strMod = ""; //$NON-NLS-1$ + if (shiftDown()) { + strMod += ",shift"; //$NON-NLS-1$ + } + if (controlDown()) { + strMod += ",control"; //$NON-NLS-1$ + } + if (metaDown()) { + strMod += ",meta"; //$NON-NLS-1$ + } + return strMod; + } + + /** + * Translates x and y coordinates of his event to the x+dx and x+dy + * coordinates. + * + * @param dx + * the distance by which the event's x coordinate is increased. + * @param dy + * the distance by which the event's y coordinate is increased. + */ + public void translate(int dx, int dy) { + x += dx; + y += dy; + } + + /** + * Checks if Control key is down or not. + * + * @return true, if Control key is down; false otherwise. + */ + public boolean controlDown() { + return (modifiers & CTRL_MASK) != 0; + } + + /** + * Checks if Meta key is down or not. + * + * @return true, if Meta key is down; false otherwise. + */ + public boolean metaDown() { + return (modifiers & META_MASK) != 0; + } + + /** + * Checks if Shift key is down or not. + * + * @return true, if Shift key is down; false otherwise. + */ + public boolean shiftDown() { + return (modifiers & SHIFT_MASK) != 0; + } + +} diff --git a/awt/java/awt/EventDispatchThread.java b/awt/java/awt/EventDispatchThread.java new file mode 100644 index 0000000..442c8a2 --- /dev/null +++ b/awt/java/awt/EventDispatchThread.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov, Pavel Dolgov + * @version $Revision$ + */ +package java.awt; + +import org.apache.harmony.awt.wtk.NativeEvent; +import org.apache.harmony.awt.wtk.NativeEventQueue; + +class EventDispatchThread extends Thread { + + private static final class MarkerEvent extends AWTEvent { + MarkerEvent(Object source, int id) { + super(source, id); + } + } + + final Dispatcher dispatcher; + final Toolkit toolkit; + private NativeEventQueue nativeQueue; + + protected volatile boolean shutdownPending = false; + + /** + * Initialise and run the main event loop + */ + @Override + public void run() { + nativeQueue = toolkit.getNativeEventQueue(); + + try { + runModalLoop(null); + } finally { + toolkit.shutdownWatchdog.forceShutdown(); + } + } + + void runModalLoop(ModalContext context) { + long lastPaintTime = System.currentTimeMillis(); + while (!shutdownPending && (context == null || context.isModalLoopRunning())) { + try { + EventQueue eventQueue = toolkit.getSystemEventQueueImpl(); + + NativeEvent ne = nativeQueue.getNextEvent(); + if (ne != null) { + dispatcher.onEvent(ne); + MarkerEvent marker = new MarkerEvent(this, 0); + eventQueue.postEvent(marker); + for (AWTEvent ae = eventQueue.getNextEventNoWait(); + (ae != null) && (ae != marker); + ae = eventQueue.getNextEventNoWait()) { + eventQueue.dispatchEvent(ae); + } + } else { + toolkit.shutdownWatchdog.setNativeQueueEmpty(true); + AWTEvent ae = eventQueue.getNextEventNoWait(); + if (ae != null) { + eventQueue.dispatchEvent(ae); + long curTime = System.currentTimeMillis(); + if (curTime - lastPaintTime > 10) { + toolkit.onQueueEmpty(); + lastPaintTime = System.currentTimeMillis(); + } + } else { + toolkit.shutdownWatchdog.setAwtQueueEmpty(true); + toolkit.onQueueEmpty(); + lastPaintTime = System.currentTimeMillis(); + waitForAnyEvent(); + } + } + } catch (Throwable t) { + // TODO: Exception handler should be implemented + // t.printStackTrace(); + } + } + } + + private void waitForAnyEvent() { + EventQueue eventQueue = toolkit.getSystemEventQueueImpl(); + if (!eventQueue.isEmpty() || !nativeQueue.isEmpty()) { + return; + } + Object eventMonitor = nativeQueue.getEventMonitor(); + synchronized(eventMonitor) { + try { + eventMonitor.wait(); + } catch (InterruptedException e) {} + } + } + + void shutdown() { + shutdownPending = true; + } + + EventDispatchThread(Toolkit toolkit, Dispatcher dispatcher ) { + this.toolkit = toolkit; + this.dispatcher = dispatcher; + setName("AWT-EventDispatchThread"); //$NON-NLS-1$ + setDaemon(true); + } + +} diff --git a/awt/java/awt/EventQueue.java b/awt/java/awt/EventQueue.java new file mode 100644 index 0000000..126a593 --- /dev/null +++ b/awt/java/awt/EventQueue.java @@ -0,0 +1,320 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov, Pavel Dolgov + * @version $Revision$ + */ + +package java.awt; + +import java.awt.event.InvocationEvent; +import java.lang.reflect.InvocationTargetException; +import java.util.EmptyStackException; + +/** + * The EventQueue class manages events. It is a platform-independent class that + * queues events both from the underlying peer classes and from trusted + * application classes. + * + * @since Android 1.0 + */ +public class EventQueue { + + /** + * The core ref. + */ + private final EventQueueCoreAtomicReference coreRef = new EventQueueCoreAtomicReference(); + + /** + * The Class EventQueueCoreAtomicReference. + */ + private static final class EventQueueCoreAtomicReference { + + /** + * The core. + */ + private EventQueueCore core; + + /* synchronized */ + /** + * Gets the. + * + * @return the event queue core. + */ + EventQueueCore get() { + return core; + } + + /* synchronized */ + /** + * Sets the. + * + * @param newCore + * the new core. + */ + void set(EventQueueCore newCore) { + core = newCore; + } + } + + /** + * Returns true if the calling thread is the current AWT EventQueue's + * dispatch thread. + * + * @return true, if the calling thread is the current AWT EventQueue's + * dispatch thread; false otherwise. + */ + public static boolean isDispatchThread() { + return Thread.currentThread() instanceof EventDispatchThread; + } + + /** + * Posts an InvocationEvent which executes the run() method on a Runnable + * when dispatched by the AWT event dispatcher thread. + * + * @param runnable + * the Runnable whose run method should be executed synchronously + * on the EventQueue. + */ + public static void invokeLater(Runnable runnable) { + Toolkit toolkit = Toolkit.getDefaultToolkit(); + InvocationEvent event = new InvocationEvent(toolkit, runnable); + toolkit.getSystemEventQueueImpl().postEvent(event); + } + + /** + * Posts an InvocationEvent which executes the run() method on a Runnable + * when dispatched by the AWT event dispatcher thread and the notifyAll + * method is called on it immediately after run returns. + * + * @param runnable + * the Runnable whose run method should be executed synchronously + * on the EventQueue. + * @throws InterruptedException + * if another thread has interrupted this thread. + * @throws InvocationTargetException + * if an error occurred while running the runnable. + */ + public static void invokeAndWait(Runnable runnable) throws InterruptedException, + InvocationTargetException { + + if (isDispatchThread()) { + throw new Error(); + } + + final Toolkit toolkit = Toolkit.getDefaultToolkit(); + final Object notifier = new Object(); // $NON-LOCK-1$ + InvocationEvent event = new InvocationEvent(toolkit, runnable, notifier, true); + + synchronized (notifier) { + toolkit.getSystemEventQueueImpl().postEvent(event); + notifier.wait(); + } + + Exception exception = event.getException(); + + if (exception != null) { + throw new InvocationTargetException(exception); + } + } + + /** + * Gets the system event queue. + * + * @return the system event queue. + */ + private static EventQueue getSystemEventQueue() { + Thread th = Thread.currentThread(); + if (th instanceof EventDispatchThread) { + return ((EventDispatchThread)th).toolkit.getSystemEventQueueImpl(); + } + return null; + } + + /** + * Gets the most recent event's timestamp. This event was dispatched from + * the EventQueue associated with the calling thread. + * + * @return the timestamp of the last Event to be dispatched, or + * System.currentTimeMillis() if this method is invoked from a + * thread other than an event-dispatching thread. + */ + public static long getMostRecentEventTime() { + EventQueue eq = getSystemEventQueue(); + return (eq != null) ? eq.getMostRecentEventTimeImpl() : System.currentTimeMillis(); + } + + /** + * Gets the most recent event time impl. + * + * @return the most recent event time impl. + */ + private long getMostRecentEventTimeImpl() { + return getCore().getMostRecentEventTime(); + } + + /** + * Returns the the currently dispatched event by the EventQueue associated + * with the calling thread. + * + * @return the currently dispatched event or null if this method is invoked + * from a thread other than an event-dispatching thread. + */ + public static AWTEvent getCurrentEvent() { + EventQueue eq = getSystemEventQueue(); + return (eq != null) ? eq.getCurrentEventImpl() : null; + } + + /** + * Gets the current event impl. + * + * @return the current event impl. + */ + private AWTEvent getCurrentEventImpl() { + return getCore().getCurrentEvent(); + } + + /** + * Instantiates a new event queue. + */ + public EventQueue() { + setCore(new EventQueueCore(this)); + } + + /** + * Instantiates a new event queue. + * + * @param t + * the t. + */ + EventQueue(Toolkit t) { + setCore(new EventQueueCore(this, t)); + } + + /** + * Posts a event to the EventQueue. + * + * @param event + * AWTEvent. + */ + public void postEvent(AWTEvent event) { + event.isPosted = true; + getCore().postEvent(event); + } + + /** + * Returns an event from the EventQueue and removes it from this queue. + * + * @return the next AWTEvent. + * @throws InterruptedException + * is thrown if another thread interrupts this thread. + */ + public AWTEvent getNextEvent() throws InterruptedException { + return getCore().getNextEvent(); + } + + /** + * Gets the next event no wait. + * + * @return the next event no wait. + */ + AWTEvent getNextEventNoWait() { + return getCore().getNextEventNoWait(); + } + + /** + * Returns the first event of the EventQueue (without removing it from the + * queue). + * + * @return the the first AWT event of the EventQueue. + */ + public AWTEvent peekEvent() { + return getCore().peekEvent(); + } + + /** + * Returns the first event of the EventQueue with the specified ID (without + * removing it from the queue). + * + * @param id + * the type ID of event. + * @return the first event of the EventQueue with the specified ID. + */ + public AWTEvent peekEvent(int id) { + return getCore().peekEvent(id); + } + + /** + * Replaces the existing EventQueue with the specified EventQueue. Any + * pending events are transferred to the new EventQueue. + * + * @param newEventQueue + * the new event queue. + */ + public void push(EventQueue newEventQueue) { + getCore().push(newEventQueue); + } + + /** + * Stops dispatching events using this EventQueue. Any pending events are + * transferred to the previous EventQueue. + * + * @throws EmptyStackException + * is thrown if no previous push was made on this EventQueue. + */ + protected void pop() throws EmptyStackException { + getCore().pop(); + } + + /** + * Dispatches the specified event. + * + * @param event + * the AWTEvent. + */ + protected void dispatchEvent(AWTEvent event) { + getCore().dispatchEventImpl(event); + } + + /** + * Checks if the queue is empty. + * + * @return true, if is empty. + */ + boolean isEmpty() { + return getCore().isEmpty(); + } + + /** + * Gets the core. + * + * @return the core. + */ + EventQueueCore getCore() { + return coreRef.get(); + } + + /** + * Sets the core. + * + * @param newCore + * the new core. + */ + void setCore(EventQueueCore newCore) { + coreRef.set((newCore != null) ? newCore : new EventQueueCore(this)); + } +} diff --git a/awt/java/awt/EventQueueCore.java b/awt/java/awt/EventQueueCore.java new file mode 100644 index 0000000..ffc7c46 --- /dev/null +++ b/awt/java/awt/EventQueueCore.java @@ -0,0 +1,253 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt; + +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.InputMethodEvent; +import java.awt.event.InvocationEvent; +import java.awt.event.MouseEvent; +import java.util.LinkedList; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The events storage for EventQueue + */ +final class EventQueueCore { + + private final LinkedList<EventQueue> queueStack = new LinkedList<EventQueue>(); + private final LinkedList<AWTEvent> events = new LinkedList<AWTEvent>(); + + private Toolkit toolkit; + private EventQueue activeQueue; + private Thread dispatchThread; + + AWTEvent currentEvent; + long mostRecentEventTime = System.currentTimeMillis(); + + EventQueueCore(EventQueue eq) { + synchronized (this) { + queueStack.addLast(eq); + activeQueue = eq; + } + } + + EventQueueCore(EventQueue eq, Toolkit t) { + synchronized (this) { + queueStack.addLast(eq); + activeQueue = eq; + setToolkit(t); + } + } + + synchronized long getMostRecentEventTime() { + return mostRecentEventTime; + } + + synchronized AWTEvent getCurrentEvent() { + return currentEvent; + } + + synchronized boolean isSystemEventQueue() { + return toolkit != null; + } + + private void setToolkit(Toolkit t) { + toolkit = t; + if (toolkit != null) { + toolkit.setSystemEventQueueCore(this); + dispatchThread = toolkit.dispatchThread; + } + } + + synchronized void postEvent(AWTEvent event) { + //???AWT + /* + events.addLast(event); + if ((toolkit == null) && (dispatchThread == null)) { + dispatchThread = new EventQueueThread(this); + dispatchThread.start(); + } + // TODO: add event coalescing + if (toolkit != null) { + toolkit.shutdownWatchdog.setAwtQueueEmpty(false); + if (!GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance()) { + notifyEventMonitor(toolkit); + } + } + notifyAll(); + */ + } + + void notifyEventMonitor(Toolkit t) { + Object em = t.getNativeEventQueue().getEventMonitor(); + synchronized (em) { + em.notifyAll(); + } + } + + synchronized AWTEvent getNextEvent() throws InterruptedException { + while (events.isEmpty()) { + wait(); + } + AWTEvent event = events.removeFirst(); + // TODO: add event coalescing + return event; + } + + synchronized AWTEvent peekEvent() { + return events.isEmpty() ? null : events.getFirst(); + } + + synchronized AWTEvent peekEvent(int id) { + for (AWTEvent event : events) { + if (event.getID() == id) { + return event; + } + } + return null; + } + + synchronized void dispatchEvent(AWTEvent event) { + updateCurrentEventAndTime(event); + try { + activeQueue.dispatchEvent(event); + } finally { + currentEvent = null; + } + } + + void dispatchEventImpl(AWTEvent event) { + if (event instanceof ActiveEvent) { + updateCurrentEventAndTime(event); + try { + ((ActiveEvent) event).dispatch(); + } finally { + currentEvent = null; + } + return; + } + + Object src = event.getSource(); + + if (src instanceof Component) { + if (preprocessComponentEvent(event)) { + ((Component) src).dispatchEvent(event); + } + } else { + if (toolkit != null) { + toolkit.dispatchAWTEvent(event); + } + if (src instanceof MenuComponent) { + ((MenuComponent) src).dispatchEvent(event); + } + } + } + + private final boolean preprocessComponentEvent(AWTEvent event) { + if (event instanceof MouseEvent) { + return preprocessMouseEvent((MouseEvent)event); + } + return true; + } + + private final boolean preprocessMouseEvent(MouseEvent event) { + //???AWT + /* + if (toolkit != null && toolkit.mouseEventPreprocessor != null) { + toolkit.lockAWT(); + try { + return toolkit.mouseEventPreprocessor.preprocess(event); + } finally { + toolkit.unlockAWT(); + } + } + return true; + */ + return true; + } + + private void updateCurrentEventAndTime(AWTEvent event) { + currentEvent = event; + long when = 0; + if (event instanceof ActionEvent) { + when = ((ActionEvent) event).getWhen(); + } else if (event instanceof InputEvent) { + when = ((InputEvent) event).getWhen(); + } else if (event instanceof InputMethodEvent) { + when = ((InputMethodEvent) event).getWhen(); + } else if (event instanceof InvocationEvent) { + when = ((InvocationEvent) event).getWhen(); + } + if (when != 0) { + mostRecentEventTime = when; + } + } + + synchronized void push(EventQueue newEventQueue) { + // TODO: handle incorrect situations + if (queueStack.isEmpty()) { + // awt.6B=Queue stack is empty + throw new IllegalStateException(Messages.getString("awt.6B")); //$NON-NLS-1$ + } + + queueStack.addLast(newEventQueue); + activeQueue = newEventQueue; + activeQueue.setCore(this); + } + + synchronized void pop() { + EventQueue removed = queueStack.removeLast(); + if (removed != activeQueue) { + // awt.6C=Event queue stack is broken + throw new IllegalStateException(Messages.getString("awt.6C")); //$NON-NLS-1$ + } + activeQueue = queueStack.getLast(); + removed.setCore(null); + } + + synchronized AWTEvent getNextEventNoWait() { + try { + return events.isEmpty() ? null : activeQueue.getNextEvent(); + } catch (InterruptedException e) { + return null; + } + } + + synchronized boolean isEmpty() { + return (currentEvent == null) && events.isEmpty(); + } + + synchronized boolean isEmpty(long timeout) { + if (!isEmpty()) { + return false; + } + try { + wait(timeout); + } catch (InterruptedException e) {} + return isEmpty(); + } + + synchronized EventQueue getActiveEventQueue() { + return activeQueue; + } +} diff --git a/awt/java/awt/Font.java b/awt/java/awt/Font.java new file mode 100644 index 0000000..4ed9343 --- /dev/null +++ b/awt/java/awt/Font.java @@ -0,0 +1,1541 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.awt; + +import com.android.internal.awt.AndroidGraphics2D; + +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.LineMetrics; +import java.awt.font.TextAttribute; +import java.awt.font.TransformAttribute; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.io.File; +import java.io.FileInputStream; +import java.io.BufferedInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.text.CharacterIterator; +import java.text.AttributedCharacterIterator.Attribute; +import java.util.Hashtable; +import java.util.Locale; +import java.util.Map; +import java.util.StringTokenizer; + +import org.apache.harmony.awt.gl.font.AndroidGlyphVector; +import org.apache.harmony.awt.gl.font.CommonGlyphVector; +import org.apache.harmony.awt.gl.font.FontPeerImpl; +import org.apache.harmony.awt.gl.font.FontMetricsImpl; +import org.apache.harmony.awt.gl.font.LineMetricsImpl; +import org.apache.harmony.awt.internal.nls.Messages; +import org.apache.harmony.luni.util.NotImplementedException; +import org.apache.harmony.misc.HashCode; + +/** + * The Font class represents fonts for rendering text. This class allow to map + * characters to glyphs. + * <p> + * A glyph is a shape used to render a character or a sequence of characters. + * For example one character of Latin writing system represented by one glyph, + * but in complex writing system such as South and South-East Asian there is + * more complicated correspondence between characters and glyphs. + * <p> + * The Font object is identified by two types of names. The logical font name is + * the name that is used to construct the font. The font name is the name of a + * particular font face (for example, Arial Bold). The family name is the font's + * family name that specifies the typographic design across several faces (for + * example, Arial). In all the Font is identified by three attributes: the + * family name, the style (such as bold or italic), and the size. + * + * @since Android 1.0 + */ +public class Font implements Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -4206021311591459213L; + + // Identity Transform attribute + /** + * The Constant IDENTITY_TRANSFORM. + */ + private static final TransformAttribute IDENTITY_TRANSFORM = new TransformAttribute( + new AffineTransform()); + + /** + * The Constant PLAIN indicates font's plain style. + */ + public static final int PLAIN = 0; + + /** + * The Constant BOLD indicates font's bold style. + */ + public static final int BOLD = 1; + + /** + * The Constant ITALIC indicates font's italic style. + */ + public static final int ITALIC = 2; + + /** + * The Constant ROMAN_BASELINE indicated roman baseline. + */ + public static final int ROMAN_BASELINE = 0; + + /** + * The Constant CENTER_BASELINE indicates center baseline. + */ + public static final int CENTER_BASELINE = 1; + + /** + * The Constant HANGING_BASELINE indicates hanging baseline. + */ + public static final int HANGING_BASELINE = 2; + + /** + * The Constant TRUETYPE_FONT indicates a font resource of type TRUETYPE. + */ + public static final int TRUETYPE_FONT = 0; + + /** + * The Constant TYPE1_FONT indicates a font resource of type TYPE1. + */ + public static final int TYPE1_FONT = 1; + + /** + * The Constant LAYOUT_LEFT_TO_RIGHT indicates that text is left to right. + */ + public static final int LAYOUT_LEFT_TO_RIGHT = 0; + + /** + * The Constant LAYOUT_RIGHT_TO_LEFT indicates that text is right to left. + */ + public static final int LAYOUT_RIGHT_TO_LEFT = 1; + + /** + * The Constant LAYOUT_NO_START_CONTEXT indicates that the text in the char + * array before the indicated start should not be examined. + */ + public static final int LAYOUT_NO_START_CONTEXT = 2; + + /** + * The Constant LAYOUT_NO_LIMIT_CONTEXT indicates that text in the char + * array after the indicated limit should not be examined. + */ + public static final int LAYOUT_NO_LIMIT_CONTEXT = 4; + + /** + * The Constant DEFAULT_FONT. + */ + static final Font DEFAULT_FONT = new Font("Dialog", Font.PLAIN, 12); //$NON-NLS-1$ + + /** + * The name of the Font. + */ + protected String name; + + /** + * The style of the Font. + */ + protected int style; + + /** + * The size of the Font. + */ + protected int size; + + /** + * The point size of the Font. + */ + protected float pointSize; + + // Flag if the Font object transformed + /** + * The transformed. + */ + private boolean transformed; + + // Set of font attributes + /** + * The requested attributes. + */ + private Hashtable<Attribute, Object> fRequestedAttributes; + + // font peer object corresponding to this Font + /** + * The font peer. + */ + private transient FontPeerImpl fontPeer; + + // number of glyphs in this Font + /** + * The num glyphs. + */ + private transient int numGlyphs = -1; + + // code for missing glyph for this Font + /** + * The missing glyph code. + */ + private transient int missingGlyphCode = -1; + + /** + * Writes object to ObjectOutputStream. + * + * @param out + * ObjectOutputStream. + * @throws IOException + * Signals that an I/O exception has occurred. + */ + private void writeObject(java.io.ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + } + + /** + * Reads object from ObjectInputStream object and set native platform + * dependent fields to default values. + * + * @param in + * ObjectInputStream object. + * @throws IOException + * Signals that an I/O exception has occurred. + * @throws ClassNotFoundException + * the class not found exception. + */ + private void readObject(java.io.ObjectInputStream in) throws IOException, + ClassNotFoundException { + in.defaultReadObject(); + + numGlyphs = -1; + missingGlyphCode = -1; + + } + + /** + * Instantiates a new Font with the specified attributes. The Font will be + * created with default attributes if the attribute's parameter is null. + * + * @param attributes + * the attributes to be assigned to the new Font, or null. + */ + public Font(Map<? extends Attribute, ?> attributes) { + Object currAttr; + + // Default values are taken from the documentation of the Font class. + // See Font constructor, decode and getFont sections. + + this.name = "default"; //$NON-NLS-1$ + this.size = 12; + this.pointSize = 12; + this.style = Font.PLAIN; + + if (attributes != null) { + + fRequestedAttributes = new Hashtable<Attribute, Object>(attributes); + + currAttr = attributes.get(TextAttribute.SIZE); + if (currAttr != null) { + this.pointSize = ((Float)currAttr).floatValue(); + this.size = (int)Math.ceil(this.pointSize); + } + + currAttr = attributes.get(TextAttribute.POSTURE); + if (currAttr != null && currAttr.equals(TextAttribute.POSTURE_OBLIQUE)) { + this.style |= Font.ITALIC; + } + + currAttr = attributes.get(TextAttribute.WEIGHT); + if ((currAttr != null) + && (((Float)currAttr).floatValue() >= (TextAttribute.WEIGHT_BOLD).floatValue())) { + this.style |= Font.BOLD; + } + + currAttr = attributes.get(TextAttribute.FAMILY); + if (currAttr != null) { + this.name = (String)currAttr; + } + + currAttr = attributes.get(TextAttribute.TRANSFORM); + if (currAttr != null) { + if (currAttr instanceof TransformAttribute) { + this.transformed = !((TransformAttribute)currAttr).getTransform().isIdentity(); + } else if (currAttr instanceof AffineTransform) { + this.transformed = !((AffineTransform)currAttr).isIdentity(); + } + } + + } else { + fRequestedAttributes = new Hashtable<Attribute, Object>(5); + fRequestedAttributes.put(TextAttribute.TRANSFORM, IDENTITY_TRANSFORM); + + this.transformed = false; + + fRequestedAttributes.put(TextAttribute.FAMILY, name); + + fRequestedAttributes.put(TextAttribute.SIZE, new Float(this.size)); + + if ((this.style & Font.BOLD) != 0) { + fRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); + } else { + fRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_REGULAR); + } + if ((this.style & Font.ITALIC) != 0) { + fRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); + } else { + fRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_REGULAR); + } + + } + } + + /** + * Instantiates a new Font with the specified name, style and size. + * + * @param name + * the name of font. + * @param style + * the style of font. + * @param size + * the size of font. + */ + public Font(String name, int style, int size) { + + this.name = (name != null) ? name : "Default"; //$NON-NLS-1$ + this.size = (size >= 0) ? size : 0; + this.style = (style & ~0x03) == 0 ? style : Font.PLAIN; + this.pointSize = this.size; + + fRequestedAttributes = new Hashtable<Attribute, Object>(5); + + fRequestedAttributes.put(TextAttribute.TRANSFORM, IDENTITY_TRANSFORM); + + this.transformed = false; + + fRequestedAttributes.put(TextAttribute.FAMILY, this.name); + fRequestedAttributes.put(TextAttribute.SIZE, new Float(this.size)); + + if ((this.style & Font.BOLD) != 0) { + fRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); + } else { + fRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_REGULAR); + } + if ((this.style & Font.ITALIC) != 0) { + fRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); + } else { + fRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_REGULAR); + } + } + + /** + * Returns true if this Font has a glyph for the specified character. + * + * @param c + * the character. + * @return true if this Font has a glyph for the specified character, false + * otherwise. + */ + public boolean canDisplay(char c) { + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); + return peer.canDisplay(c); + } + + /** + * Returns true if the Font can display the characters of the the specified + * text from the specified start position to the specified limit position. + * + * @param text + * the text. + * @param start + * the start offset (in the character array). + * @param limit + * the limit offset (in the character array). + * @return the a character's position in the text that this Font can not + * display, or -1 if this Font can display all characters in this + * text. + */ + public int canDisplayUpTo(char[] text, int start, int limit) { + int st = start; + int result; + while ((st < limit) && canDisplay(text[st])) { + st++; + } + + if (st == limit) { + result = -1; + } else { + result = st; + } + + return result; + } + + /** + * Returns true if the Font can display the characters of the the specified + * CharacterIterator from the specified start position and the specified + * limit position. + * + * @param iter + * the CharacterIterator. + * @param start + * the start offset. + * @param limit + * the limit offset. + * @return the a character's position in the CharacterIterator that this + * Font can not display, or -1 if this Font can display all + * characters in this text. + */ + public int canDisplayUpTo(CharacterIterator iter, int start, int limit) { + int st = start; + char c = iter.setIndex(start); + int result; + + while ((st < limit) && (canDisplay(c))) { + st++; + c = iter.next(); + } + if (st == limit) { + result = -1; + } else { + result = st; + } + + return result; + } + + /** + * Returns true if this Font can display a specified String. + * + * @param str + * the String. + * @return the a character's position in the String that this Font can not + * display, or -1 if this Font can display all characters in this + * text. + */ + public int canDisplayUpTo(String str) { + char[] chars = str.toCharArray(); + return canDisplayUpTo(chars, 0, chars.length); + } + + /** + * Creates a GlyphVector of associating characters to glyphs based on the + * Unicode map of this Font. + * + * @param frc + * the FontRenderContext. + * @param chars + * the characters array. + * @return the GlyphVector of associating characters to glyphs based on the + * Unicode map of this Font. + */ + public GlyphVector createGlyphVector(FontRenderContext frc, char[] chars) { + return new AndroidGlyphVector(chars, frc, this, 0); + } + + /** + * Creates a GlyphVector of associating characters contained in the + * specified CharacterIterator to glyphs based on the Unicode map of this + * Font. + * + * @param frc + * the FontRenderContext. + * @param iter + * the CharacterIterator. + * @return the GlyphVector of associating characters contained in the + * specified CharacterIterator to glyphs based on the Unicode map of + * this Font. + */ + public GlyphVector createGlyphVector(FontRenderContext frc, CharacterIterator iter) { + throw new RuntimeException("Not implemented!"); //$NON-NLS-1$ + } + + /** + * Creates a GlyphVector of associating characters to glyphs based on the + * Unicode map of this Font. + * + * @param frc + * the FontRenderContext. + * @param glyphCodes + * the specified integer array of glyph codes. + * @return the GlyphVector of associating characters to glyphs based on the + * Unicode map of this Font. + * @throws NotImplementedException + * if this method is not implemented by a subclass. + */ + public GlyphVector createGlyphVector(FontRenderContext frc, int[] glyphCodes) + throws org.apache.harmony.luni.util.NotImplementedException { + throw new RuntimeException("Not implemented!"); //$NON-NLS-1$ + } + + /** + * Creates a GlyphVector of associating characters to glyphs based on the + * Unicode map of this Font. + * + * @param frc + * the FontRenderContext. + * @param str + * the specified String. + * @return the GlyphVector of associating characters to glyphs based on the + * Unicode map of this Font. + */ + public GlyphVector createGlyphVector(FontRenderContext frc, String str) { + return new AndroidGlyphVector(str.toCharArray(), frc, this, 0); + + } + + /** + * Returns the font style constant value corresponding to one of the font + * style names ("BOLD", "ITALIC", "BOLDITALIC"). This method returns + * Font.PLAIN if the argument is not one of the predefined style names. + * + * @param fontStyleName + * font style name. + * @return font style constant value corresponding to the font style name + * specified. + */ + private static int getFontStyle(String fontStyleName) { + int result = Font.PLAIN; + + if (fontStyleName.toUpperCase().equals("BOLDITALIC")) { //$NON-NLS-1$ + result = Font.BOLD | Font.ITALIC; + } else if (fontStyleName.toUpperCase().equals("BOLD")) { //$NON-NLS-1$ + result = Font.BOLD; + } else if (fontStyleName.toUpperCase().equals("ITALIC")) { //$NON-NLS-1$ + result = Font.ITALIC; + } + + return result; + } + + /** + * Decodes the specified string which described the Font. The string should + * have the following format: fontname-style-pointsize. The style can be + * PLAIN, BOLD, BOLDITALIC, or ITALIC. + * + * @param str + * the string which describes the font. + * @return the Font from the specified string. + */ + public static Font decode(String str) { + // XXX: Documentation doesn't describe all cases, e.g. fonts face names + // with + // symbols that are suggested as delimiters in the documentation. + // In this decode implementation only ***-***-*** format is used with + // '-' + // as the delimiter to avoid unexpected parse results of font face names + // with spaces. + + if (str == null) { + return DEFAULT_FONT; + } + + StringTokenizer strTokens; + String delim = "-"; //$NON-NLS-1$ + String substr; + + int fontSize = DEFAULT_FONT.size; + int fontStyle = DEFAULT_FONT.style; + String fontName = DEFAULT_FONT.name; + + strTokens = new StringTokenizer(str.trim(), delim); + + // Font Name + if (strTokens.hasMoreTokens()) { + fontName = strTokens.nextToken(); // first token is the font name + } + + // Font Style or Size (if the style is undefined) + if (strTokens.hasMoreTokens()) { + substr = strTokens.nextToken(); + + try { + // if second token is the font size + fontSize = Integer.parseInt(substr); + } catch (NumberFormatException e) { + // then second token is the font style + fontStyle = getFontStyle(substr); + } + + } + + // Font Size + if (strTokens.hasMoreTokens()) { + try { + fontSize = Integer.parseInt(strTokens.nextToken()); + } catch (NumberFormatException e) { + } + } + + return new Font(fontName, fontStyle, fontSize); + } + + /** + * Performs the specified affine transform to the Font and returns a new + * Font. + * + * @param trans + * the AffineTransform. + * @return the Font object. + * @throws IllegalArgumentException + * if affine transform parameter is null. + */ + @SuppressWarnings("unchecked") + public Font deriveFont(AffineTransform trans) { + + if (trans == null) { + // awt.94=transform can not be null + throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$ + } + + Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>)fRequestedAttributes + .clone(); + + derivefRequestedAttributes.put(TextAttribute.TRANSFORM, new TransformAttribute(trans)); + + return new Font(derivefRequestedAttributes); + + } + + /** + * Returns a new Font that is a copy of the current Font modified so that + * the size is the specified size. + * + * @param size + * the size of font. + * @return the Font object. + */ + @SuppressWarnings("unchecked") + public Font deriveFont(float size) { + Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>)fRequestedAttributes + .clone(); + derivefRequestedAttributes.put(TextAttribute.SIZE, new Float(size)); + return new Font(derivefRequestedAttributes); + } + + /** + * Returns a new Font that is a copy of the current Font modified so that + * the style is the specified style. + * + * @param style + * the style of font. + * @return the Font object. + */ + @SuppressWarnings("unchecked") + public Font deriveFont(int style) { + Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>)fRequestedAttributes + .clone(); + + if ((style & Font.BOLD) != 0) { + derivefRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); + } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) { + derivefRequestedAttributes.remove(TextAttribute.WEIGHT); + } + + if ((style & Font.ITALIC) != 0) { + derivefRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); + } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) { + derivefRequestedAttributes.remove(TextAttribute.POSTURE); + } + + return new Font(derivefRequestedAttributes); + } + + /** + * Returns a new Font that is a copy of the current Font modified to match + * the specified style and with the specified affine transform applied to + * its glyphs. + * + * @param style + * the style of font. + * @param trans + * the AffineTransform. + * @return the Font object. + */ + @SuppressWarnings("unchecked") + public Font deriveFont(int style, AffineTransform trans) { + + if (trans == null) { + // awt.94=transform can not be null + throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$ + } + Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>)fRequestedAttributes + .clone(); + + if ((style & BOLD) != 0) { + derivefRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); + } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) { + derivefRequestedAttributes.remove(TextAttribute.WEIGHT); + } + + if ((style & ITALIC) != 0) { + derivefRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); + } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) { + derivefRequestedAttributes.remove(TextAttribute.POSTURE); + } + derivefRequestedAttributes.put(TextAttribute.TRANSFORM, new TransformAttribute(trans)); + + return new Font(derivefRequestedAttributes); + } + + /** + * Returns a new Font that is a copy of the current Font modified so that + * the size and style are the specified size and style. + * + * @param style + * the style of font. + * @param size + * the size of font. + * @return the Font object. + */ + @SuppressWarnings("unchecked") + public Font deriveFont(int style, float size) { + Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>)fRequestedAttributes + .clone(); + + if ((style & BOLD) != 0) { + derivefRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); + } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) { + derivefRequestedAttributes.remove(TextAttribute.WEIGHT); + } + + if ((style & ITALIC) != 0) { + derivefRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); + } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) { + derivefRequestedAttributes.remove(TextAttribute.POSTURE); + } + + derivefRequestedAttributes.put(TextAttribute.SIZE, new Float(size)); + return new Font(derivefRequestedAttributes); + + } + + /** + * Returns a new Font object with a new set of font attributes. + * + * @param attributes + * the map of attributes. + * @return the Font. + */ + @SuppressWarnings("unchecked") + public Font deriveFont(Map<? extends Attribute, ?> attributes) { + Attribute[] avalAttributes = this.getAvailableAttributes(); + + Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>)fRequestedAttributes + .clone(); + Object currAttribute; + for (Attribute element : avalAttributes) { + currAttribute = attributes.get(element); + if (currAttribute != null) { + derivefRequestedAttributes.put(element, currAttribute); + } + } + return new Font(derivefRequestedAttributes); + } + + /** + * Compares the specified Object with the current Font. + * + * @param obj + * the Object to be compared. + * @return true, if the specified Object is an instance of Font with the + * same family, size, and style as this Font, false otherwise. + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + + if (obj != null) { + try { + Font font = (Font)obj; + + return ((this.style == font.style) && (this.size == font.size) + && this.name.equals(font.name) && (this.pointSize == font.pointSize) && (this + .getTransform()).equals(font.getTransform())); + } catch (ClassCastException e) { + } + } + + return false; + } + + /** + * Gets the map of font's attributes. + * + * @return the map of font's attributes. + */ + @SuppressWarnings("unchecked") + public Map<TextAttribute, ?> getAttributes() { + return (Map<TextAttribute, ?>)fRequestedAttributes.clone(); + } + + /** + * Gets the keys of all available attributes. + * + * @return the keys array of all available attributes. + */ + public Attribute[] getAvailableAttributes() { + Attribute[] attrs = { + TextAttribute.FAMILY, TextAttribute.POSTURE, TextAttribute.SIZE, + TextAttribute.TRANSFORM, TextAttribute.WEIGHT, TextAttribute.SUPERSCRIPT, + TextAttribute.WIDTH + }; + return attrs; + } + + /** + * Gets the baseline for this character. + * + * @param c + * the character. + * @return the baseline for this character. + */ + public byte getBaselineFor(char c) { + // TODO: implement using TT BASE table data + return 0; + } + + /** + * Gets the family name of the Font. + * + * @return the family name of the Font. + */ + public String getFamily() { + if (fRequestedAttributes != null) { + fRequestedAttributes.get(TextAttribute.FAMILY); + } + return null; + } + + /** + * Returns the family name of this Font associated with the specified + * locale. + * + * @param l + * the locale. + * @return the family name of this Font associated with the specified + * locale. + */ + public String getFamily(Locale l) { + if (l == null) { + // awt.01='{0}' parameter is null + throw new NullPointerException(Messages.getString("awt.01", "Locale")); //$NON-NLS-1$ //$NON-NLS-2$ + } + return getFamily(); + } + + /** + * Gets a Font with the specified attribute set. + * + * @param attributes + * the attributes to be assigned to the new Font. + * @return the Font. + */ + public static Font getFont(Map<? extends Attribute, ?> attributes) { + Font fnt = (Font)attributes.get(TextAttribute.FONT); + if (fnt != null) { + return fnt; + } + return new Font(attributes); + } + + /** + * Gets a Font object from the system properties list with the specified + * name or returns the specified Font if there is no such property. + * + * @param sp + * the specified property name. + * @param f + * the Font. + * @return the Font object from the system properties list with the + * specified name or the specified Font if there is no such + * property. + */ + public static Font getFont(String sp, Font f) { + String pr = System.getProperty(sp); + if (pr == null) { + return f; + } + return decode(pr); + } + + /** + * Gets a Font object from the system properties list with the specified + * name. + * + * @param sp + * the system property name. + * @return the Font, or null if there is no such property with the specified + * name. + */ + public static Font getFont(String sp) { + return getFont(sp, null); + } + + /** + * Gets the font name. + * + * @return the font name. + */ + public String getFontName() { + if (fRequestedAttributes != null) { + fRequestedAttributes.get(TextAttribute.FAMILY); + } + return null; + } + + /** + * Returns the font name associated with the specified locale. + * + * @param l + * the locale. + * @return the font name associated with the specified locale. + */ + public String getFontName(Locale l) { + return getFamily(); + } + + /** + * Returns a LineMetrics object created with the specified parameters. + * + * @param chars + * the chars array. + * @param start + * the start offset. + * @param end + * the end offset. + * @param frc + * the FontRenderContext. + * @return the LineMetrics for the specified parameters. + */ + public LineMetrics getLineMetrics(char[] chars, int start, int end, FontRenderContext frc) { + if (frc == null) { + // awt.00=FontRenderContext is null + throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$ + } + + // FontMetrics fm = AndroidGraphics2D.getInstance().getFontMetrics(); + FontMetrics fm = new FontMetricsImpl(this); + float[] fmet = { + fm.getAscent(), fm.getDescent(), fm.getLeading() + }; + return new LineMetricsImpl(chars.length, fmet, null); + } + + /** + * Returns a LineMetrics object created with the specified parameters. + * + * @param iter + * the CharacterIterator. + * @param start + * the start offset. + * @param end + * the end offset. + * @param frc + * the FontRenderContext. + * @return the LineMetrics for the specified parameters. + */ + public LineMetrics getLineMetrics(CharacterIterator iter, int start, int end, + FontRenderContext frc) { + + if (frc == null) { + // awt.00=FontRenderContext is null + throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$ + } + + String resultString; + int iterCount; + + iterCount = end - start; + if (iterCount < 0) { + resultString = ""; //$NON-NLS-1$ + } else { + char[] chars = new char[iterCount]; + int i = 0; + for (char c = iter.setIndex(start); c != CharacterIterator.DONE && (i < iterCount); c = iter + .next()) { + chars[i] = c; + i++; + } + resultString = new String(chars); + } + return this.getLineMetrics(resultString, frc); + } + + /** + * Returns a LineMetrics object created with the specified parameters. + * + * @param str + * the String. + * @param frc + * the FontRenderContext. + * @return the LineMetrics for the specified parameters. + */ + public LineMetrics getLineMetrics(String str, FontRenderContext frc) { + // FontMetrics fm = AndroidGraphics2D.getInstance().getFontMetrics(); + FontMetrics fm = new FontMetricsImpl(this); + float[] fmet = { + fm.getAscent(), fm.getDescent(), fm.getLeading() + }; + // Log.i("FONT FMET", fmet.toString()); + return new LineMetricsImpl(str.length(), fmet, null); + + } + + /** + * Returns a LineMetrics object created with the specified parameters. + * + * @param str + * the String. + * @param start + * the start offset. + * @param end + * the end offset. + * @param frc + * the FontRenderContext. + * @return the LineMetrics for the specified parameters. + */ + public LineMetrics getLineMetrics(String str, int start, int end, FontRenderContext frc) { + return this.getLineMetrics(str.substring(start, end), frc); + } + + /** + * Gets the logical bounds of the specified String in the specified + * FontRenderContext. The logical bounds contains the origin, ascent, + * advance, and height. + * + * @param ci + * the specified CharacterIterator. + * @param start + * the start offset. + * @param end + * the end offset. + * @param frc + * the FontRenderContext. + * @return a Rectangle2D object. + */ + public Rectangle2D getStringBounds(CharacterIterator ci, int start, int end, + FontRenderContext frc) { + int first = ci.getBeginIndex(); + int finish = ci.getEndIndex(); + char[] chars; + + if (start < first) { + // awt.95=Wrong start index: {0} + throw new IndexOutOfBoundsException(Messages.getString("awt.95", start)); //$NON-NLS-1$ + } + if (end > finish) { + // awt.96=Wrong finish index: {0} + throw new IndexOutOfBoundsException(Messages.getString("awt.96", end)); //$NON-NLS-1$ + } + if (start > end) { + // awt.97=Wrong range length: {0} + throw new IndexOutOfBoundsException(Messages.getString("awt.97", //$NON-NLS-1$ + (end - start))); + } + + if (frc == null) { + throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$ + } + + chars = new char[end - start]; + + ci.setIndex(start); + for (int i = 0; i < chars.length; i++) { + chars[i] = ci.current(); + ci.next(); + } + + return this.getStringBounds(chars, 0, chars.length, frc); + + } + + /** + * Gets the logical bounds of the specified String in the specified + * FontRenderContext. The logical bounds contains the origin, ascent, + * advance, and height. + * + * @param str + * the specified String. + * @param frc + * the FontRenderContext. + * @return a Rectangle2D object. + */ + public Rectangle2D getStringBounds(String str, FontRenderContext frc) { + char[] chars = str.toCharArray(); + return this.getStringBounds(chars, 0, chars.length, frc); + + } + + /** + * Gets the logical bounds of the specified String in the specified + * FontRenderContext. The logical bounds contains the origin, ascent, + * advance, and height. + * + * @param str + * the specified String. + * @param start + * the start offset. + * @param end + * the end offset. + * @param frc + * the FontRenderContext. + * @return a Rectangle2D object. + */ + public Rectangle2D getStringBounds(String str, int start, int end, FontRenderContext frc) { + + return this.getStringBounds((str.substring(start, end)), frc); + } + + /** + * Gets the logical bounds of the specified String in the specified + * FontRenderContext. The logical bounds contains the origin, ascent, + * advance, and height. + * + * @param chars + * the specified character array. + * @param start + * the start offset. + * @param end + * the end offset. + * @param frc + * the FontRenderContext. + * @return a Rectangle2D object. + */ + public Rectangle2D getStringBounds(char[] chars, int start, int end, FontRenderContext frc) { + if (start < 0) { + // awt.95=Wrong start index: {0} + throw new IndexOutOfBoundsException(Messages.getString("awt.95", start)); //$NON-NLS-1$ + } + if (end > chars.length) { + // awt.96=Wrong finish index: {0} + throw new IndexOutOfBoundsException(Messages.getString("awt.96", end)); //$NON-NLS-1$ + } + if (start > end) { + // awt.97=Wrong range length: {0} + throw new IndexOutOfBoundsException(Messages.getString("awt.97", //$NON-NLS-1$ + (end - start))); + } + + if (frc == null) { + throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$ + } + + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); + + final int TRANSFORM_MASK = AffineTransform.TYPE_GENERAL_ROTATION + | AffineTransform.TYPE_GENERAL_TRANSFORM; + Rectangle2D bounds; + + AffineTransform transform = getTransform(); + + // XXX: for transforms where an angle between basis vectors is not 90 + // degrees Rectanlge2D class doesn't fit as Logical bounds. + if ((transform.getType() & TRANSFORM_MASK) == 0) { + int width = 0; + for (int i = start; i < end; i++) { + width += peer.charWidth(chars[i]); + } + // LineMetrics nlm = peer.getLineMetrics(); + + LineMetrics nlm = getLineMetrics(chars, start, end, frc); + + bounds = transform.createTransformedShape( + new Rectangle2D.Float(0, -nlm.getAscent(), width, nlm.getHeight())) + .getBounds2D(); + } else { + int len = end - start; + char[] subChars = new char[len]; + System.arraycopy(chars, start, subChars, 0, len); + bounds = createGlyphVector(frc, subChars).getLogicalBounds(); + } + return bounds; + } + + /** + * Gets the character's maximum bounds as defined in the specified + * FontRenderContext. + * + * @param frc + * the FontRenderContext. + * @return the character's maximum bounds. + */ + public Rectangle2D getMaxCharBounds(FontRenderContext frc) { + if (frc == null) { + // awt.00=FontRenderContext is null + throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$ + } + + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); + + Rectangle2D bounds = peer.getMaxCharBounds(frc); + AffineTransform transform = getTransform(); + // !! Documentation doesn't describe meaning of max char bounds + // for the fonts that have rotate transforms. For all transforms + // returned bounds are the bounds of transformed maxCharBounds + // Rectangle2D that corresponds to the font with identity transform. + // TODO: resolve this issue to return correct bounds + bounds = transform.createTransformedShape(bounds).getBounds2D(); + + return bounds; + } + + /** + * Returns a new GlyphVector object performing full layout of the text. + * + * @param frc + * the FontRenderContext. + * @param chars + * the character array to be layout. + * @param start + * the start offset of the text to use for the GlyphVector. + * @param count + * the count of characters to use for the GlyphVector. + * @param flags + * the flag indicating text direction: LAYOUT_RIGHT_TO_LEFT, + * LAYOUT_LEFT_TO_RIGHT. + * @return the GlyphVector. + */ + public GlyphVector layoutGlyphVector(FontRenderContext frc, char[] chars, int start, int count, + int flags) { + // TODO: implement method for bidirectional text. + // At the moment only LTR and RTL texts supported. + if (start < 0) { + // awt.95=Wrong start index: {0} + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.95", //$NON-NLS-1$ + start)); + } + + if (count < 0) { + // awt.98=Wrong count value, can not be negative: {0} + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.98", //$NON-NLS-1$ + count)); + } + + if (start + count > chars.length) { + // awt.99=Wrong [start + count] is out of range: {0} + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.99", //$NON-NLS-1$ + (start + count))); + } + + char[] out = new char[count]; + System.arraycopy(chars, start, out, 0, count); + + return new CommonGlyphVector(out, frc, this, flags); + } + + /** + * Returns the String representation of this Font. + * + * @return the String representation of this Font. + */ + @Override + public String toString() { + String stl = "plain"; //$NON-NLS-1$ + String result; + + if (this.isBold() && this.isItalic()) { + stl = "bolditalic"; //$NON-NLS-1$ + } + if (this.isBold() && !this.isItalic()) { + stl = "bold"; //$NON-NLS-1$ + } + + if (!this.isBold() && this.isItalic()) { + stl = "italic"; //$NON-NLS-1$ + } + + result = this.getClass().getName() + "[family=" + this.getFamily() + //$NON-NLS-1$ + ",name=" + this.name + //$NON-NLS-1$ + ",style=" + stl + //$NON-NLS-1$ + ",size=" + this.size + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + return result; + } + + /** + * Gets the postscript name of this Font. + * + * @return the postscript name of this Font. + */ + public String getPSName() { + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); + return peer.getPSName(); + } + + /** + * Gets the logical name of this Font. + * + * @return the logical name of this Font. + */ + public String getName() { + return (this.name); + } + + /** + * Gets the peer of this Font. + * + * @return the peer of this Font. + * @deprecated Font rendering is platform independent now. + */ + @Deprecated + public java.awt.peer.FontPeer getPeer() { + if (fontPeer == null) { + fontPeer = (FontPeerImpl)Toolkit.getDefaultToolkit().getGraphicsFactory().getFontPeer( + this); + } + return fontPeer; + + } + + /** + * Gets the transform acting on this Font (from the Font's attributes). + * + * @return the transformation of this Font. + */ + public AffineTransform getTransform() { + Object transform = fRequestedAttributes.get(TextAttribute.TRANSFORM); + + if (transform != null) { + if (transform instanceof TransformAttribute) { + return ((TransformAttribute)transform).getTransform(); + } + if (transform instanceof AffineTransform) { + return new AffineTransform((AffineTransform)transform); + } + } else { + transform = new AffineTransform(); + } + return (AffineTransform)transform; + + } + + /** + * Checks if this font is transformed or not. + * + * @return true, if this font is transformed, false otherwise. + */ + public boolean isTransformed() { + return this.transformed; + } + + /** + * Checks if this font has plain style or not. + * + * @return true, if this font has plain style, false otherwise. + */ + public boolean isPlain() { + return (this.style == PLAIN); + } + + /** + * Checks if this font has italic style or not. + * + * @return true, if this font has italic style, false otherwise. + */ + public boolean isItalic() { + return (this.style & ITALIC) != 0; + } + + /** + * Checks if this font has bold style or not. + * + * @return true, if this font has bold style, false otherwise. + */ + public boolean isBold() { + return (this.style & BOLD) != 0; + } + + /** + * Returns true if this Font has uniform line metrics. + * + * @return true if this Font has uniform line metrics, false otherwise. + */ + public boolean hasUniformLineMetrics() { + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); + return peer.hasUniformLineMetrics(); + } + + /** + * Returns hash code of this Font object. + * + * @return the hash code of this Font object. + */ + @Override + public int hashCode() { + HashCode hash = new HashCode(); + + hash.append(this.name); + hash.append(this.style); + hash.append(this.size); + + return hash.hashCode(); + } + + /** + * Gets the style of this Font. + * + * @return the style of this Font. + */ + public int getStyle() { + return this.style; + } + + /** + * Gets the size of this Font. + * + * @return the size of this Font. + */ + public int getSize() { + return this.size; + } + + /** + * Gets the number of glyphs for this Font. + * + * @return the number of glyphs for this Font. + */ + public int getNumGlyphs() { + if (numGlyphs == -1) { + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); + this.numGlyphs = peer.getNumGlyphs(); + } + return this.numGlyphs; + } + + /** + * Gets the glyphCode which is used as default glyph when this Font does not + * have a glyph for a specified Unicode. + * + * @return the missing glyph code. + */ + public int getMissingGlyphCode() { + if (missingGlyphCode == -1) { + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); + this.missingGlyphCode = peer.getMissingGlyphCode(); + } + return this.missingGlyphCode; + } + + /** + * Gets the float value of font's size. + * + * @return the float value of font's size. + */ + public float getSize2D() { + return this.pointSize; + } + + /** + * Gets the italic angle of this Font. + * + * @return the italic angle of this Font. + */ + public float getItalicAngle() { + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); + return peer.getItalicAngle(); + } + + /** + * Creates the font with the specified font format and font file. + * + * @param fontFormat + * the font format. + * @param fontFile + * the file object represented the input data for the font. + * @return the Font. + * @throws FontFormatException + * is thrown if fontFile does not contain the required font + * tables for the specified format. + * @throws IOException + * signals that an I/O exception has occurred. + */ + public static Font createFont(int fontFormat, File fontFile) throws FontFormatException, + IOException { + // ???AWT not supported + InputStream is = new FileInputStream(fontFile); + try { + return createFont(fontFormat, is); + } finally { + is.close(); + } + } + + /** + * Creates the font with the specified font format and input stream. + * + * @param fontFormat + * the font format. + * @param fontStream + * the input stream represented input data for the font. + * @return the Font. + * @throws FontFormatException + * is thrown if fontFile does not contain the required font + * tables for the specified format. + * @throws IOException + * signals that an I/O exception has occurred. + */ + public static Font createFont(int fontFormat, InputStream fontStream) + throws FontFormatException, IOException { + + // ???AWT not supported + + BufferedInputStream buffStream; + int bRead = 0; + int size = 8192; + // memory page size, for the faster reading + byte buf[] = new byte[size]; + + if (fontFormat != TRUETYPE_FONT) { // awt.9A=Unsupported font format + throw new IllegalArgumentException(Messages.getString("awt.9A")); //$NON-NLS-1$ + } + + /* Get font file in system-specific directory */ + + File fontFile = Toolkit.getDefaultToolkit().getGraphicsFactory().getFontManager() + .getTempFontFile(); + + // BEGIN android-modified + buffStream = new BufferedInputStream(fontStream, 8192); + // END android-modified + FileOutputStream fOutStream = new FileOutputStream(fontFile); + + bRead = buffStream.read(buf, 0, size); + + while (bRead != -1) { + fOutStream.write(buf, 0, bRead); + bRead = buffStream.read(buf, 0, size); + } + + buffStream.close(); + fOutStream.close(); + + Font font = null; + + font = Toolkit.getDefaultToolkit().getGraphicsFactory().embedFont( + fontFile.getAbsolutePath()); + if (font == null) { // awt.9B=Can't create font - bad font data + throw new FontFormatException(Messages.getString("awt.9B")); //$NON-NLS-1$ + } + return font; + } + +} diff --git a/awt/java/awt/FontFormatException.java b/awt/java/awt/FontFormatException.java new file mode 100644 index 0000000..806711a --- /dev/null +++ b/awt/java/awt/FontFormatException.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt; + +/** + * The FontFormatException class is used to provide notification and information + * that font can't be created. + * + * @since Android 1.0 + */ +public class FontFormatException extends Exception { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -4481290147811361272L; + + /** + * Instantiates a new font format exception with detailed message. + * + * @param reason + * the detailed message. + */ + public FontFormatException(String reason) { + super(reason); + } + +} diff --git a/awt/java/awt/FontMetrics.java b/awt/java/awt/FontMetrics.java new file mode 100644 index 0000000..9082626 --- /dev/null +++ b/awt/java/awt/FontMetrics.java @@ -0,0 +1,466 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt; + +import java.awt.font.FontRenderContext; +import java.awt.font.LineMetrics; +import java.awt.geom.Rectangle2D; +import java.io.Serializable; +import java.text.CharacterIterator; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The FontMetrics class contains information about the rendering of a + * particular font on a particular screen. + * <p> + * Each character in the Font has three values that help define where to place + * it: an ascent, a descent, and an advance. The ascent is the distance the + * character extends above the baseline. The descent is the distance the + * character extends below the baseline. The advance width defines the position + * at which the next character should be placed. + * <p> + * An array of characters or a string has an ascent, a descent, and an advance + * width too. The ascent or descent of the array is specified by the maximum + * ascent or descent of the characters in the array. The advance width is the + * sum of the advance widths of each of the characters in the character array. + * </p> + * + * @since Android 1.0 + */ +public abstract class FontMetrics implements Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 1681126225205050147L; + + /** + * The font from which the FontMetrics is created. + */ + protected Font font; + + /** + * Instantiates a new font metrics from the specified Font. + * + * @param fnt + * the Font. + */ + protected FontMetrics(Font fnt) { + this.font = fnt; + } + + /** + * Returns the String representation of this FontMetrics. + * + * @return the string. + */ + @Override + public String toString() { + return this.getClass().getName() + "[font=" + this.getFont() + //$NON-NLS-1$ + "ascent=" + this.getAscent() + //$NON-NLS-1$ + ", descent=" + this.getDescent() + //$NON-NLS-1$ + ", height=" + this.getHeight() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * Gets the font associated with this FontMetrics. + * + * @return the font associated with this FontMetrics. + */ + public Font getFont() { + return font; + } + + /** + * Gets the height of the text line in this Font. + * + * @return the height of the text line in this Font. + */ + public int getHeight() { + return this.getAscent() + this.getDescent() + this.getLeading(); + } + + /** + * Gets the font ascent of the Font associated with this FontMetrics. The + * font ascent is the distance from the font's baseline to the top of most + * alphanumeric characters. + * + * @return the ascent of the Font associated with this FontMetrics. + */ + public int getAscent() { + return 0; + } + + /** + * Gets the font descent of the Font associated with this FontMetrics. The + * font descent is the distance from the font's baseline to the bottom of + * most alphanumeric characters with descenders. + * + * @return the descent of the Font associated with this FontMetrics. + */ + public int getDescent() { + return 0; + } + + /** + * Gets the leading of the Font associated with this FontMetrics. + * + * @return the leading of the Font associated with this FontMetrics. + */ + public int getLeading() { + return 0; + } + + /** + * Gets the LineMetrics object for the specified CharacterIterator in the + * specified Graphics. + * + * @param ci + * the CharacterIterator. + * @param beginIndex + * the offset. + * @param limit + * the number of characters to be used. + * @param context + * the Graphics. + * @return the LineMetrics object for the specified CharacterIterator in the + * specified Graphics. + */ + public LineMetrics getLineMetrics(CharacterIterator ci, int beginIndex, int limit, + Graphics context) { + return font.getLineMetrics(ci, beginIndex, limit, this.getFRCFromGraphics(context)); + } + + /** + * Gets the LineMetrics object for the specified String in the specified + * Graphics. + * + * @param str + * the String. + * @param context + * the Graphics. + * @return the LineMetrics object for the specified String in the specified + * Graphics. + */ + public LineMetrics getLineMetrics(String str, Graphics context) { + return font.getLineMetrics(str, this.getFRCFromGraphics(context)); + } + + /** + * Gets the LineMetrics object for the specified character array in the + * specified Graphics. + * + * @param chars + * the character array. + * @param beginIndex + * the offset of array. + * @param limit + * the number of characters to be used. + * @param context + * the Graphics. + * @return the LineMetrics object for the specified character array in the + * specified Graphics. + */ + public LineMetrics getLineMetrics(char[] chars, int beginIndex, int limit, Graphics context) { + return font.getLineMetrics(chars, beginIndex, limit, this.getFRCFromGraphics(context)); + } + + /** + * Gets the LineMetrics object for the specified String in the specified + * Graphics. + * + * @param str + * the String. + * @param beginIndex + * the offset. + * @param limit + * the number of characters to be used. + * @param context + * the Graphics. + * @return the LineMetrics object for the specified String in the specified + * Graphics. + */ + public LineMetrics getLineMetrics(String str, int beginIndex, int limit, Graphics context) { + return font.getLineMetrics(str, beginIndex, limit, this.getFRCFromGraphics(context)); + } + + /** + * Returns the character's maximum bounds in the specified Graphics context. + * + * @param context + * the Graphics context. + * @return the character's maximum bounds in the specified Graphics context. + */ + public Rectangle2D getMaxCharBounds(Graphics context) { + return this.font.getMaxCharBounds(this.getFRCFromGraphics(context)); + } + + /** + * Gets the bounds of the specified CharacterIterator in the specified + * Graphics context. + * + * @param ci + * the CharacterIterator. + * @param beginIndex + * the begin offset of the array. + * @param limit + * the number of characters. + * @param context + * the Graphics. + * @return the bounds of the specified CharacterIterator in the specified + * Graphics context. + */ + public Rectangle2D getStringBounds(CharacterIterator ci, int beginIndex, int limit, + Graphics context) { + return font.getStringBounds(ci, beginIndex, limit, this.getFRCFromGraphics(context)); + } + + /** + * Gets the bounds of the specified String in the specified Graphics + * context. + * + * @param str + * the String. + * @param beginIndex + * the begin offset of the array. + * @param limit + * the number of characters. + * @param context + * the Graphics. + * @return the bounds of the specified String in the specified Graphics + * context. + */ + public Rectangle2D getStringBounds(String str, int beginIndex, int limit, Graphics context) { + return font.getStringBounds(str, beginIndex, limit, this.getFRCFromGraphics(context)); + } + + /** + * Gets the bounds of the specified characters array in the specified + * Graphics context. + * + * @param chars + * the characters array. + * @param beginIndex + * the begin offset of the array. + * @param limit + * the number of characters. + * @param context + * the Graphics. + * @return the bounds of the specified characters array in the specified + * Graphics context. + */ + public Rectangle2D getStringBounds(char[] chars, int beginIndex, int limit, Graphics context) { + return font.getStringBounds(chars, beginIndex, limit, this.getFRCFromGraphics(context)); + } + + /** + * Gets the bounds of the specified String in the specified Graphics + * context. + * + * @param str + * the String. + * @param context + * the Graphics. + * @return the bounds of the specified String in the specified Graphics + * context. + */ + public Rectangle2D getStringBounds(String str, Graphics context) { + return font.getStringBounds(str, this.getFRCFromGraphics(context)); + } + + /** + * Checks if the Font has uniform line metrics or not. The Font can contain + * characters of other fonts for covering character set. In this case the + * Font isn't uniform. + * + * @return true, if the Font has uniform line metrics, false otherwise. + */ + public boolean hasUniformLineMetrics() { + return this.font.hasUniformLineMetrics(); + } + + /** + * Returns the distance from the leftmost point to the rightmost point on + * the string's baseline showing the specified array of bytes in this Font. + * + * @param data + * the array of bytes to be measured. + * @param off + * the start offset. + * @param len + * the number of bytes to be measured. + * @return the advance width of the array. + */ + public int bytesWidth(byte[] data, int off, int len) { + int width = 0; + if ((off >= data.length) || (off < 0)) { + // awt.13B=offset off is out of range + throw new IllegalArgumentException(Messages.getString("awt.13B")); //$NON-NLS-1$ + } + + if ((off + len > data.length)) { + // awt.13C=number of elemets len is out of range + throw new IllegalArgumentException(Messages.getString("awt.13C")); //$NON-NLS-1$ + } + + for (int i = off; i < off + len; i++) { + width += charWidth(data[i]); + } + + return width; + } + + /** + * Returns the distance from the leftmost point to the rightmost point on + * the string's baseline showing the specified array of characters in this + * Font. + * + * @param data + * the array of characters to be measured. + * @param off + * the start offset. + * @param len + * the number of bytes to be measured. + * @return the advance width of the array. + */ + public int charsWidth(char[] data, int off, int len) { + int width = 0; + if ((off >= data.length) || (off < 0)) { + // awt.13B=offset off is out of range + throw new IllegalArgumentException(Messages.getString("awt.13B")); //$NON-NLS-1$ + } + + if ((off + len > data.length)) { + // awt.13C=number of elemets len is out of range + throw new IllegalArgumentException(Messages.getString("awt.13C")); //$NON-NLS-1$ + } + + for (int i = off; i < off + len; i++) { + width += charWidth(data[i]); + } + + return width; + } + + /** + * Returns the distance from the leftmost point to the rightmost point of + * the specified character in this Font. + * + * @param ch + * the specified Unicode point code of character to be measured. + * @return the advance width of the character. + */ + public int charWidth(int ch) { + return 0; + } + + /** + * Returns the distance from the leftmost point to the rightmost point of + * the specified character in this Font. + * + * @param ch + * the specified character to be measured. + * @return the advance width of the character. + */ + public int charWidth(char ch) { + return 0; + } + + /** + * Gets the maximum advance width of character in this Font. + * + * @return the maximum advance width of character in this Font. + */ + public int getMaxAdvance() { + return 0; + } + + /** + * Gets the maximum font ascent of the Font associated with this + * FontMetrics. + * + * @return the maximum font ascent of the Font associated with this + * FontMetrics. + */ + public int getMaxAscent() { + return 0; + } + + /** + * Gets the maximum font descent of character in this Font. + * + * @return the maximum font descent of character in this Font. + * @deprecated Replaced by getMaxDescent() method. + */ + @Deprecated + public int getMaxDecent() { + return 0; + } + + /** + * Gets the maximum font descent of character in this Font. + * + * @return the maximum font descent of character in this Font. + */ + public int getMaxDescent() { + return 0; + } + + /** + * Gets the advance widths of the characters in the Font. + * + * @return the advance widths of the characters in the Font. + */ + public int[] getWidths() { + return null; + } + + /** + * Returns the advance width for the specified String in this Font. + * + * @param str + * String to be measured. + * @return the the advance width for the specified String in this Font. + */ + public int stringWidth(String str) { + return 0; + } + + /** + * Returns a FontRenderContext instance of the Graphics context specified. + * + * @param context + * the specified Graphics context. + * @return a FontRenderContext of the specified Graphics context. + */ + private FontRenderContext getFRCFromGraphics(Graphics context) { + FontRenderContext frc; + if (context instanceof Graphics2D) { + frc = ((Graphics2D)context).getFontRenderContext(); + } else { + frc = new FontRenderContext(null, false, false); + } + + return frc; + } +} diff --git a/awt/java/awt/GradientPaint.java b/awt/java/awt/GradientPaint.java new file mode 100644 index 0000000..3b32ef5 --- /dev/null +++ b/awt/java/awt/GradientPaint.java @@ -0,0 +1,255 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The GradientPaint class defines a way to fill a Shape with a linear color + * gradient pattern. + * <p> + * The GradientPaint's fill pattern is determined by two points and two colors, + * plus the cyclic mode option. Each of the two points is painted with its + * corresponding color, and on the line segment connecting the two points, the + * color is proportionally changed between the two colors. For points on the + * same line which are not between the two specified points (outside of the + * connecting segment) their color is determined by the cyclic mode option. If + * the mode is cyclic, then the rest of the line repeats the color pattern of + * the connecting segment, cycling back and forth between the two colors. If + * not, the mode is acyclic which means that all points on the line outside the + * connecting line segment are given the same color as the closest of the two + * specified points. + * <p> + * The color of points that are not on the line connecting the two specified + * points are given by perpendicular projection: by taking the set of lines + * perpendicular to the connecting line and for each one, the whole line is + * colored with the same color. + * + * @since Android 1.0 + */ +public class GradientPaint implements Paint { + + /** + * The start point color. + */ + Color color1; + + /** + * The end color point. + */ + Color color2; + + /** + * The location of the start point. + */ + Point2D point1; + + /** + * The location of the end point. + */ + Point2D point2; + + /** + * The indicator of cycle filling. If TRUE filling repeated outside points + * stripe, if FALSE solid color filling outside. + */ + boolean cyclic; + + /** + * Instantiates a new GradientPaint with cyclic or acyclic mode. + * + * @param point1 + * the first specified point. + * @param color1 + * the Color of the first specified point. + * @param point2 + * the second specified point. + * @param color2 + * the Color of the second specified point. + * @param cyclic + * the cyclic mode - true if the gradient pattern should cycle + * repeatedly between the two colors; false otherwise. + */ + public GradientPaint(Point2D point1, Color color1, Point2D point2, Color color2, boolean cyclic) { + if (point1 == null || point2 == null) { + // awt.6D=Point is null + throw new NullPointerException(Messages.getString("awt.6D")); //$NON-NLS-1$ + } + if (color1 == null || color2 == null) { + // awt.6E=Color is null + throw new NullPointerException(Messages.getString("awt.6E")); //$NON-NLS-1$ + } + + this.point1 = point1; + this.point2 = point2; + this.color1 = color1; + this.color2 = color2; + this.cyclic = cyclic; + } + + /** + * Instantiates a new GradientPaint with cyclic or acyclic mode; points are + * specified by coordinates. + * + * @param x1 + * the X coordinate of the first point. + * @param y1 + * the Y coordinate of the first point. + * @param color1 + * the color of the first point. + * @param x2 + * the X coordinate of the second point. + * @param y2 + * the Y coordinate of the second point. + * @param color2 + * the color of the second point. + * @param cyclic + * the cyclic mode - true if the gradient pattern should cycle + * repeatedly between the two colors; false otherwise. + */ + public GradientPaint(float x1, float y1, Color color1, float x2, float y2, Color color2, + boolean cyclic) { + this(new Point2D.Float(x1, y1), color1, new Point2D.Float(x2, y2), color2, cyclic); + } + + /** + * Instantiates a new acyclic GradientPaint; points are specified by + * coordinates. + * + * @param x1 + * the X coordinate of the first point. + * @param y1 + * the Y coordinate of the first point. + * @param color1 + * the color of the first point. + * @param x2 + * the X coordinate of the second point. + * @param y2 + * the Y coordinate of the second point. + * @param color2 + * the color of the second point. + */ + public GradientPaint(float x1, float y1, Color color1, float x2, float y2, Color color2) { + this(x1, y1, color1, x2, y2, color2, false); + } + + /** + * Instantiates a new acyclic GradientPaint. + * + * @param point1 + * the first specified point. + * @param color1 + * the Color of the first specified point. + * @param point2 + * the second specified point. + * @param color2 + * the Color of the second specified point. + */ + public GradientPaint(Point2D point1, Color color1, Point2D point2, Color color2) { + this(point1, color1, point2, color2, false); + } + + /** + * Creates PaintContext for a color pattern generating. + * + * @param cm + * the ColorModel of the Paint data. + * @param deviceBounds + * the bounding Rectangle of graphics primitives being rendered + * in the device space. + * @param userBounds + * the bounding Rectangle of graphics primitives being rendered + * in the user space. + * @param t + * the AffineTransform from user space into device space. + * @param hints + * the RrenderingHints object. + * @return the PaintContext for color pattern generating. + * @see java.awt.Paint#createContext(java.awt.image.ColorModel, + * java.awt.Rectangle, java.awt.geom.Rectangle2D, + * java.awt.geom.AffineTransform, java.awt.RenderingHints) + */ + public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, + Rectangle2D userBounds, AffineTransform t, RenderingHints hints) { + return new GradientPaintContext(cm, t, point1, color1, point2, color2, cyclic); + } + + /** + * Gets the color of the first point. + * + * @return the color of the first point. + */ + public Color getColor1() { + return color1; + } + + /** + * Gets the color of the second point. + * + * @return the color of the second point. + */ + public Color getColor2() { + return color2; + } + + /** + * Gets the first point. + * + * @return the Point object - the first point. + */ + public Point2D getPoint1() { + return point1; + } + + /** + * Gets the second point. + * + * @return the Point object - the second point. + */ + public Point2D getPoint2() { + return point2; + } + + /** + * Gets the transparency mode for the GradientPaint. + * + * @return the transparency mode for the GradientPaint. + * @see java.awt.Transparency#getTransparency() + */ + public int getTransparency() { + int a1 = color1.getAlpha(); + int a2 = color2.getAlpha(); + return (a1 == 0xFF && a2 == 0xFF) ? OPAQUE : TRANSLUCENT; + } + + /** + * Returns the GradientPaint mode: true for cyclic mode, false for acyclic + * mode. + * + * @return true if the gradient cycles repeatedly between the two colors; + * false otherwise. + */ + public boolean isCyclic() { + return cyclic; + } +} diff --git a/awt/java/awt/GradientPaintContext.java b/awt/java/awt/GradientPaintContext.java new file mode 100644 index 0000000..74575f5 --- /dev/null +++ b/awt/java/awt/GradientPaintContext.java @@ -0,0 +1,204 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ +package java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.image.ColorModel; +import java.awt.image.DataBufferInt; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +class GradientPaintContext implements PaintContext { + + /** + * The size of noncyclic part of color lookup table + */ + static int LOOKUP_SIZE = 256; + + /** + * The index mask to lookup color in the table + */ + static int LOOKUP_MASK = 0x1FF; + + /** + * The min value equivalent to zero. If absolute value less then ZERO it considered as zero. + */ + static double ZERO = 1E-10; + + /** + * The ColorModel user defined for PaintContext + */ + ColorModel cm; + + /** + * The indicator of cycle filling. + */ + boolean cyclic; + + /** + * The integer color value of the start point + */ + int c1; + + /** + * The integer color value of the end point + */ + int c2; + + /** + * The lookup gradient color table + */ + int[] table; + + /** + * The tempopary pre-calculated value to evalutae color index + */ + int dx; + + /** + * The tempopary pre-calculated value to evalutae color index + */ + int dy; + + /** + * The tempopary pre-calculated value to evalutae color index + */ + int delta; + + /** + * Constructs a new GradientPaintcontext + * @param cm - not used + * @param t - the fill transformation + * @param point1 - the start fill point + * @param color1 - color of the start point + * @param point2 - the end fill point + * @param color2 - color of the end point + * @param cyclic - the indicator of cycle filling + */ + GradientPaintContext(ColorModel cm, AffineTransform t, Point2D point1, Color color1, Point2D point2, Color color2, boolean cyclic) { + this.cyclic = cyclic; + this.cm = ColorModel.getRGBdefault(); + + c1 = color1.getRGB(); + c2 = color2.getRGB(); + + double px = point2.getX() - point1.getX(); + double py = point2.getY() - point1.getY(); + + Point2D p = t.transform(point1, null); + Point2D bx = new Point2D.Double(px, py); + Point2D by = new Point2D.Double(py, -px); + + t.deltaTransform(bx, bx); + t.deltaTransform(by, by); + + double vec = bx.getX() * by.getY() - bx.getY() * by.getX(); + + if (Math.abs(vec) < ZERO) { + dx = dy = delta = 0; + table = new int[1]; + table[0] = c1; + } else { + double mult = LOOKUP_SIZE * 256 / vec; + dx = (int)(by.getX() * mult); + dy = (int)(by.getY() * mult); + delta = (int)((p.getX() * by.getY() - p.getY() * by.getX()) * mult); + createTable(); + } + } + + /** + * Create color index lookup table. Calculate 256 step trasformation from + * the start point color to the end point color. Colors multiplied by 256 to do integer calculations. + */ + void createTable() { + double ca = (c1 >> 24) & 0xFF; + double cr = (c1 >> 16) & 0xFF; + double cg = (c1 >> 8) & 0xFF; + double cb = c1 & 0xFF; + + double k = 1.0 / LOOKUP_SIZE; + double da = (((c2 >> 24) & 0xFF) - ca) * k; + double dr = (((c2 >> 16) & 0xFF) - cr) * k; + double dg = (((c2 >> 8) & 0xFF) - cg) * k; + double db = ((c2 & 0xFF) - cb) * k; + + table = new int[cyclic ? LOOKUP_SIZE + LOOKUP_SIZE : LOOKUP_SIZE]; + for(int i = 0; i < LOOKUP_SIZE; i++) { + table[i] = + (int)ca << 24 | + (int)cr << 16 | + (int)cg << 8 | + (int)cb; + ca += da; + cr += dr; + cg += dg; + cb += db; + } + if (cyclic) { + for(int i = 0; i < LOOKUP_SIZE; i++) { + table[LOOKUP_SIZE + LOOKUP_SIZE - 1 - i] = table[i]; + } + } + } + + public ColorModel getColorModel() { + return cm; + } + + public void dispose() { + } + + public Raster getRaster(int x, int y, int w, int h) { + WritableRaster rast = cm.createCompatibleWritableRaster(w, h); + + int[] buf = ((DataBufferInt)rast.getDataBuffer()).getData(); + + int c = x * dy - y * dx - delta; + int cx = dy; + int cy = - w * dy - dx; + int k = 0; + + if (cyclic) { + for(int j = 0; j < h; j++) { + for(int i = 0; i < w; i++) { + buf[k++] = table[(c >> 8) & LOOKUP_MASK]; + c += cx; + } + c += cy; + } + } else { + for(int j = 0; j < h; j++) { + for(int i = 0; i < w; i++) { + int index = c >> 8; + buf[k++] = index < 0 ? c1 : index >= LOOKUP_SIZE ? c2 : table[index]; + c += cx; + } + c += cy; + } + } + + return rast; + } + +} + diff --git a/awt/java/awt/Graphics.java b/awt/java/awt/Graphics.java new file mode 100644 index 0000000..2d6e79f --- /dev/null +++ b/awt/java/awt/Graphics.java @@ -0,0 +1,924 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt; + +import java.awt.image.ImageObserver; +import java.text.AttributedCharacterIterator; + +/** + * The abstract Graphics class allows applications to draw on a screen or other + * rendering target. There are several properties which define rendering + * options: origin point, clipping area, color, font. <br> + * <br> + * The origin point specifies the beginning of the clipping area coordinate + * system. All coordinates used in rendering operations are computed with + * respect to this point. The clipping area defines the boundaries where + * rendering operations can be performed. Rendering operations can't modify + * pixels outside of the clipping area. <br> + * <br> + * The draw and fill methods allow applications to drawing shapes, text, images + * with specified font and color options in the specified part of the screen. + * + * @since Android 1.0 + */ +public abstract class Graphics { + + // Constructors + + /** + * Instantiates a new Graphics. This constructor is default for Graphics and + * can not be called directly. + */ + protected Graphics() { + } + + // Public methods + + /** + * Creates a copy of the Graphics object with a new origin and a new + * specified clip area. The new clip area is the rectangle defined by the + * origin point with coordinates X,Y and the given width and height. The + * coordinates of all subsequent rendering operations will be computed with + * respect to the new origin and can be performed only within the range of + * the clipping area dimensions. + * + * @param x + * the X coordinate of the original point. + * @param y + * the Y coordinate of the original point. + * @param width + * the width of clipping area. + * @param height + * the height of clipping area. + * @return the Graphics object with new origin point and clipping area. + */ + public Graphics create(int x, int y, int width, int height) { + Graphics res = create(); + res.translate(x, y); + res.clipRect(0, 0, width, height); + return res; + } + + /** + * Draws the highlighted outline of a rectangle. + * + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of rectangle. + * @param height + * the height of rectangle. + * @param raised + * a boolean value that determines whether the rectangle is drawn + * as raised or indented. + */ + public void draw3DRect(int x, int y, int width, int height, boolean raised) { + // Note: lighter/darker colors should be used to draw 3d rect. + // The resulting rect is (width+1)x(height+1). Stroke and paint + // attributes of + // the Graphics2D should be reset to the default values. + // fillRect is used instead of drawLine to bypass stroke + // reset/set and rasterization. + + Color color = getColor(); + Color colorUp, colorDown; + if (raised) { + colorUp = color.brighter(); + colorDown = color.darker(); + } else { + colorUp = color.darker(); + colorDown = color.brighter(); + } + + setColor(colorUp); + fillRect(x, y, width, 1); + fillRect(x, y + 1, 1, height); + + setColor(colorDown); + fillRect(x + width, y, 1, height); + fillRect(x + 1, y + height, width, 1); + } + + /** + * Draws the text represented by byte array. This method uses the current + * font and color for rendering. + * + * @param bytes + * the byte array which contains the text to be drawn. + * @param off + * the offset within the byte array of the text to be drawn. + * @param len + * the number of bytes of text to draw. + * @param x + * the X coordinate where the text is to be drawn. + * @param y + * the Y coordinate where the text is to be drawn. + */ + public void drawBytes(byte[] bytes, int off, int len, int x, int y) { + drawString(new String(bytes, off, len), x, y); + } + + /** + * Draws the text represented by character array. This method uses the + * current font and color for rendering. + * + * @param chars + * the character array. + * @param off + * the offset within the character array of the text to be drawn. + * @param len + * the number of characters which will be drawn. + * @param x + * the X coordinate where the text is to be drawn. + * @param y + * the Y coordinate where the text is to be drawn. + */ + public void drawChars(char[] chars, int off, int len, int x, int y) { + drawString(new String(chars, off, len), x, y); + } + + /** + * Draws the outline of a polygon which is defined by Polygon object. + * + * @param p + * the Polygon object. + */ + public void drawPolygon(Polygon p) { + drawPolygon(p.xpoints, p.ypoints, p.npoints); + } + + /** + * Draws the rectangle with the specified width and length and top left + * corner coordinates. + * + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + */ + public void drawRect(int x, int y, int width, int height) { + int[] xpoints = { + x, x, x + width, x + width + }; + int[] ypoints = { + y, y + height, y + height, y + }; + + drawPolygon(xpoints, ypoints, 4); + } + + /** + * Fills the highlighted outline of a rectangle. + * + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + * @param raised + * a boolean value that determines whether the rectangle is drawn + * as raised or indented. + */ + public void fill3DRect(int x, int y, int width, int height, boolean raised) { + // Note: lighter/darker colors should be used to draw 3d rect. + // The resulting rect is (width)x(height), same as fillRect. + // Stroke and paint attributes of the Graphics2D should be reset + // to the default values. fillRect is used instead of drawLine to + // bypass stroke reset/set and line rasterization. + + Color color = getColor(); + Color colorUp, colorDown; + if (raised) { + colorUp = color.brighter(); + colorDown = color.darker(); + setColor(color); + } else { + colorUp = color.darker(); + colorDown = color.brighter(); + setColor(colorUp); + } + + width--; + height--; + fillRect(x + 1, y + 1, width - 1, height - 1); + + setColor(colorUp); + fillRect(x, y, width, 1); + fillRect(x, y + 1, 1, height); + + setColor(colorDown); + fillRect(x + width, y, 1, height); + fillRect(x + 1, y + height, width, 1); + } + + /** + * Fills the polygon with the current color. + * + * @param p + * the Polygon object. + */ + public void fillPolygon(Polygon p) { + fillPolygon(p.xpoints, p.ypoints, p.npoints); + } + + /** + * Disposes of the Graphics. + */ + @Override + public void finalize() { + } + + /** + * Gets the bounds of the current clipping area as a rectangle and copies it + * to an existing rectangle. + * + * @param r + * a Rectangle object where the current clipping area bounds are + * to be copied. + * @return the bounds of the current clipping area. + */ + public Rectangle getClipBounds(Rectangle r) { + Shape clip = getClip(); + + if (clip != null) { + // TODO: Can we get shape bounds without creating Rectangle object? + Rectangle b = clip.getBounds(); + r.x = b.x; + r.y = b.y; + r.width = b.width; + r.height = b.height; + } + + return r; + } + + /** + * Gets the bounds of the current clipping area as a rectangle. + * + * @return a Rectangle object. + * @deprecated Use {@link #getClipBounds()} + */ + @Deprecated + public Rectangle getClipRect() { + return getClipBounds(); + } + + /** + * Gets the font metrics of the current font. The font metrics object + * contains information about the rendering of a particular font. + * + * @return the font metrics of current font. + */ + public FontMetrics getFontMetrics() { + return getFontMetrics(getFont()); + } + + /** + * Determines whether or not the specified rectangle intersects the current + * clipping area. + * + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + * @return true, if the specified rectangle intersects the current clipping + * area, false otherwise. + */ + public boolean hitClip(int x, int y, int width, int height) { + // TODO: Create package private method Rectangle.intersects(int, int, + // int, int); + return getClipBounds().intersects(new Rectangle(x, y, width, height)); + } + + /** + * Returns string which represents this Graphics object. + * + * @return the string which represents this Graphics object. + */ + @Override + public String toString() { + // TODO: Think about string representation of Graphics. + return "Graphics"; //$NON-NLS-1$ + } + + // Abstract methods + + /** + * Clears the specified rectangle. This method fills specified rectangle + * with background color. + * + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + */ + public abstract void clearRect(int x, int y, int width, int height); + + /** + * Intersects the current clipping area with a new rectangle. If the current + * clipping area is not defined, the rectangle becomes a new clipping area. + * Rendering operations are only allowed within the new the clipping area. + * + * @param x + * the X coordinate of the rectangle for intersection. + * @param y + * the Y coordinate of the rectangle for intersection. + * @param width + * the width of the rectangle for intersection. + * @param height + * the height of the rectangle for intersection. + */ + public abstract void clipRect(int x, int y, int width, int height); + + /** + * Copies the rectangle area to another area specified by a distance (dx, + * dy) from the original rectangle's location. Positive dx and dy values + * give a new location defined by translation to the right and down from the + * original location, negative dx and dy values - to the left and up. + * + * @param sx + * the X coordinate of the rectangle which will be copied. + * @param sy + * the Y coordinate of the rectangle which will be copied. + * @param width + * the width of the rectangle which will be copied. + * @param height + * the height of the rectangle which will be copied. + * @param dx + * the horizontal distance from the source rectangle's location + * to the copy's location. + * @param dy + * the vertical distance from the source rectangle's location to + * the copy's location. + */ + public abstract void copyArea(int sx, int sy, int width, int height, int dx, int dy); + + /** + * Creates a new copy of this Graphics. + * + * @return a new Graphics context which is a copy of this Graphics. + */ + public abstract Graphics create(); + + /** + * Disposes of the Graphics. This Graphics object can not be used after + * calling this method. + */ + public abstract void dispose(); + + /** + * Draws the arc covering the specified rectangle and using the current + * color. The rectangle is defined by the origin point (X, Y) and dimensions + * (width and height). The arc center is the the center of specified + * rectangle. The angle origin is 3 o'clock position, the positive angle is + * counted as a counter-clockwise rotation, the negative angle is counted as + * clockwise rotation. + * + * @param x + * the X origin coordinate of the rectangle which scales the arc. + * @param y + * the Y origin coordinate of the rectangle which scales the arc. + * @param width + * the width of the rectangle which scales the arc. + * @param height + * the height of the rectangle which scales the arc. + * @param sa + * start angle - the origin angle of arc. + * @param ea + * arc angle - the angular arc value relative to the start angle. + */ + public abstract void drawArc(int x, int y, int width, int height, int sa, int ea); + + /** + * Draws the specified image with the defined background color. The top left + * corner of image will be drawn at point (x, y) in current coordinate + * system. The image loading process notifies the specified Image Observer. + * This method returns true if the image has loaded, otherwise it returns + * false. + * + * @param img + * the image which will be drawn. + * @param x + * the X coordinate of the image top left corner. + * @param y + * the Y coordinate of the image top left corner. + * @param bgcolor + * the background color. + * @param observer + * the ImageObserver object which should be notified about image + * loading process. + * @return true, if loading image is successful or image is null, false + * otherwise. + */ + public abstract boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer); + + /** + * Draws the specified image. The top left corner of image will be drawn at + * point (x, y) in current coordinate system. The image loading process + * notifies the specified Image Observer. This method returns true if the + * image has loaded, otherwise it returns false. + * + * @param img + * the image which will be drawn. + * @param x + * the X coordinate of the image top left corner. + * @param y + * the Y coordinate of the image top left corner. + * @param observer + * the ImageObserver object which should be notified about image + * loading process. + * @return true, if loading image is successful or image is null, otherwise + * false. + */ + public abstract boolean drawImage(Image img, int x, int y, ImageObserver observer); + + /** + * Scales the specified image to fit in the specified rectangle and draws it + * with the defined background color. The top left corner of the image will + * be drawn at the point (x, y) in current coordinate system. The non-opaque + * pixels will be drawn in the background color. The image loading process + * notifies the specified Image Observer. This method returns true if the + * image has loaded, otherwise it returns false. + * + * @param img + * the image which will be drawn. + * @param x + * the X coordinate of the image's top left corner. + * @param y + * the Y coordinate of the image's top left corner. + * @param width + * the width of rectangle which scales the image. + * @param height + * the height of rectangle which scales the image. + * @param bgcolor + * the background color. + * @param observer + * the ImageObserver object which should be notified about image + * loading process. + * @return true, if loading image is successful or image is null, otherwise + * false. + */ + public abstract boolean drawImage(Image img, int x, int y, int width, int height, + Color bgcolor, ImageObserver observer); + + /** + * Scales the specified image to fit in the specified rectangle and draws + * it. The top left corner of the image will be drawn at the point (x, y) in + * current coordinate system. The image loading process notifies the + * specified Image Observer. This method returns true if the image has + * loaded, otherwise it returns false. + * + * @param img + * the image which will be drawn. + * @param x + * the X coordinate of the image top left corner. + * @param y + * the Y coordinate of the image top left corner. + * @param width + * the width of rectangle which scales the image. + * @param height + * the height of rectangle which scales the image. + * @param observer + * the ImageObserver object which should be notified about image + * loading process. + * @return true, if loading image is successful or image is null, otherwise + * false. + */ + public abstract boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer); + + /** + * Scales the specified area of the specified image to fit in the rectangle + * area defined by its corners coordinates and draws the sub-image with the + * specified background color. The sub-image to be drawn is defined by its + * top left corner coordinates (sx1, sy1) and bottom right corner + * coordinates (sx2, sy2) computed with respect to the origin (top left + * corner) of the source image. The non opaque pixels will be drawn in the + * background color. The image loading process notifies specified Image + * Observer. This method returns true if the image has loaded, otherwise it + * returns false. + * + * @param img + * the image which will be drawn. + * @param dx1 + * the X top left corner coordinate of the destination rectangle + * area. + * @param dy1 + * the Y top left corner coordinate of the destination rectangle + * area. + * @param dx2 + * the X bottom right corner coordinate of the destination + * rectangle area. + * @param dy2 + * the Y bottom right corner coordinate of the destination + * rectangle area. + * @param sx1 + * the X top left corner coordinate of the area to be drawn + * within the source image. + * @param sy1 + * the Y top left corner coordinate of the area to be drawn + * within the source image. + * @param sx2 + * the X bottom right corner coordinate of the area to be drawn + * within the source image. + * @param sy2 + * the Y bottom right corner coordinate of the area to be drawn + * within the source image. + * @param bgcolor + * the background color. + * @param observer + * the ImageObserver object which should be notified about image + * loading process. + * @return true, if loading image is successful or image is null, false + * otherwise. + */ + public abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, + int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer); + + /** + * Scales the specified area of the specified image to fit in the rectangle + * area defined by its corners coordinates and draws the sub-image. The + * sub-image to be drawn is defined by its top left corner coordinates (sx1, + * sy1) and bottom right corner coordinates (sx2, sy2) computed with respect + * to the origin (top left corner) of the source image. The image loading + * process notifies specified Image Observer. This method returns true if + * the image has loaded, otherwise it returns false. + * + * @param img + * the image which will be drawn. + * @param dx1 + * the X top left corner coordinate of the destination rectangle + * area. + * @param dy1 + * the Y top left corner coordinate of the destination rectangle + * area. + * @param dx2 + * the X bottom right corner coordinate of the destination + * rectangle area. + * @param dy2 + * the Y bottom right corner coordinate of the destination + * rectangle area. + * @param sx1 + * the X top left corner coordinate of the area to be drawn + * within the source image. + * @param sy1 + * the Y top left corner coordinate of the area to be drawn + * within the source image. + * @param sx2 + * the X bottom right corner coordinate of the area to be drawn + * within the source image. + * @param sy2 + * the Y bottom right corner coordinate of the area to be drawn + * within the source image. + * @param observer + * the ImageObserver object which should be notified about image + * loading process. + * @return true, if loading image is successful or image is null, false + * otherwise. + */ + public abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, + int sy1, int sx2, int sy2, ImageObserver observer); + + /** + * Draws a line from the point (x1, y1) to the point (x2, y2). This method + * draws the line with current color which can be changed by setColor(Color + * c) method. + * + * @param x1 + * the X coordinate of the first point. + * @param y1 + * the Y coordinate of the first point. + * @param x2 + * the X coordinate of the second point. + * @param y2 + * the Y coordinate of the second point. + */ + public abstract void drawLine(int x1, int y1, int x2, int y2); + + /** + * Draws the outline of an oval to fit in the rectangle defined by the given + * width, height, and top left corner. + * + * @param x + * the X top left corner oval coordinate. + * @param y + * the Y top left corner oval coordinate. + * @param width + * the oval width. + * @param height + * the oval height. + */ + public abstract void drawOval(int x, int y, int width, int height); + + /** + * Draws the outline of a polygon. The polygon vertices are defined by + * points with xpoints[i], ypoints[i] as coordinates. The polygon edges are + * the lines from the points with (xpoints[i-1], ypoints[i-1]) coordinates + * to the points with (xpoints[i], ypoints[i]) coordinates, for 0 < i < + * npoints +1. + * + * @param xpoints + * the array of X coordinates of the polygon vertices. + * @param ypoints + * the array of Y coordinates of the polygon vertices. + * @param npoints + * the number of polygon vertices/points. + */ + public abstract void drawPolygon(int[] xpoints, int[] ypoints, int npoints); + + /** + * Draws a set of connected lines which are defined by the x and y + * coordinate arrays. The polyline is closed if coordinates of the first + * point are the same as coordinates of the last point. + * + * @param xpoints + * the array of X point coordinates. + * @param ypoints + * the array of Y point coordinates. + * @param npoints + * the number of points. + */ + public abstract void drawPolyline(int[] xpoints, int[] ypoints, int npoints); + + /** + * Draws the outline of a rectangle with round corners. + * + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + * @param arcWidth + * the arc width for the corners. + * @param arcHeight + * the arc height for the corners. + */ + public abstract void drawRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight); + + /** + * Draws a text defined by an iterator. The iterator should specify the font + * for every character. + * + * @param iterator + * the iterator. + * @param x + * the X coordinate of the first character. + * @param y + * the Y coordinate of the first character. + */ + public abstract void drawString(AttributedCharacterIterator iterator, int x, int y); + + /** + * Draws a text defined by a string. This method draws the text with current + * font and color. + * + * @param str + * the string. + * @param x + * the X coordinate of the first character. + * @param y + * the Y coordinate of the first character. + */ + public abstract void drawString(String str, int x, int y); + + /** + * Fills the arc covering the rectangle and using the current color. The + * rectangle is defined by the origin point (X, Y) and dimensions (width and + * height). The arc center is the the center of specified rectangle. The + * angle origin is at the 3 o'clock position, and a positive angle gives + * counter-clockwise rotation, a negative angle gives clockwise rotation. + * + * @param x + * the X origin coordinate of the rectangle which scales the arc. + * @param y + * the Y origin coordinate of the rectangle which scales the arc. + * @param width + * the width of the rectangle which scales the arc. + * @param height + * the height of the rectangle which scales the arc. + * @param sa + * start angle - the origin angle of arc. + * @param ea + * arc angle - the angular arc value relative to the start angle. + */ + public abstract void fillArc(int x, int y, int width, int height, int sa, int ea); + + /** + * Fills an oval with the current color where the oval is defined by the + * bounding rectangle with the given width, height, and top left corner. + * + * @param x + * the X top left corner oval coordinate. + * @param y + * the Y top left corner oval coordinate. + * @param width + * the oval width. + * @param height + * the oval height. + */ + public abstract void fillOval(int x, int y, int width, int height); + + /** + * Fills a polygon with the current color. The polygon vertices are defined + * by the points with xpoints[i], ypoints[i] as coordinates. The polygon + * edges are the lines from the points with (xpoints[i-1], ypoints[i-1]) + * coordinates to the points with (xpoints[i], ypoints[i]) coordinates, for + * 0 < i < npoints +1. + * + * @param xpoints + * the array of X coordinates of the polygon vertices. + * @param ypoints + * the array of Y coordinates of the polygon vertices. + * @param npoints + * the number of polygon vertices/points. + */ + public abstract void fillPolygon(int[] xpoints, int[] ypoints, int npoints); + + /** + * Fills a rectangle with the current color. The rectangle is defined by its + * width and length and top left corner coordinates. + * + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of rectangle. + * @param height + * the height of rectangle. + */ + public abstract void fillRect(int x, int y, int width, int height); + + /** + * Fills a round cornered rectangle with the current color. + * + * @param x + * the X coordinate of the top left corner of the bounding + * rectangle. + * @param y + * the Y coordinate of the top left corner of the bounding + * rectangle. + * @param width + * the width of the bounding rectangle. + * @param height + * the height of the bounding rectangle. + * @param arcWidth + * the arc width at the corners. + * @param arcHeight + * the arc height at the corners. + */ + public abstract void fillRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight); + + /** + * Gets the clipping area. <br> + * <br> + * + * @return a Shape object of the clipping area or null if it is not set. + */ + public abstract Shape getClip(); + + /** + * Gets the bounds of the current clipping area as a rectangle. + * + * @return a Rectangle object which represents the bounds of the current + * clipping area. + */ + public abstract Rectangle getClipBounds(); + + /** + * Gets the current color of Graphics. + * + * @return the current color. + */ + public abstract Color getColor(); + + /** + * Gets the current font of Graphics. + * + * @return the current font. + */ + public abstract Font getFont(); + + /** + * Gets the font metrics of the specified font. The font metrics object + * contains information about the rendering of a particular font. + * + * @param font + * the specified font. + * @return the font metrics for the specified font. + */ + public abstract FontMetrics getFontMetrics(Font font); + + /** + * Sets the new clipping area specified by rectangle. The new clipping area + * doesn't depend on the window's visibility. Rendering operations can't be + * performed outside new clipping area. + * + * @param x + * the X coordinate of the new clipping rectangle. + * @param y + * the Y coordinate of the new clipping rectangle. + * @param width + * the width of the new clipping rectangle. + * @param height + * the height of the new clipping rectangle. + */ + public abstract void setClip(int x, int y, int width, int height); + + /** + * Sets the new clipping area to be the area specified by Shape object. The + * new clipping area doesn't depend on the window's visibility. Rendering + * operations can't be performed outside new clipping area. + * + * @param clip + * the Shape object which represents new clipping area. + */ + public abstract void setClip(Shape clip); + + /** + * Sets the current Graphics color. All rendering operations with this + * Graphics will use this color. + * + * @param c + * the new color. + */ + public abstract void setColor(Color c); + + /** + * Sets the current Graphics font. All rendering operations with this + * Graphics will use this font. + * + * @param font + * the new font. + */ + public abstract void setFont(Font font); + + /** + * Sets the paint mode for the Graphics which overwrites all rendering + * operations with the current color. + */ + public abstract void setPaintMode(); + + /** + * Sets the XOR mode for the Graphics which changes a pixel from the current + * color to the specified XOR color. <br> + * <br> + * + * @param color + * the new XOR mode. + */ + public abstract void setXORMode(Color color); + + /** + * Translates the origin of Graphics current coordinate system to the point + * with X, Y coordinates in the current coordinate system. All rendering + * operation in this Graphics will be related to the new origin. + * + * @param x + * the X coordinate of the origin. + * @param y + * the Y coordinate of the origin. + */ + public abstract void translate(int x, int y); +} diff --git a/awt/java/awt/Graphics2D.java b/awt/java/awt/Graphics2D.java new file mode 100644 index 0000000..04a7319 --- /dev/null +++ b/awt/java/awt/Graphics2D.java @@ -0,0 +1,513 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.awt; + +import java.awt.font.GlyphVector; +import java.awt.font.FontRenderContext; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ImageObserver; +import java.awt.image.RenderedImage; +import java.awt.image.renderable.RenderableImage; +import java.text.AttributedCharacterIterator; +import java.util.Map; + +/** + * The Graphics2D class extends Graphics class and provides more capabilities + * for rendering text, images, shapes. This provides methods to perform + * transformation of coordinate system, color management, and text layout. The + * following attributes exist for rendering: + * <ul> + * <li>Color - current Graphics2D color;</li> + * <li>Font - current Graphics2D font;</li> + * <li>Stroke - pen with a width of 1 pixel;</li> + * <li>Transform - current Graphics2D Transformation;</li> + * <li>Composite - alpha compositing rules for combining source and destination + * colors.</li> + * </ul> + * + * @since Android 1.0 + */ +public abstract class Graphics2D extends Graphics { + + /** + * Instantiates a new Graphics2D object. This constructor should never be + * called directly. + */ + protected Graphics2D() { + super(); + } + + /** + * Adds preferences for the rendering algorithms. The preferences are + * arbitrary and specified by Map objects. All specified by Map object + * preferences can be modified. + * + * @param hints + * the rendering hints. + */ + public abstract void addRenderingHints(Map<?, ?> hints); + + /** + * Intersects the current clipping area with the specified Shape and the + * result becomes a new clipping area. If current clipping area is not + * defined, the Shape becomes the new clipping area. No rendering operations + * are allowed outside the clipping area. + * + * @param s + * the specified Shape object which will be intersected with + * current clipping area. + */ + public abstract void clip(Shape s); + + /** + * Draws the outline of the specified Shape. + * + * @param s + * the Shape which outline is drawn. + */ + public abstract void draw(Shape s); + + /** + * Draws the specified GlyphVector object's text at the point x, y. + * + * @param g + * the GlyphVector object to be drawn. + * @param x + * the X position where the GlyphVector's text should be + * rendered. + * @param y + * the Y position where the GlyphVector's text should be + * rendered. + */ + public abstract void drawGlyphVector(GlyphVector g, float x, float y); + + /** + * Draws the BufferedImage -- modified according to the operation + * BufferedImageOp -- at the point x, y. + * + * @param img + * the BufferedImage to be rendered. + * @param op + * the filter to be applied to the image before rendering. + * @param x + * the X coordinate of the point where the image's upper left + * corner will be placed. + * @param y + * the Y coordinate of the point where the image's upper left + * corner will be placed. + */ + public abstract void drawImage(BufferedImage img, BufferedImageOp op, int x, int y); + + /** + * Draws BufferedImage transformed from image space into user space + * according to the AffineTransform xform and notifies the ImageObserver. + * + * @param img + * the BufferedImage to be rendered. + * @param xform + * the affine transformation from the image to the user space. + * @param obs + * the ImageObserver to be notified about the image conversion. + * @return true, if the image is successfully loaded and rendered, or it's + * null, otherwise false. + */ + public abstract boolean drawImage(Image img, AffineTransform xform, ImageObserver obs); + + /** + * Draws a RenderableImage which is transformed from image space into user + * according to the AffineTransform xform. + * + * @param img + * the RenderableImage to be rendered. + * @param xform + * the affine transformation from image to user space. + */ + public abstract void drawRenderableImage(RenderableImage img, AffineTransform xform); + + /** + * Draws a RenderedImage which is transformed from image space into user + * according to the AffineTransform xform. + * + * @param img + * the RenderedImage to be rendered. + * @param xform + * the affine transformation from image to user space. + */ + public abstract void drawRenderedImage(RenderedImage img, AffineTransform xform); + + /** + * Draws the string specified by the AttributedCharacterIterator. The first + * character's position is specified by the X, Y parameters. + * + * @param iterator + * whose text is drawn. + * @param x + * the X position where the first character is drawn. + * @param y + * the Y position where the first character is drawn. + */ + public abstract void drawString(AttributedCharacterIterator iterator, float x, float y); + + /** + * Draws the string specified by the AttributedCharacterIterator. The first + * character's position is specified by the X, Y parameters. + * + * @param iterator + * whose text is drawn. + * @param x + * the X position where the first character is drawn. + * @param y + * the Y position where the first character is drawn. + * @see java.awt.Graphics#drawString(AttributedCharacterIterator, int, int) + */ + @Override + public abstract void drawString(AttributedCharacterIterator iterator, int x, int y); + + /** + * Draws the String whose the first character position is specified by the + * parameters X, Y. + * + * @param s + * the String to be drawn. + * @param x + * the X position of the first character. + * @param y + * the Y position of the first character. + */ + public abstract void drawString(String s, float x, float y); + + /** + * Draws the String whose the first character coordinates are specified by + * the parameters X, Y. + * + * @param str + * the String to be drawn. + * @param x + * the X coordinate of the first character. + * @param y + * the Y coordinate of the first character. + * @see java.awt.Graphics#drawString(String, int, int) + */ + @Override + public abstract void drawString(String str, int x, int y); + + /** + * Fills the interior of the specified Shape. + * + * @param s + * the Shape to be filled. + */ + public abstract void fill(Shape s); + + /** + * Gets the background color. + * + * @return the current background color. + */ + public abstract Color getBackground(); + + /** + * Gets the current composite of the Graphics2D. + * + * @return the current composite which specifies the compositing style. + */ + public abstract Composite getComposite(); + + /** + * Gets the device configuration. + * + * @return the device configuration. + */ + public abstract GraphicsConfiguration getDeviceConfiguration(); + + /** + * Gets the rendering context of the Font. + * + * @return the FontRenderContext. + */ + public abstract FontRenderContext getFontRenderContext(); + + /** + * Gets the current Paint of Graphics2D. + * + * @return the current Paint of Graphics2D. + */ + public abstract Paint getPaint(); + + /** + * Gets the value of single preference for specified key. + * + * @param key + * the specified key of the rendering hint. + * @return the value of rendering hint for specified key. + */ + public abstract Object getRenderingHint(RenderingHints.Key key); + + /** + * Gets the set of the rendering preferences as a collection of key/value + * pairs. + * + * @return the RenderingHints which contains the rendering preferences. + */ + public abstract RenderingHints getRenderingHints(); + + /** + * Gets current stroke of the Graphics2D. + * + * @return current stroke of the Graphics2D. + */ + public abstract Stroke getStroke(); + + /** + * Gets current affine transform of the Graphics2D. + * + * @return current AffineTransform of the Graphics2D. + */ + public abstract AffineTransform getTransform(); + + /** + * Determines whether or not the specified Shape intersects the specified + * Rectangle. If the onStroke parameter is true, this method checks whether + * or not the specified Shape outline intersects the specified Rectangle, + * otherwise this method checks whether or not the specified Shape's + * interior intersects the specified Rectangle. + * + * @param rect + * the specified Rectangle. + * @param s + * the Shape to check for intersection. + * @param onStroke + * the parameter determines whether or not this method checks for + * intersection of the Shape outline or of the Shape interior + * with the Rectangle. + * @return true, if there is a hit, false otherwise. + */ + public abstract boolean hit(Rectangle rect, Shape s, boolean onStroke); + + /** + * Performs a rotation transform relative to current Graphics2D Transform. + * The coordinate system is rotated by the specified angle in radians + * relative to current origin. + * + * @param theta + * the angle of rotation in radians. + */ + public abstract void rotate(double theta); + + /** + * Performs a translated rotation transform relative to current Graphics2D + * Transform. The coordinate system is rotated by the specified angle in + * radians relative to current origin and then moved to point (x, y). Is + * this right? + * + * @param theta + * the angle of rotation in radians. + * @param x + * the X coordinate. + * @param y + * the Y coordinate. + */ + public abstract void rotate(double theta, double x, double y); + + /** + * Performs a linear scale transform relative to current Graphics2D + * Transform. The coordinate system is rescaled vertically and horizontally + * by the specified parameters. + * + * @param sx + * the scaling factor by which the X coordinate is multiplied. + * @param sy + * the scaling factor by which the Y coordinate is multiplied. + */ + public abstract void scale(double sx, double sy); + + /** + * Sets a new background color for clearing rectangular areas. The clearRect + * method uses the current background color. + * + * @param color + * the new background color. + */ + public abstract void setBackground(Color color); + + /** + * Sets the current composite for Graphics2D. + * + * @param comp + * the Composite object. + */ + public abstract void setComposite(Composite comp); + + /** + * Sets the paint for Graphics2D. + * + * @param paint + * the Paint object. + */ + public abstract void setPaint(Paint paint); + + /** + * Sets a key-value pair in the current RenderingHints map. + * + * @param key + * the key of the rendering hint to set. + * @param value + * the value to set for the rendering hint. + */ + public abstract void setRenderingHint(RenderingHints.Key key, Object value); + + /** + * Replaces the current rendering hints with the specified rendering + * preferences. + * + * @param hints + * the new Map of rendering hints. + */ + public abstract void setRenderingHints(Map<?, ?> hints); + + /** + * Sets the stroke for the Graphics2D. + * + * @param s + * the Stroke object. + */ + public abstract void setStroke(Stroke s); + + /** + * Overwrite the current Transform of the Graphics2D. The specified + * Transform should be received from the getTransform() method and should be + * used only for restoring the original Graphics2D transform after calling + * draw or fill methods. + * + * @param Tx + * the specified Transform. + */ + public abstract void setTransform(AffineTransform Tx); + + /** + * Performs a shear transform relative to current Graphics2D Transform. The + * coordinate system is shifted by the specified multipliers relative to + * current position. + * + * @param shx + * the multiplier by which the X coordinates shift position along + * X axis as a function of Y coordinates. + * @param shy + * the multiplier by which the Y coordinates shift position along + * Y axis as a function of X coordinates. + */ + public abstract void shear(double shx, double shy); + + /** + * Concatenates the AffineTransform object with current Transform of this + * Graphics2D. The transforms are applied in reverse order with the last + * specified transform applied first and the next transformation applied to + * the result of previous transformation. More precisely, if Cx is the + * current Graphics2D transform, the transform method's result with Tx as + * the parameter is the transformation Rx, where Rx(p) = Cx(Tx(p)), for p - + * a point in current coordinate system. Rx becomes the current Transform + * for this Graphics2D. + * + * @param Tx + * the AffineTransform object to be concatenated with current + * Transform. + */ + public abstract void transform(AffineTransform Tx); + + /** + * Performs a translate transform relative to current Graphics2D Transform. + * The coordinate system is moved by the specified distance relative to + * current position. + * + * @param tx + * the translation distance along the X axis. + * @param ty + * the translation distance along the Y axis. + */ + public abstract void translate(double tx, double ty); + + /** + * Moves the origin Graphics2D Transform to the point with x, y coordinates + * in current coordinate system. The new origin of coordinate system is + * moved to the (x, y) point accordingly. All rendering and transform + * operations are performed relative to this new origin. + * + * @param x + * the X coordinate. + * @param y + * the Y coordinate. + * @see java.awt.Graphics#translate(int, int) + */ + @Override + public abstract void translate(int x, int y); + + /** + * Fills a 3D rectangle with the current color. The rectangle is specified + * by its width, height, and top left corner coordinates. + * + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of rectangle. + * @param height + * the height of rectangle. + * @param raised + * a boolean value that determines whether the rectangle is drawn + * as raised or indented. + * @see java.awt.Graphics#fill3DRect(int, int, int, int, boolean) + */ + @Override + public void fill3DRect(int x, int y, int width, int height, boolean raised) { + // According to the spec, color should be used instead of paint, + // so Graphics.fill3DRect resets paint and + // it should be restored after the call + Paint savedPaint = getPaint(); + super.fill3DRect(x, y, width, height, raised); + setPaint(savedPaint); + } + + /** + * Draws the highlighted outline of a rectangle. + * + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of rectangle. + * @param height + * the height of rectangle. + * @param raised + * a boolean value that determines whether the rectangle is drawn + * as raised or indented. + * @see java.awt.Graphics#draw3DRect(int, int, int, int, boolean) + */ + @Override + public void draw3DRect(int x, int y, int width, int height, boolean raised) { + // According to the spec, color should be used instead of paint, + // so Graphics.draw3DRect resets paint and + // it should be restored after the call + Paint savedPaint = getPaint(); + super.draw3DRect(x, y, width, height, raised); + setPaint(savedPaint); + } +}
\ No newline at end of file diff --git a/awt/java/awt/GraphicsConfiguration.java b/awt/java/awt/GraphicsConfiguration.java new file mode 100644 index 0000000..d59e896 --- /dev/null +++ b/awt/java/awt/GraphicsConfiguration.java @@ -0,0 +1,226 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.VolatileImage; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The GraphicsConfiguration class contains the characteristics of graphics + * devices such as a printer or monitor, and represents device's capabilities + * and modes. Many GraphicsConfiguration objects can be associated with single + * graphics device. + * + * @since Android 1.0 + */ +public abstract class GraphicsConfiguration { + + /** + * Constructor could not be used directly and should be obtained in extended + * classes. + */ + protected GraphicsConfiguration() { + } + + /** + * Creates BufferedImage image object with a data layout and color model + * compatible with this GraphicsConfiguration with specified width and + * height parameters. + * + * @param width + * the width of BufferedImage. + * @param height + * the height of BufferedImage. + * @return the BufferedImage object with specified width and height + * parameters. + */ + public abstract BufferedImage createCompatibleImage(int width, int height); + + /** + * Creates a BufferedImage that has the specified width, height, + * transparency and has a data layout and color model compatible with this + * GraphicsConfiguration. + * + * @param width + * the width of image. + * @param height + * the height of image. + * @param transparency + * the transparency mode. + * @return the BufferedImage object. + */ + public abstract BufferedImage createCompatibleImage(int width, int height, int transparency); + + /** + * Creates a VolatileImage that has the specified width and height and has a + * data layout and color model compatible with this GraphicsConfiguration. + * + * @param width + * the width of image. + * @param height + * the height of image. + * @return the VolatileImage object. + */ + public abstract VolatileImage createCompatibleVolatileImage(int width, int height); + + /** + * Creates a VolatileImage that supports the specified width, height, + * transparency and has a data layout and color model compatible with this + * GraphicsConfiguration. + * + * @param width + * the width of image. + * @param height + * the height of image. + * @param transparency + * the transparency mode. + * @return the VolatileImage object. + */ + public abstract VolatileImage createCompatibleVolatileImage(int width, int height, + int transparency); + + /** + * Gets the bounds of area covered by the GraphicsConfiguration in the + * device coordinates space. + * + * @return the Rectangle of GraphicsConfiguration's bounds. + */ + public abstract Rectangle getBounds(); + + /** + * Gets the ColorModel of the GraphicsConfiguration. + * + * @return the ColorModel object of the GraphicsConfiguration. + */ + public abstract ColorModel getColorModel(); + + /** + * Gets the ColorModel of the GraphicsConfiguration which supports specified + * Transparency. + * + * @param transparency + * the Transparency mode: OPAQUE, BITMASK, or TRANSLUCENT. + * @return the ColorModel of the GraphicsConfiguration which supports + * specified Transparency. + */ + public abstract ColorModel getColorModel(int transparency); + + /** + * Gets the default AffineTransform of the GraphicsConfiguration. This + * method translates user coordinates to device coordinates. + * + * @return the default AffineTransform of the GraphicsConfiguration. + */ + public abstract AffineTransform getDefaultTransform(); + + /** + * Gets the GraphicsDevice of the GraphicsConfiguration. + * + * @return the GraphicsDevice of the GraphicsConfiguration. + */ + public abstract GraphicsDevice getDevice(); + + /** + * Gets the normalizing AffineTransform of the GraphicsConfiguration. + * + * @return the normalizing AffineTransform of the GraphicsConfiguration. + */ + public abstract AffineTransform getNormalizingTransform(); + + /** + * Creates VolatileImage with specified width, height, ImageCapabilities; a + * data layout and color model compatible with this GraphicsConfiguration. + * + * @param width + * the width of image. + * @param height + * the height of image. + * @param caps + * the ImageCapabilities object. + * @return the VolatileImage which data layout and color model compatible + * with this GraphicsConfiguration. + * @throws AWTException + * if ImageCapabilities is not supported by the + * GraphicsConfiguration. + */ + public VolatileImage createCompatibleVolatileImage(int width, int height, ImageCapabilities caps) + throws AWTException { + VolatileImage res = createCompatibleVolatileImage(width, height); + if (!res.getCapabilities().equals(caps)) { + // awt.14A=Can not create VolatileImage with specified capabilities + throw new AWTException(Messages.getString("awt.14A")); //$NON-NLS-1$ + } + return res; + } + + /** + * Creates a VolatileImage with specified width, height, transparency and + * ImageCapabilities; a data layout and color model compatible with this + * GraphicsConfiguration. + * + * @param width + * the width of image. + * @param height + * the height of image. + * @param caps + * the ImageCapabilities object. + * @param transparency + * the Transparency mode: OPAQUE, BITMASK, or TRANSLUCENT. + * @return the VolatileImage which data layout and color model compatible + * with this GraphicsConfiguration. + * @throws AWTException + * if ImageCapabilities is not supported by the + * GraphicsConfiguration. + */ + public VolatileImage createCompatibleVolatileImage(int width, int height, + ImageCapabilities caps, int transparency) throws AWTException { + VolatileImage res = createCompatibleVolatileImage(width, height, transparency); + if (!res.getCapabilities().equals(caps)) { + // awt.14A=Can not create VolatileImage with specified capabilities + throw new AWTException(Messages.getString("awt.14A")); //$NON-NLS-1$ + } + return res; + } + + /** + * Gets the buffering capabilities of the GraphicsConfiguration. + * + * @return the BufferCapabilities object. + */ + public BufferCapabilities getBufferCapabilities() { + return new BufferCapabilities(new ImageCapabilities(false), new ImageCapabilities(false), + BufferCapabilities.FlipContents.UNDEFINED); + } + + /** + * Gets the image capabilities of the GraphicsConfiguration. + * + * @return the ImageCapabilities object. + */ + public ImageCapabilities getImageCapabilities() { + return new ImageCapabilities(false); + } +} diff --git a/awt/java/awt/GraphicsDevice.java b/awt/java/awt/GraphicsDevice.java new file mode 100644 index 0000000..9eda4e0 --- /dev/null +++ b/awt/java/awt/GraphicsDevice.java @@ -0,0 +1,196 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The GraphicsDevice class describes the graphics devices (such as screens or + * printers) which are available in a particular graphics environment. Many + * GraphicsDevice instances can be associated with a single GraphicsEnvironment. + * Each GraphicsDevice has one or more GraphicsConfiguration objects which + * specify the different configurations and modes of GraphicsDevice. + * + * @since Android 1.0 + */ +public abstract class GraphicsDevice { + + /** + * The display mode. + */ + private DisplayMode displayMode; + + // ???AWT + // private Window fullScreenWindow = null; + + /** + * The Constant TYPE_IMAGE_BUFFER indicates a image buffer device. + */ + + public static final int TYPE_IMAGE_BUFFER = 2; + + /** + * The Constant TYPE_PRINTER indicates a printer device. + */ + public static final int TYPE_PRINTER = 1; + + /** + * The Constant TYPE_RASTER_SCREEN indicates a raster screen device. + */ + public static final int TYPE_RASTER_SCREEN = 0; + + /** + * Constructor is not to be used directly as this class is abstract. + */ + protected GraphicsDevice() { + displayMode = new DisplayMode(0, 0, DisplayMode.BIT_DEPTH_MULTI, + DisplayMode.REFRESH_RATE_UNKNOWN); + } + + /** + * Returns an array of GraphicsConfiguration objects associated with the + * GraphicsDevice. + * + * @return an array of GraphicsConfiguration objects associated with the + * GraphicsDevice. + */ + public abstract GraphicsConfiguration[] getConfigurations(); + + /** + * Gets the default configuration for the GraphicsDevice. + * + * @return the default GraphicsConfiguration object for the GraphicsDevice. + */ + public abstract GraphicsConfiguration getDefaultConfiguration(); + + /** + * Gets the String identifier which associated with the GraphicsDevice in + * the GraphicsEnvironment. + * + * @return the String identifier of the GraphicsDevice in the + * GraphicsEnvironment. + */ + public abstract String getIDstring(); + + /** + * Gets the type of this GraphicsDevice: TYPE_IMAGE_BUFFER, TYPE_PRINTER or + * TYPE_RASTER_SCREEN. + * + * @return the type of this GraphicsDevice: TYPE_IMAGE_BUFFER, TYPE_PRINTER + * or TYPE_RASTER_SCREEN. + */ + public abstract int getType(); + + /** + * Returns the number of bytes available in accelerated memory on this + * device. + * + * @return the number of bytes available accelerated memory. + */ + public int getAvailableAcceleratedMemory() { + return 0; + } + + /* + * ???AWT public GraphicsConfiguration + * getBestConfiguration(GraphicsConfigTemplate gct) { return + * gct.getBestConfiguration(getConfigurations()); } + */ + + /** + * Gets the current display mode of the GraphicsDevice. + * + * @return the current display mode of the GraphicsDevice. + */ + public DisplayMode getDisplayMode() { + return displayMode; + } + + /** + * Gets an array of display modes available in this GraphicsDevice. + * + * @return an array of display modes available in this GraphicsDevice. + */ + public DisplayMode[] getDisplayModes() { + DisplayMode[] dms = { + displayMode + }; + return dms; + } + + /* + * ???AWT public Window getFullScreenWindow() { return fullScreenWindow; } + */ + + /** + * Returns true if this GraphicsDevice supports low-level display changes. + * + * @return true, if this GraphicsDevice supports low-level display changes; + * false otherwise. + */ + public boolean isDisplayChangeSupported() { + return false; + } + + /** + * Returns true if this GraphicsDevice supports full screen mode. + * + * @return true, if this GraphicsDevice supports full screen mode, false + * otherwise. + */ + public boolean isFullScreenSupported() { + return false; + } + + // an array of display modes available in this GraphicsDevice. + + /** + * Sets the display mode of this GraphicsDevice. + * + * @param dm + * the new display mode of this GraphicsDevice. + */ + public void setDisplayMode(DisplayMode dm) { + if (!isDisplayChangeSupported()) { + // awt.122=Does not support display mode changes + throw new UnsupportedOperationException(Messages.getString("awt.122")); //$NON-NLS-1$ + } + + DisplayMode[] dms = getDisplayModes(); + for (DisplayMode element : dms) { + if (element.equals(dm)) { + displayMode = dm; + return; + } + } + // awt.123=Unsupported display mode: {0} + throw new IllegalArgumentException(Messages.getString("awt.123", dm)); //$NON-NLS-1$ + } + + /* + * ???AWT public void setFullScreenWindow(Window w) { if (w == null) { + * fullScreenWindow = null; return; } fullScreenWindow = w; if + * (isFullScreenSupported()) { w.enableInputMethods(false); } else { + * w.setSize(displayMode.getWidth(), displayMode.getHeight()); + * w.setLocation(0, 0); } w.setVisible(true); w.setAlwaysOnTop(true); } + */ +} diff --git a/awt/java/awt/GraphicsEnvironment.java b/awt/java/awt/GraphicsEnvironment.java new file mode 100644 index 0000000..d527417 --- /dev/null +++ b/awt/java/awt/GraphicsEnvironment.java @@ -0,0 +1,212 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt; + +import java.awt.image.BufferedImage; +import java.util.Locale; + +import org.apache.harmony.awt.ContextStorage; +import org.apache.harmony.awt.gl.CommonGraphics2DFactory; + +/** + * The GraphicsEnvironment class defines a collection of GraphicsDevice objects + * and Font objects which are available for Java application on current + * platform. + * + * @since Android 1.0 + */ +public abstract class GraphicsEnvironment { + + /** + * Constructor could not be used directly and should be obtained in extended + * classes. + */ + protected GraphicsEnvironment() { + } + + /** + * Gets the local GraphicsEnvironment. + * + * @return the local GraphicsEnvironment. + */ + public static GraphicsEnvironment getLocalGraphicsEnvironment() { + synchronized (ContextStorage.getContextLock()) { + if (ContextStorage.getGraphicsEnvironment() == null) { + if (isHeadless()) { + ContextStorage.setGraphicsEnvironment(new HeadlessGraphicsEnvironment()); + } else { + CommonGraphics2DFactory g2df = (CommonGraphics2DFactory)Toolkit + .getDefaultToolkit().getGraphicsFactory(); + + ContextStorage.setGraphicsEnvironment(g2df + .createGraphicsEnvironment(ContextStorage.getWindowFactory())); + } + } + + return ContextStorage.getGraphicsEnvironment(); + } + } + + /** + * Returns whether or not a display, keyboard, and mouse are supported in + * this graphics environment. + * + * @return true, if HeadlessException will be thrown from areas of the + * graphics environment that are dependent on a display, keyboard, + * or mouse, false otherwise. + */ + public boolean isHeadlessInstance() { + return false; + } + + /** + * Checks whether or not a display, keyboard, and mouse are supported in + * this environment. + * + * @return true, if a HeadlessException is thrown from areas of the Toolkit + * and GraphicsEnvironment that are dependent on a display, + * keyboard, or mouse, false otherwise. + */ + public static boolean isHeadless() { + return "true".equals(System.getProperty("java.awt.headless")); + } + + /** + * Gets the maximum bounds of system centered windows. + * + * @return the maximum bounds of system centered windows. + * @throws HeadlessException + * if isHeadless() method returns true. + */ + public Rectangle getMaximumWindowBounds() throws HeadlessException { + return getDefaultScreenDevice().getDefaultConfiguration().getBounds(); + } + + /** + * Gets the Point which should defines the center of system window. + * + * @return the Point where the system window should be centered. + * @throws HeadlessException + * if isHeadless() method returns true. + */ + public Point getCenterPoint() throws HeadlessException { + Rectangle mwb = getMaximumWindowBounds(); + return new Point(mwb.width >> 1, mwb.height >> 1); + } + + /** + * Indicates that the primary font should be used. Primary font is specified + * by initial system locale or default encoding). + */ + public void preferLocaleFonts() { + // Note: API specification says following: + // "The actual change in font rendering behavior resulting + // from a call to this method is implementation dependent; + // it may have no effect at all." So, doing nothing is an + // acceptable behavior for this method. + + // For now FontManager uses 1.4 font.properties scheme for font mapping, + // so + // this method doesn't make any sense. The implementation of this method + // which will influence font mapping is postponed until + // 1.5 mapping scheme not implemented. + + // todo - Implement non-default behavior with 1.5 font mapping scheme + } + + /** + * Indicates that a proportional preference of the font should be used. + */ + public void preferProportionalFonts() { + // Note: API specification says following: + // "The actual change in font rendering behavior resulting + // from a call to this method is implementation dependent; + // it may have no effect at all." So, doing nothing is an + // acceptable behavior for this method. + + // For now FontManager uses 1.4 font.properties scheme for font mapping, + // so + // this method doesn't make any sense. The implementation of this method + // which will influence font mapping is postponed until + // 1.5 mapping scheme not implemented. + + // todo - Implement non-default behavior with 1.5 font mapping scheme + } + + /** + * Creates the Graphics2D object for rendering to the specified + * BufferedImage. + * + * @param bufferedImage + * the BufferedImage object. + * @return the Graphics2D object which allows to render to the specified + * BufferedImage. + */ + public abstract Graphics2D createGraphics(BufferedImage bufferedImage); + + /** + * Gets the array of all available fonts instances in this + * GraphicsEnviroments. + * + * @return the array of all available fonts instances in this + * GraphicsEnviroments. + */ + public abstract Font[] getAllFonts(); + + /** + * Gets the array of all available font family names. + * + * @return the array of all available font family names. + */ + public abstract String[] getAvailableFontFamilyNames(); + + /** + * Gets the array of all available font family names for the specified + * locale. + * + * @param locale + * the Locale object which represents geographical region. The + * default locale is used if locale is null. + * @return the array of available font family names for the specified + * locale. + */ + public abstract String[] getAvailableFontFamilyNames(Locale locale); + + /** + * Gets the default screen device as GraphicDevice object. + * + * @return the GraphicDevice object which represents default screen device. + * @throws HeadlessException + * if isHeadless() returns true. + */ + public abstract GraphicsDevice getDefaultScreenDevice() throws HeadlessException; + + /** + * Gets an array of all available screen devices. + * + * @return the array of GraphicsDevice objects which represents all + * available screen devices. + * @throws HeadlessException + * if isHeadless() returns true. + */ + public abstract GraphicsDevice[] getScreenDevices() throws HeadlessException; +} diff --git a/awt/java/awt/HeadlessException.java b/awt/java/awt/HeadlessException.java new file mode 100644 index 0000000..ec111f1 --- /dev/null +++ b/awt/java/awt/HeadlessException.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt; + +/** + * The HeadlessException class provides notifications and error messages when + * code that is dependent on a keyboard, display, or mouse is called in an + * environment that does not support a keyboard, display, or mouse. + * + * @since Android 1.0 + */ +public class HeadlessException extends UnsupportedOperationException { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 167183644944358563L; + + /** + * Instantiates a new headless exception. + */ + public HeadlessException() { + super(); + } + + /** + * Instantiates a new headless exception with the specified message. + * + * @param msg + * the String which represents error message. + */ + public HeadlessException(String msg) { + super(msg); + } +} diff --git a/awt/java/awt/HeadlessGraphicsEnvironment.java b/awt/java/awt/HeadlessGraphicsEnvironment.java new file mode 100644 index 0000000..306393f --- /dev/null +++ b/awt/java/awt/HeadlessGraphicsEnvironment.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.awt; + +import java.awt.GraphicsDevice; +import java.awt.HeadlessException; + +import org.apache.harmony.awt.gl.CommonGraphicsEnvironment; + +/** + * The HeadlessGraphicsEnvironment class is the CommonGraphicsEnvironment + * implementation to use in the case where the environment lacks display, + * keyboard, and mouse support. + * + * @since Android 1.0 + */ +public class HeadlessGraphicsEnvironment extends CommonGraphicsEnvironment { + + /** + * Returns whether or not a display, keyboard, and mouse are supported in + * this graphics environment. + * + * @return true, if HeadlessException will be thrown from areas of the + * graphics environment that are dependent on a display, keyboard, + * or mouse, false otherwise. + */ + @Override + public boolean isHeadlessInstance() { + return true; + } + + /** + * Gets the default screen device as GraphicDevice object. + * + * @return the GraphicDevice object which represents default screen device. + * @throws HeadlessException + * if isHeadless() returns true. + */ + @Override + public GraphicsDevice getDefaultScreenDevice() throws HeadlessException { + throw new HeadlessException(); + } + + /** + * Gets an array of all available screen devices. + * + * @return the array of GraphicsDevice objects which represents all + * available screen devices. + * @throws HeadlessException + * if isHeadless() returns true. + */ + @Override + public GraphicsDevice[] getScreenDevices() throws HeadlessException { + throw new HeadlessException(); + } + +} diff --git a/awt/java/awt/HeadlessToolkit.java b/awt/java/awt/HeadlessToolkit.java new file mode 100644 index 0000000..c64a85a --- /dev/null +++ b/awt/java/awt/HeadlessToolkit.java @@ -0,0 +1,226 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.awt; + +//???AWT +//import java.awt.datatransfer.Clipboard; +//import java.awt.dnd.DragGestureEvent; +//import java.awt.dnd.DragGestureListener; +//import java.awt.dnd.DragGestureRecognizer; +//import java.awt.dnd.DragSource; +//import java.awt.dnd.InvalidDnDOperationException; +//import java.awt.dnd.peer.DragSourceContextPeer; +import java.awt.im.InputMethodHighlight; +import java.awt.image.ColorModel; //import java.awt.peer.*; +//import java.beans.PropertyChangeSupport; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.apache.harmony.awt.ComponentInternals; //import org.apache.harmony.awt.datatransfer.DTK; +import org.apache.harmony.awt.wtk.GraphicsFactory; +import org.apache.harmony.awt.wtk.NativeEventQueue; +import org.apache.harmony.awt.wtk.WindowFactory; + +/** + * The HeadlessToolkit class is a subclass of ToolkitImpl to be used for + * graphical environments that lack keyboard and mouse capabilities. + * + * @since Android 1.0 + */ +public final class HeadlessToolkit extends ToolkitImpl { + + // ???AWT + /* + * @Override protected ButtonPeer createButton(Button a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected CheckboxPeer createCheckbox(Checkbox a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected CheckboxMenuItemPeer + * createCheckboxMenuItem(CheckboxMenuItem a0) throws HeadlessException { + * throw new HeadlessException(); } + * @Override protected ChoicePeer createChoice(Choice a0) throws + * HeadlessException { throw new HeadlessException(); } public Cursor + * createCustomCursor(Image img, Point hotSpot, String name) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected DialogPeer createDialog(Dialog a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override public <T extends DragGestureRecognizer> T + * createDragGestureRecognizer( Class<T> recognizerAbstractClass, DragSource + * ds, Component c, int srcActions, DragGestureListener dgl) { return null; + * } + * @Override public DragSourceContextPeer + * createDragSourceContextPeer(DragGestureEvent dge) throws + * InvalidDnDOperationException { throw new InvalidDnDOperationException(); + * } + * @Override protected FileDialogPeer createFileDialog(FileDialog a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected FramePeer createFrame(Frame a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected LabelPeer createLabel(Label a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected ListPeer createList(List a0) throws HeadlessException + * { throw new HeadlessException(); } + * @Override protected MenuPeer createMenu(Menu a0) throws HeadlessException + * { throw new HeadlessException(); } + * @Override protected MenuBarPeer createMenuBar(MenuBar a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected MenuItemPeer createMenuItem(MenuItem a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected PopupMenuPeer createPopupMenu(PopupMenu a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected ScrollbarPeer createScrollbar(Scrollbar a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected ScrollPanePeer createScrollPane(ScrollPane a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected TextAreaPeer createTextArea(TextArea a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected TextFieldPeer createTextField(TextField a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected WindowPeer createWindow(Window a0) throws + * HeadlessException { throw new HeadlessException(); } + */ + + @Override + public Dimension getBestCursorSize(int prefWidth, int prefHeight) throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public ColorModel getColorModel() throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public GraphicsFactory getGraphicsFactory() throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public boolean getLockingKeyState(int keyCode) throws UnsupportedOperationException { + throw new HeadlessException(); + } + + @Override + public int getMaximumCursorColors() throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public int getMenuShortcutKeyMask() throws HeadlessException { + throw new HeadlessException(); + } + + // ???AWT + /* + * @Override NativeEventQueue getNativeEventQueue() throws HeadlessException + * { throw new HeadlessException(); } + * @Override public PrintJob getPrintJob(Frame frame, String jobtitle, + * JobAttributes jobAttributes, PageAttributes pageAttributes) throws + * IllegalArgumentException { throw new IllegalArgumentException(); } + * @Override public PrintJob getPrintJob(Frame frame, String jobtitle, + * Properties props) throws NullPointerException { throw new + * NullPointerException(); } + */ + + @Override + public Insets getScreenInsets(GraphicsConfiguration gc) throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public int getScreenResolution() throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public Dimension getScreenSize() throws HeadlessException { + throw new HeadlessException(); + } + + // ???AWT + /* + * @Override public Clipboard getSystemClipboard() throws HeadlessException + * { throw new HeadlessException(); } + * @Override public Clipboard getSystemSelection() throws HeadlessException + * { throw new HeadlessException(); } + * @Override WindowFactory getWindowFactory() throws HeadlessException { + * throw new HeadlessException(); } + */ + + @Override + protected void init() { + lockAWT(); + try { + ComponentInternals.setComponentInternals(new ComponentInternalsImpl()); + // ???AWT: new EventQueue(this); // create the system EventQueue + // ???AWT: dispatcher = new Dispatcher(this); + desktopProperties = new HashMap<String, Object>(); + // ???AWT: desktopPropsSupport = new PropertyChangeSupport(this); + // ???AWT: awtEventsManager = new AWTEventsManager(); + // ???AWT: dispatchThread = new HeadlessEventDispatchThread(this, + // dispatcher); + // ???AWT: dtk = DTK.getDTK(); + dispatchThread.start(); + } finally { + unlockAWT(); + } + } + + @Override + public boolean isDynamicLayoutActive() throws HeadlessException { + throw new HeadlessException(); + } + + @Override + protected boolean isDynamicLayoutSet() throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public boolean isFrameStateSupported(int state) throws HeadlessException { + throw new HeadlessException(); + } + + @Override + protected void loadSystemColors(int[] systemColors) throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public Map<java.awt.font.TextAttribute, ?> mapInputMethodHighlight( + InputMethodHighlight highlight) throws HeadlessException { + throw new HeadlessException(); + } + + @Override + Map<java.awt.font.TextAttribute, ?> mapInputMethodHighlightImpl(InputMethodHighlight highlight) + throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public void setDynamicLayout(boolean dynamic) throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public void setLockingKeyState(int keyCode, boolean on) throws UnsupportedOperationException { + throw new HeadlessException(); + } +} diff --git a/awt/java/awt/IllegalComponentStateException.java b/awt/java/awt/IllegalComponentStateException.java new file mode 100644 index 0000000..bed1729 --- /dev/null +++ b/awt/java/awt/IllegalComponentStateException.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ + +package java.awt; + +/** + * The IllegalComponentStateException class is used to provide notification that + * AWT component is not in an appropriate state for the requested operation. + * + * @since Android 1.0 + */ +public class IllegalComponentStateException extends IllegalStateException { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -1889339587208144238L; + + /** + * Instantiates a new IllegalComponentStateException with the specified + * message. + * + * @param s + * the String message which describes the exception. + */ + public IllegalComponentStateException(String s) { + super(s); + } + + /** + * Instantiates a new IllegalComponentStateException without detailed + * message. + */ + public IllegalComponentStateException() { + } + +} diff --git a/awt/java/awt/Image.java b/awt/java/awt/Image.java new file mode 100644 index 0000000..7ae3ed8 --- /dev/null +++ b/awt/java/awt/Image.java @@ -0,0 +1,205 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt; + +import java.awt.image.AreaAveragingScaleFilter; +import java.awt.image.FilteredImageSource; +import java.awt.image.ImageFilter; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.ReplicateScaleFilter; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Image abstract class represents the graphic images. + * + * @since Android 1.0 + */ +public abstract class Image { + + /** + * The UndefinedProperty object should be returned if property is not + * defined for a particular image. + */ + public static final Object UndefinedProperty = new Object(); // $NON-LOCK-1$ + + /** + * The Constant SCALE_DEFAULT indicates the default image scaling algorithm. + */ + public static final int SCALE_DEFAULT = 1; + + /** + * The Constant SCALE_FAST indicates an image scaling algorithm which places + * a higher priority on scaling speed than on the image's smoothness. + */ + public static final int SCALE_FAST = 2; + + /** + * The Constant SCALE_SMOOTH indicates an image scaling algorithm which + * places a higher priority on image smoothness than on scaling speed. + */ + public static final int SCALE_SMOOTH = 4; + + /** + * The Constant SCALE_REPLICATE indicates the image scaling algorithm in the + * ReplicateScaleFilter class. + */ + public static final int SCALE_REPLICATE = 8; + + /** + * The Constant SCALE_AREA_AVERAGING indicates the area averaging image + * scaling algorithm. + */ + public static final int SCALE_AREA_AVERAGING = 16; + + /** + * The acceleration priority indicates image acceleration. + */ + protected float accelerationPriority = 0.5f; + + /** + * The Constant capabilities. + */ + private static final ImageCapabilities capabilities = new ImageCapabilities(false); + + /** + * Gets the image property with the specified name. The UndefinedProperty + * object should be return if the property is not specified for this image. + * The return value should be null if the property is currently unknown yet + * and the specified ImageObserver is to be notified later. + * + * @param name + * the name of image's property. + * @param observer + * the ImageObserver. + * @return the Object which represents value of the specified property. + */ + public abstract Object getProperty(String name, ImageObserver observer); + + /** + * Gets the ImageProducer object which represents data of this Image. + * + * @return the ImageProducer object which represents data of this Image. + */ + public abstract ImageProducer getSource(); + + /** + * Gets the width of this image. The specified ImageObserver object is + * notified when the width of this image is available. + * + * @param observer + * the ImageObserver object which is is notified when the width + * of this image is available. + * @return the width of image, or -1 if the width of this image is not + * available. + */ + public abstract int getWidth(ImageObserver observer); + + /** + * Gets the height of this image. The specified ImageObserver object is + * notified when the height of this image is available. + * + * @param observer + * the ImageObserver object which is is notified when the height + * of this image is available. + * @return the height of image, or -1 if the height of this image is not + * available. + */ + public abstract int getHeight(ImageObserver observer); + + /** + * Gets the scaled instance of this Image. This method returns an Image + * object constructed from the source of this image with the specified + * width, height, and applied scaling algorithm. + * + * @param width + * the width of scaled Image. + * @param height + * the height of scaled Image. + * @param hints + * the constant which indicates scaling algorithm. + * @return the scaled Image. + */ + public Image getScaledInstance(int width, int height, int hints) { + ImageFilter filter; + if ((hints & (SCALE_SMOOTH | SCALE_AREA_AVERAGING)) != 0) { + filter = new AreaAveragingScaleFilter(width, height); + } else { + filter = new ReplicateScaleFilter(width, height); + } + ImageProducer producer = new FilteredImageSource(getSource(), filter); + return Toolkit.getDefaultToolkit().createImage(producer); + } + + /** + * Gets a Graphics object for rendering this image. This method can be used + * for off-screen images. + * + * @return a Graphics object for rendering to this image. + */ + public abstract Graphics getGraphics(); + + /** + * Flushes resources which are used by this Image object. This method resets + * the image to the reconstructed state from the image's source. + */ + public abstract void flush(); + + /** + * Gets the acceleration priority of this image. + * + * @return the acceleration priority of this image. + */ + public float getAccelerationPriority() { + return accelerationPriority; + } + + /** + * Sets the acceleration priority for this image. + * + * @param priority + * the new acceleration priority (value in the range 0-1). + */ + public void setAccelerationPriority(float priority) { + if (priority < 0 || priority > 1) { + // awt.10A=Priority must be a value between 0 and 1, inclusive + throw new IllegalArgumentException(Messages.getString("awt.10A")); //$NON-NLS-1$ + } + accelerationPriority = priority; + } + + /** + * Gets an ImageCapabilities object of this Image object for the specified + * GraphicsConfiguration. + * + * @param gc + * the specified GraphicsConfiguration object (null value means + * default GraphicsConfiguration). + * @return an ImageCapabilities object of this Image object for the + * specified GraphicsConfiguration. + */ + public ImageCapabilities getCapabilities(GraphicsConfiguration gc) { + // Note: common image is not accelerated. + return capabilities; + } +} diff --git a/awt/java/awt/ImageCapabilities.java b/awt/java/awt/ImageCapabilities.java new file mode 100644 index 0000000..c6d5946 --- /dev/null +++ b/awt/java/awt/ImageCapabilities.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt; + +/** + * The ImageCapabilities class gives information about an image's capabilities. + * + * @since Android 1.0 + */ +public class ImageCapabilities implements Cloneable { + + /** + * The accelerated. + */ + private final boolean accelerated; + + /** + * Instantiates a new ImageCapabilities with the specified acceleration flag + * which indicates whether acceleration is desired or not. + * + * @param accelerated + * the accelerated flag. + */ + public ImageCapabilities(boolean accelerated) { + this.accelerated = accelerated; + } + + /** + * Returns a copy of this ImageCapabilities object. + * + * @return the copy of this ImageCapabilities object. + */ + @Override + public Object clone() { + return new ImageCapabilities(accelerated); + } + + /** + * Returns true if the Image of this ImageCapabilities is or can be + * accelerated. + * + * @return true, if the Image of this ImageCapabilities is or can be + * accelerated, false otherwise. + */ + public boolean isAccelerated() { + return accelerated; + } + + /** + * Returns true if this ImageCapabilities applies to the VolatileImage which + * can lose its surfaces. + * + * @return true if this ImageCapabilities applies to the VolatileImage which + * can lose its surfaces, false otherwise. + */ + public boolean isTrueVolatile() { + return true; + } +} diff --git a/awt/java/awt/Insets.java b/awt/java/awt/Insets.java new file mode 100644 index 0000000..04f198c6 --- /dev/null +++ b/awt/java/awt/Insets.java @@ -0,0 +1,179 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev + * @version $Revision$ + */ + +package java.awt; + +import java.io.Serializable; + +import org.apache.harmony.misc.HashCode; + +/** + * The Insets class represents the borders of a container. This class describes + * the space that a container should leave at each edge: the top, the bottom, + * the right side, and the left side. The space can be filled with a border, a + * blank space, or a title. + * + * @since Android 1.0 + */ +public class Insets implements Cloneable, Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -2272572637695466749L; + + /** + * The top inset indicates the size of the space added to the top of the + * rectangle. + */ + public int top; + + /** + * The left inset indicates the size of the space added to the left side of + * the rectangle. + */ + public int left; + + /** + * The bottom inset indicates the size of the space subtracted from the + * bottom of the rectangle. + */ + public int bottom; + + /** + * The right inset indicates the size of the space subtracted from the right + * side of the rectangle. + */ + public int right; + + /** + * Instantiates a new Inset object with the specified top, left, bottom, + * right parameters. + * + * @param top + * the top inset. + * @param left + * the left inset. + * @param bottom + * the bottom inset. + * @param right + * the right inset. + */ + public Insets(int top, int left, int bottom, int right) { + setValues(top, left, bottom, right); + } + + /** + * Returns a hash code of the Insets object. + * + * @return a hash code of the Insets object. + */ + @Override + public int hashCode() { + int hashCode = HashCode.EMPTY_HASH_CODE; + hashCode = HashCode.combine(hashCode, top); + hashCode = HashCode.combine(hashCode, left); + hashCode = HashCode.combine(hashCode, bottom); + hashCode = HashCode.combine(hashCode, right); + return hashCode; + } + + /** + * Returns a copy of this Insets object. + * + * @return a copy of this Insets object. + */ + @Override + public Object clone() { + return new Insets(top, left, bottom, right); + } + + /** + * Checks if this Insets object is equal to the specified object. + * + * @param o + * the Object to be compared. + * @return true, if the object is an Insets object whose data values are + * equal to those of this object, false otherwise. + */ + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof Insets) { + Insets i = (Insets)o; + return ((i.left == left) && (i.bottom == bottom) && (i.right == right) && (i.top == top)); + } + return false; + } + + /** + * Returns a String representation of this Insets object. + * + * @return a String representation of this Insets object. + */ + @Override + public String toString() { + /* + * The format is based on 1.5 release behavior which can be revealed by + * the following code: System.out.println(new Insets(1, 2, 3, 4)); + */ + + return (getClass().getName() + "[left=" + left + ",top=" + top + //$NON-NLS-1$ //$NON-NLS-2$ + ",right=" + right + ",bottom=" + bottom + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + /** + * Sets top, left, bottom, and right insets to the specified values. + * + * @param top + * the top inset. + * @param left + * the left inset. + * @param bottom + * the bottom inset. + * @param right + * the right inset. + */ + public void set(int top, int left, int bottom, int right) { + setValues(top, left, bottom, right); + } + + /** + * Sets the values. + * + * @param top + * the top. + * @param left + * the left. + * @param bottom + * the bottom. + * @param right + * the right. + */ + private void setValues(int top, int left, int bottom, int right) { + this.top = top; + this.left = left; + this.bottom = bottom; + this.right = right; + } +} diff --git a/awt/java/awt/ItemSelectable.java b/awt/java/awt/ItemSelectable.java new file mode 100644 index 0000000..212cf70 --- /dev/null +++ b/awt/java/awt/ItemSelectable.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ + +package java.awt; + +import java.awt.event.ItemListener; + +/** + * The ItemSelectable interface represents a set of items which can be selected. + * + * @since Android 1.0 + */ +public interface ItemSelectable { + + /** + * Adds an ItemListener for receiving item events when the state of an item + * is changed by the user. + * + * @param l + * the ItemListener. + */ + public void addItemListener(ItemListener l); + + /** + * Gets an array of the selected objects or null if there is no selected + * object. + * + * @return an array of the selected objects or null if there is no selected + * object. + */ + public Object[] getSelectedObjects(); + + /** + * Removes the specified ItemListener. + * + * @param l + * the ItemListener which will be removed. + */ + public void removeItemListener(ItemListener l); + +} diff --git a/awt/java/awt/MenuComponent.java b/awt/java/awt/MenuComponent.java new file mode 100644 index 0000000..9c1b120 --- /dev/null +++ b/awt/java/awt/MenuComponent.java @@ -0,0 +1,783 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.awt; + +import java.awt.event.FocusListener; +import java.awt.event.MouseEvent; +import java.awt.peer.MenuComponentPeer; +import java.io.Serializable; +import java.util.Locale; //import javax.accessibility.Accessible; +//import javax.accessibility.AccessibleComponent; +//import javax.accessibility.AccessibleContext; +//import javax.accessibility.AccessibleRole; +//import javax.accessibility.AccessibleSelection; +//import javax.accessibility.AccessibleStateSet; +import org.apache.harmony.awt.gl.MultiRectArea; +import org.apache.harmony.awt.state.MenuItemState; +import org.apache.harmony.awt.state.MenuState; +import org.apache.harmony.luni.util.NotImplementedException; + +/** + * The MenuComponent abstract class is the superclass for menu components. Menu + * components receive and process AWT events. + * + * @since Android 1.0 + */ +public abstract class MenuComponent implements Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -4536902356223894379L; + + /** + * The name. + */ + private String name; + + /** + * The font. + */ + private Font font; + + /** + * The parent. + */ + MenuContainer parent; + + /** + * The deprecated event handler. + */ + boolean deprecatedEventHandler = true; + + /** + * The selected item index. + */ + private int selectedItemIndex; + + // ???AWT: private AccessibleContext accessibleContext; + + /** + * The toolkit. + */ + final Toolkit toolkit = Toolkit.getDefaultToolkit(); + + // ???AWT + /* + * protected abstract class AccessibleAWTMenuComponent extends + * AccessibleContext implements Serializable, AccessibleComponent, + * AccessibleSelection { private static final long serialVersionUID = + * -4269533416223798698L; public void addFocusListener(FocusListener + * listener) { } public boolean contains(Point pt) { return false; } public + * Accessible getAccessibleAt(Point pt) { return null; } public Color + * getBackground() { return null; } public Rectangle getBounds() { return + * null; } public Cursor getCursor() { return null; } public Font getFont() + * { return MenuComponent.this.getFont(); } public FontMetrics + * getFontMetrics(Font font) { return null; } public Color getForeground() { + * return null; } public Point getLocation() { return null; } public Point + * getLocationOnScreen() { return null; } public Dimension getSize() { + * return null; } public boolean isEnabled() { return true; // always + * enabled } public boolean isFocusTraversable() { return true; // always + * focus traversable } public boolean isShowing() { return true;// always + * showing } public boolean isVisible() { return true; // always visible } + * public void removeFocusListener(FocusListener listener) { } public void + * requestFocus() { } public void setBackground(Color color) { } public void + * setBounds(Rectangle rect) { } public void setCursor(Cursor cursor) { } + * public void setEnabled(boolean enabled) { } public void setFont(Font + * font) { MenuComponent.this.setFont(font); } public void + * setForeground(Color color) { } public void setLocation(Point pt) { } + * public void setSize(Dimension pt) { } public void setVisible(boolean + * visible) { } public void addAccessibleSelection(int index) { } public + * void clearAccessibleSelection() { } public Accessible + * getAccessibleSelection(int index) { return null; } public int + * getAccessibleSelectionCount() { return 0; } public boolean + * isAccessibleChildSelected(int index) { return false; } public void + * removeAccessibleSelection(int index) { } public void + * selectAllAccessibleSelection() { } + * @Override public Accessible getAccessibleChild(int index) { return null; + * } + * @Override public int getAccessibleChildrenCount() { return 0; } + * @Override public AccessibleComponent getAccessibleComponent() { return + * this; } + * @Override public String getAccessibleDescription() { return + * super.getAccessibleDescription(); } + * @Override public int getAccessibleIndexInParent() { toolkit.lockAWT(); + * try { Accessible aParent = getAccessibleParent(); int aIndex = -1; if + * (aParent instanceof MenuComponent) { MenuComponent parent = + * (MenuComponent) aParent; int count = parent.getItemCount(); for (int i = + * 0; i < count; i++) { MenuComponent comp = parent.getItem(i); if (comp + * instanceof Accessible) { aIndex++; if (comp == MenuComponent.this) { + * return aIndex; } } } } return -1; } finally { toolkit.unlockAWT(); } } + * @Override public String getAccessibleName() { return + * super.getAccessibleName(); } + * @Override public Accessible getAccessibleParent() { toolkit.lockAWT(); + * try { Accessible aParent = super.getAccessibleParent(); if (aParent != + * null) { return aParent; } MenuContainer parent = getParent(); if (parent + * instanceof Accessible) { aParent = (Accessible) parent; } return aParent; + * } finally { toolkit.unlockAWT(); } } + * @Override public AccessibleRole getAccessibleRole() { return + * AccessibleRole.AWT_COMPONENT; } + * @Override public AccessibleSelection getAccessibleSelection() { return + * this; } + * @Override public AccessibleStateSet getAccessibleStateSet() { return new + * AccessibleStateSet(); } + * @Override public Locale getLocale() { return Locale.getDefault(); } } + */ + + /** + * The accessor to MenuComponent internal state, utilized by the visual + * theme. + * + * @throws HeadlessException + * the headless exception. + */ + // ???AWT + /* + * class State implements MenuState { Dimension size; Dimension getSize() { + * if (size == null) { calculate(); } return size; } public int getWidth() { + * return getSize().width; } public int getHeight() { return + * getSize().height; } public Font getFont() { return + * MenuComponent.this.getFont(); } public int getItemCount() { return + * MenuComponent.this.getItemCount(); } public int getSelectedItemIndex() { + * return MenuComponent.this.getSelectedItemIndex(); } public boolean + * isFontSet() { return MenuComponent.this.isFontSet(); } + * @SuppressWarnings("deprecation") public FontMetrics getFontMetrics(Font + * f) { return MenuComponent.this.toolkit.getFontMetrics(f); } public Point + * getLocation() { return MenuComponent.this.getLocation(); } public + * MenuItemState getItem(int index) { MenuItem item = + * MenuComponent.this.getItem(index); return item.itemState; } public void + * setSize(int w, int h) { this.size = new Dimension(w, h); } void + * calculate() { size = new Dimension(); + * size.setSize(toolkit.theme.calculateMenuSize(this)); } void reset() { for + * (int i = 0; i < getItemCount(); i++) { ((MenuItem.State) + * getItem(i)).reset(); } } } + */ + + /** + * Pop-up box for menu. It transfers the paint events, keyboard and mouse + * events to the menu component itself. + */ + // ???AWT + /* + * class MenuPopupBox extends PopupBox { private final Point lastMousePos = + * new Point(); + * @Override boolean isMenu() { return true; } + * @Override void paint(Graphics gr) { MenuComponent.this.paint(gr); } + * @Override void onKeyEvent(int eventId, int vKey, long when, int + * modifiers) { MenuComponent.this.onKeyEvent(eventId, vKey, when, + * modifiers); } + * @Override void onMouseEvent(int eventId, Point where, int mouseButton, + * long when, int modifiers, int wheelRotation) { // prevent conflict of + * mouse and keyboard // when sub-menu drops down due to keyboard navigation + * if (lastMousePos.equals(where) && (eventId == MouseEvent.MOUSE_MOVED || + * eventId == MouseEvent.MOUSE_ENTERED)) { return; } + * lastMousePos.setLocation(where); MenuComponent.this.onMouseEvent(eventId, + * where, mouseButton, when, modifiers); } } + */ + + /** + * Instantiates a new MenuComponent object. + * + * @throws HeadlessException + * if the graphical interface environment can't support + * MenuComponents. + */ + public MenuComponent() throws HeadlessException { + toolkit.lockAWT(); + try { + Toolkit.checkHeadless(); + name = autoName(); + selectedItemIndex = -1; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the name of the MenuComponent object. + * + * @return the name of the MenuComponent object. + */ + public String getName() { + toolkit.lockAWT(); + try { + return name; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Returns a String representation of the MenuComponent object. + * + * @return a String representation of the MenuComponent object. + */ + @Override + public String toString() { + toolkit.lockAWT(); + try { + return getClass().getName() + "[" + paramString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the parent menu container. + * + * @return the parent. + */ + public MenuContainer getParent() { + toolkit.lockAWT(); + try { + return parent; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the name of the MenuComponent to the specified string. + * + * @param name + * the new name of the MenuComponent object. + */ + public void setName(String name) { + toolkit.lockAWT(); + try { + this.name = name; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Dispatches AWT event. + * + * @param event + * the AWTEvent. + */ + public final void dispatchEvent(AWTEvent event) { + toolkit.lockAWT(); + try { + processEvent(event); + if (deprecatedEventHandler) { + postDeprecatedEvent(event); + } + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Post deprecated event. + * + * @param event + * the event. + */ + void postDeprecatedEvent(AWTEvent event) { + Event evt = event.getEvent(); + if (evt != null) { + postEvent(evt); + } + } + + /** + * Gets the peer of the MenuComponent; an application must not use this + * method directly. + * + * @return the MenuComponentPeer object. + * @throws NotImplementedException + * if this method is not implemented by a subclass. + * @deprecated an application must not use this method directly. + */ + @Deprecated + public MenuComponentPeer getPeer() throws org.apache.harmony.luni.util.NotImplementedException { + toolkit.lockAWT(); + try { + } finally { + toolkit.unlockAWT(); + } + if (true) { + throw new RuntimeException("Method is not implemented"); //TODO: implement //$NON-NLS-1$ + } + return null; + } + + /** + * Gets the locking object of this MenuComponent. + * + * @return the locking object of this MenuComponent. + */ + protected final Object getTreeLock() { + return toolkit.awtTreeLock; + } + + /** + * Posts the Event to the MenuComponent. + * + * @param e + * the Event. + * @return true, if the event is posted successfully, false otherwise. + * @deprecated Replaced dispatchEvent method. + */ + @SuppressWarnings("deprecation") + @Deprecated + public boolean postEvent(Event e) { + toolkit.lockAWT(); + try { + if (parent != null) { + return parent.postEvent(e); + } + return false; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Returns the string representation of the MenuComponent state. + * + * @return returns the string representation of the MenuComponent state. + */ + protected String paramString() { + toolkit.lockAWT(); + try { + return getName(); + } finally { + toolkit.unlockAWT(); + } + } + + // ???AWT + /* + * public AccessibleContext getAccessibleContext() { toolkit.lockAWT(); try + * { if (accessibleContext == null) { accessibleContext = + * createAccessibleContext(); } return accessibleContext; } finally { + * toolkit.unlockAWT(); } } + */ + + /** + * Gets the font of the MenuComponent object. + * + * @return the Font of the MenuComponent object. + */ + public Font getFont() { + toolkit.lockAWT(); + try { + if (font == null && hasDefaultFont()) { + return toolkit.getDefaultFont(); + } + if (font == null && parent != null) { + return parent.getFont(); + } + return font; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks if is font set. + * + * @return true, if is font set + */ + boolean isFontSet() { + return font != null + || ((parent instanceof MenuComponent) && ((MenuComponent)parent).isFontSet()); + } + + /** + * Checks for default font. + * + * @return true, if successful. + */ + boolean hasDefaultFont() { + return false; + } + + /** + * Processes an AWTEevent on this menu component. + * + * @param event + * the AWTEvent. + */ + protected void processEvent(AWTEvent event) { + toolkit.lockAWT(); + try { + // do nothing + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Removes the peer of the MenuComponent. + */ + public void removeNotify() { + toolkit.lockAWT(); + try { + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the Font for this MenuComponent object. + * + * @param font + * the new Font to be used for this MenuComponent. + */ + public void setFont(Font font) { + toolkit.lockAWT(); + try { + this.font = font; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the parent. + * + * @param parent + * the new parent. + */ + void setParent(MenuContainer parent) { + this.parent = parent; + } + + /** + * Gets the location. + * + * @return the location. + */ + Point getLocation() { + // to be overridden + return new Point(0, 0); + } + + /** + * Gets the width. + * + * @return the width. + */ + int getWidth() { + // to be overridden + return 1; + } + + /** + * Gets the height. + * + * @return the height. + */ + int getHeight() { + // to be overridden + return 1; + } + + /** + * Recursively find the menu item for a menu shortcut. + * + * @param gr + * the gr. + * @return the menu item; or null if the item is not available for this + * shortcut. + */ + // ???AWT + /* + * MenuItem getShortcutMenuItemImpl(MenuShortcut ms) { if (ms == null) { + * return null; } for (int i = 0; i < getItemCount(); i++) { MenuItem mi = + * getItem(i); if (mi instanceof Menu) { mi = ((Menu) + * mi).getShortcutMenuItemImpl(ms); if (mi != null) { return mi; } } else if + * (ms.equals(mi.getShortcut())) { return mi; } } return null; } + */ + + void paint(Graphics gr) { + gr.setColor(Color.LIGHT_GRAY); + gr.fillRect(0, 0, getWidth(), getHeight()); + gr.setColor(Color.BLACK); + } + + /** + * Mouse events handler. + * + * @param eventId + * one of the MouseEvent.MOUSE_* constants. + * @param where + * mouse location. + * @param mouseButton + * mouse button that was pressed or released. + * @param when + * event time. + * @param modifiers + * input event modifiers. + */ + void onMouseEvent(int eventId, Point where, int mouseButton, long when, int modifiers) { + // to be overridden + } + + /** + * Keyboard event handler. + * + * @param eventId + * one of the KeyEvent.KEY_* constants. + * @param vKey + * the key code. + * @param when + * event time. + * @param modifiers + * input event modifiers. + */ + void onKeyEvent(int eventId, int vKey, long when, int modifiers) { + // to be overridden + } + + /** + * Post the ActionEvent or ItemEvent, depending on type of the menu item. + * + * @param index + * the index. + * @return the item rect. + */ + // ???AWT + /* + * void fireItemAction(int item, long when, int modifiers) { MenuItem mi = + * getItem(item); mi.itemSelected(when, modifiers); } MenuItem getItem(int + * index) { // to be overridden return null; } int getItemCount() { return + * 0; } + */ + + /** + * @return The sub-menu of currently selecetd item, or null if such a + * sub-menu is not available. + */ + // ???AWT + /* + * Menu getSelectedSubmenu() { if (selectedItemIndex < 0) { return null; } + * MenuItem item = getItem(selectedItemIndex); return (item instanceof Menu) + * ? (Menu) item : null; } + */ + + /** + * Convenience method for selectItem(index, true). + */ + // ???AWT + /* + * void selectItem(int index) { selectItem(index, true); } + */ + + /** + * Change the selection in the menu. + * + * @param index + * new selecetd item's index. + * @param showSubMenu + * if new selected item has a sub-menu, should that sub-menu be + * displayed. + */ + // ???AWT + /* + * void selectItem(int index, boolean showSubMenu) { if (selectedItemIndex + * == index) { return; } if (selectedItemIndex >= 0 && + * getItem(selectedItemIndex) instanceof Menu) { ((Menu) + * getItem(selectedItemIndex)).hide(); } MultiRectArea clip = + * getUpdateClip(index, selectedItemIndex); selectedItemIndex = index; + * Graphics gr = getGraphics(clip); if (gr != null) { paint(gr); } if + * (showSubMenu) { showSubMenu(selectedItemIndex); } } + */ + + /** + * Change the selected item to the next one in the requested direction + * moving cyclically, skipping separators + * + * @param forward + * the direction to move the selection. + * @param showSubMenu + * if new selected item has a sub-menu, should that sub-menu be + * displayed. + */ + // ???AWT + /* + * void selectNextItem(boolean forward, boolean showSubMenu) { int selected + * = getSelectedItemIndex(); int count = getItemCount(); if (count == 0) { + * return; } if (selected < 0) { selected = (forward ? count - 1 : 0); } int + * i = selected; do { i = (forward ? (i + 1) : (i + count - 1)) % count; i + * %= count; MenuItem item = getItem(i); if (!"-".equals(item.getLabel())) { + * //$NON-NLS-1$ selectItem(i, showSubMenu); return; } } while (i != + * selected); } void showSubMenu(int index) { if ((index < 0) || + * !isActive()) { return; } MenuItem item = getItem(index); if (item + * instanceof Menu) { Menu menu = ((Menu) getItem(index)); if + * (menu.getItemCount() == 0) { return; } Point location = + * getSubmenuLocation(index); menu.show(location.x, location.y, false); } } + */ + + /** + * @return the menu bar which is the root of current menu's hierarchy; or + * null if the hierarchy root is not a menu bar. + */ + // ???AWT + /* + * MenuBar getMenuBar() { if (parent instanceof MenuBar) { return (MenuBar) + * parent; } if (parent instanceof MenuComponent) { return ((MenuComponent) + * parent).getMenuBar(); } return null; } PopupBox getPopupBox() { return + * null; } + */ + + Rectangle getItemRect(int index) { + // to be overridden + return null; + } + + /** + * Determine the clip region when menu selection is changed from index1 to + * index2. + * + * @param index1 + * old selected item. + * @param index2 + * new selected item. + * @return the region to repaint. + */ + final MultiRectArea getUpdateClip(int index1, int index2) { + MultiRectArea clip = new MultiRectArea(); + if (index1 >= 0) { + clip.add(getItemRect(index1)); + } + if (index2 >= 0) { + clip.add(getItemRect(index2)); + } + return clip; + } + + /** + * Gets the submenu location. + * + * @param index + * the index. + * @return the submenu location. + */ + Point getSubmenuLocation(int index) { + // to be overridden + return new Point(0, 0); + } + + /** + * Gets the selected item index. + * + * @return the selected item index. + */ + int getSelectedItemIndex() { + return selectedItemIndex; + } + + /** + * Hide. + */ + void hide() { + selectedItemIndex = -1; + if (parent instanceof MenuComponent) { + ((MenuComponent)parent).itemHidden(this); + } + } + + /** + * Item hidden. + * + * @param mc + * the mc. + */ + void itemHidden(MenuComponent mc) { + // to be overridden + } + + /** + * Checks if is visible. + * + * @return true, if is visible. + */ + boolean isVisible() { + return true; + } + + /** + * Checks if is active. + * + * @return true, if is active. + */ + boolean isActive() { + return true; + } + + /** + * Hide all menu hierarchy. + */ + void endMenu() { + // ???AWT: toolkit.dispatcher.popupDispatcher.deactivateAll(); + } + + /** + * Handle the mouse click or Enter key event on a menu's item. + * + * @param when + * the event time. + * @param modifiers + * input event modifiers. + */ + void itemSelected(long when, int modifiers) { + endMenu(); + } + + /** + * Auto name. + * + * @return the string. + */ + String autoName() { + String name = getClass().getName(); + if (name.indexOf("$") != -1) { //$NON-NLS-1$ + return null; + } + // ???AWT: int number = toolkit.autoNumber.nextMenuComponent++; + int number = 0; + name = name.substring(name.lastIndexOf(".") + 1) + Integer.toString(number); //$NON-NLS-1$ + return name; + } + + /** + * Creates the Graphics object for the pop-up box of this menu component. + * + * @param clip + * the clip to set on this Graphics. + * @return the created Graphics object, or null if such object is not + * available. + */ + Graphics getGraphics(MultiRectArea clip) { + // to be overridden + return null; + } + + /** + * @return accessible context specific for particular menu component. + */ + // ???AWT + /* + * AccessibleContext createAccessibleContext() { return null; } + */ +} diff --git a/awt/java/awt/MenuContainer.java b/awt/java/awt/MenuContainer.java new file mode 100644 index 0000000..e509a1b --- /dev/null +++ b/awt/java/awt/MenuContainer.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ + +package java.awt; + +/** + * The MenuContainer interface represents all menu containers. + * + * @since Android 1.0 + */ +public interface MenuContainer { + + /** + * Removes the specified MenuComponent from the MenuContainer. + * + * @param c + * the MenuComponent. + */ + public void remove(MenuComponent c); + + /** + * Gets the Font of the MenuContainer. + * + * @return the font of the MenuContainer. + */ + public Font getFont(); + + /** + * Posts an Event. + * + * @param e + * the Event. + * @return true if the event is posted successfully, false otherwise. + * @deprecated Replaced by dispatchEvent method. + */ + @Deprecated + public boolean postEvent(Event e); + +} diff --git a/awt/java/awt/ModalContext.java b/awt/java/awt/ModalContext.java new file mode 100644 index 0000000..32a5912 --- /dev/null +++ b/awt/java/awt/ModalContext.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt; + +/** + * + * The context for nested event loop. It can be dialog, popup menu etc. + */ +class ModalContext { + + private boolean running = false; + + private final Toolkit toolkit; + + ModalContext() { + toolkit = Toolkit.getDefaultToolkit(); + } + + /** + * Set up and run modal loop in this context + * + */ + void runModalLoop() { + running = true; + toolkit.dispatchThread.runModalLoop(this); + } + + /** + * Leave the modal loop running in this context + * This method doesn't stops the loop immediately, + * it just sets the flag that says the modal loop to stop + * + */ + void endModalLoop() { + running = false; + } + + /** + * + * @return modal loop is currently running in this context + */ + boolean isModalLoopRunning() { + return running; + } + +} diff --git a/awt/java/awt/MouseDispatcher.java b/awt/java/awt/MouseDispatcher.java new file mode 100644 index 0000000..df48f9d --- /dev/null +++ b/awt/java/awt/MouseDispatcher.java @@ -0,0 +1,418 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev, Michael Danilov, Pavel Dolgov + * @version $Revision$ + */ +package java.awt; + +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.awt.Dispatcher.MouseGrabManager; +import java.util.EventListener; + +import org.apache.harmony.awt.wtk.NativeEvent; +import org.apache.harmony.awt.wtk.NativeWindow; + + +class MouseDispatcher { + + // Fields for synthetic mouse click events generation + private static final int clickDelta = 5; + private final long[] lastPressTime = new long[] {0l, 0l, 0l}; + private final Point[] lastPressPos = new Point[] {null, null, null}; + private final boolean[] buttonPressed = new boolean[] {false, false, false}; + private final int[] clickCount = new int[] {0, 0, 0}; + + // Fields for mouse entered/exited support + private Component lastUnderPointer = null; + private final Point lastScreenPos = new Point(-1, -1); + + // Fields for redundant mouse moved/dragged filtering + private Component lastUnderMotion = null; + private Point lastLocalPos = new Point(-1, -1); + + private final MouseGrabManager mouseGrabManager; + private final Toolkit toolkit; + + static Point convertPoint(Component src, int x, int y, Component dest) { + Point srcPoint = getAbsLocation(src); + Point destPoint = getAbsLocation(dest); + + return new Point(x + (srcPoint.x - destPoint.x), + y + (srcPoint.y - destPoint.y)); + } + + static Point convertPoint(Component src, Point p, Component dst) { + return convertPoint(src, p.x, p.y, dst); + } + + private static Point getAbsLocation(Component comp) { + Point location = new Point(0, 0); +// BEGIN android-changed: AWT components not supported +// for (Component parent = comp; parent != null; parent = parent.parent) { +// Point parentPos = (parent instanceof EmbeddedWindow ? +// parent.getNativeWindow().getScreenPos() : +// parent.getLocation()); +// +// location.translate(parentPos.x, parentPos.y); +// +// if (parent instanceof Window) { +// break; +// } +// } +// END android-changed + + return location; + } + + MouseDispatcher(MouseGrabManager mouseGrabManager, + Toolkit toolkit) { + this.mouseGrabManager = mouseGrabManager; + this.toolkit = toolkit; + } + + Point getPointerPos() { + return lastScreenPos; + } + + boolean dispatch(Component src, NativeEvent event) { + int id = event.getEventId(); + + lastScreenPos.setLocation(event.getScreenPos()); + checkMouseEnterExit(event.getInputModifiers(), event.getTime()); + + if (id == MouseEvent.MOUSE_WHEEL) { +// BEGIN android-changed: AWT components not supported +// dispatchWheelEvent(src, event); +// END android-changed + } else if ((id != MouseEvent.MOUSE_ENTERED) && + (id != MouseEvent.MOUSE_EXITED)) { + PointerInfo info = new PointerInfo(src, event.getLocalPos()); + + mouseGrabManager.preprocessEvent(event); + findEventSource(info); + if ((id == MouseEvent.MOUSE_PRESSED) || + (id == MouseEvent.MOUSE_RELEASED)) { + + dispatchButtonEvent(info, event); + } else if ((id == MouseEvent.MOUSE_MOVED) || + (id == MouseEvent.MOUSE_DRAGGED)) { + + dispatchMotionEvent(info, event); + } + } + + return false; + } + + private void checkMouseEnterExit(int modifiers, long when) { +// BEGIN android-changed: AWT components not supported +// PointerInfo info = findComponentUnderPointer(); +// Component curUnderPointer = +// propagateEvent(info, AWTEvent.MOUSE_EVENT_MASK, +// MouseListener.class, false).src; +// +// if (curUnderPointer != lastUnderPointer) { +// Point pos = info.position; +// if ((lastUnderPointer != null) && +// lastUnderPointer.isMouseExitedExpected()) { +// +// Point exitPos = convertPoint(null, lastScreenPos.x, +// lastScreenPos.y, lastUnderPointer); +// +// postMouseEnterExit(MouseEvent.MOUSE_EXITED, modifiers, when, +// exitPos.x, exitPos.y, lastUnderPointer); +// } +// setCursor(curUnderPointer); +// if (curUnderPointer != null) { +// postMouseEnterExit(MouseEvent.MOUSE_ENTERED, modifiers, when, +// pos.x, pos.y, curUnderPointer); +// } +// lastUnderPointer = curUnderPointer; +// } +// END android-changed + } + + private void setCursor(Component comp) { + if (comp == null) { + return; + } + Component grabOwner = mouseGrabManager.getSyntheticGrabOwner(); + Component cursorComp = ((grabOwner != null) && + grabOwner.isShowing() ? grabOwner : comp); + cursorComp.setCursor(); + } + + private void postMouseEnterExit(int id, int mod, long when, + int x, int y, Component comp) { + if (comp.isIndirectlyEnabled()) { + toolkit.getSystemEventQueueImpl().postEvent( + new MouseEvent(comp, id, when, mod, x, y, 0, false)); + comp.setMouseExitedExpected(id == MouseEvent.MOUSE_ENTERED); + } else { + comp.setMouseExitedExpected(false); + } + } + + // BEGIN android-changed: AWT components not supported +// private PointerInfo findComponentUnderPointer() { +// NativeWindow nativeWindow = toolkit.getWindowFactory(). +// getWindowFromPoint(lastScreenPos); +// +// if (nativeWindow != null) { +// Component comp = toolkit.getComponentById(nativeWindow.getId()); +// +// if (comp != null) { +// Window window = comp.getWindowAncestor(); +// Point pointerPos = convertPoint(null, lastScreenPos.x, +// lastScreenPos.y, window); +// +// if (window.getClient().contains(pointerPos)) { +// PointerInfo info = new PointerInfo(window, pointerPos); +// +// fall2Child(info); +// +// return info; +// } +// } +// } +// +// return new PointerInfo(null, null); +// } +// END android-changed + + private void findEventSource(PointerInfo info) { + Component grabOwner = mouseGrabManager.getSyntheticGrabOwner(); + + if (grabOwner != null && grabOwner.isShowing()) { + info.position = convertPoint(info.src, info.position, grabOwner); + info.src = grabOwner; + } else { + //???AWT: rise2TopLevel(info); + //???AWT: fall2Child(info); + } + } + + // BEGIN android-changed: AWT components not supported +// private void rise2TopLevel(PointerInfo info) { +// while (!(info.src instanceof Window)) { +// info.position.translate(info.src.x, info.src.y); +// info.src = info.src.parent; +// } +// } +// +// private void fall2Child(PointerInfo info) { +// Insets insets = info.src.getInsets(); +// +// final Point pos = info.position; +// final int x = pos.x; +// final int y = pos.y; +// if ((x >= insets.left) && (y >= insets.top) && +// (x < (info.src.w - insets.right)) && +// (y < (info.src.h - insets.bottom))) +// { +// Component[] children = ((Container) info.src).getComponents(); +// +// for (Component child : children) { +// if (child.isShowing()) { +// if (child.contains(x - child.getX(), +// y - child.getY())) +// { +// info.src = child; +// pos.translate(-child.x, -child.y); +// +// if (child instanceof Container) { +// fall2Child(info); +// } +// +// return; +// } +// } +// } +// } +// } +// END android-changed + + private void dispatchButtonEvent(PointerInfo info, NativeEvent event) { + int button = event.getMouseButton(); + long time = event.getTime(); + int id = event.getEventId(); + int index = button - 1; + boolean clickRequired = false; + + propagateEvent(info, AWTEvent.MOUSE_EVENT_MASK, + MouseListener.class, false); + if (id == MouseEvent.MOUSE_PRESSED) { + int clickInterval = toolkit.dispatcher.clickInterval; + mouseGrabManager.onMousePressed(info.src); + buttonPressed[index] = true; + clickCount[index] = (!deltaExceeded(index, info) && + ((time - lastPressTime[index]) <= clickInterval)) ? + clickCount[index] + 1 : 1; + lastPressTime[index] = time; + lastPressPos[index] = info.position; + } else { + mouseGrabManager.onMouseReleased(info.src); + // set cursor back on synthetic mouse grab end: +// BEGIN android-changed: AWT components not supported +// setCursor(findComponentUnderPointer().src); +// END android-changed + if (buttonPressed[index]) { + buttonPressed[index] = false; + clickRequired = !deltaExceeded(index, info); + } else { + clickCount[index] = 0; + } + } + if (info.src.isIndirectlyEnabled()) { + final Point pos = info.position; + final int mod = event.getInputModifiers(); + toolkit.getSystemEventQueueImpl().postEvent( + new MouseEvent(info.src, id, time, mod, pos.x, + pos.y, clickCount[index], + event.getTrigger(), button)); + if (clickRequired) { + toolkit.getSystemEventQueueImpl().postEvent( + new MouseEvent(info.src, + MouseEvent.MOUSE_CLICKED, + time, mod, pos.x, pos.y, + clickCount[index], false, + button)); + } + } + } + + private boolean deltaExceeded(int index, PointerInfo info) { + final Point lastPos = lastPressPos[index]; + if (lastPos == null) { + return true; + } + return ((Math.abs(lastPos.x - info.position.x) > clickDelta) || + (Math.abs(lastPos.y - info.position.y) > clickDelta)); + } + + private void dispatchMotionEvent(PointerInfo info, NativeEvent event) { + propagateEvent(info, AWTEvent.MOUSE_MOTION_EVENT_MASK, + MouseMotionListener.class, false); + final Point pos = info.position; + if ((lastUnderMotion != info.src) || + !lastLocalPos.equals(pos)) { + + lastUnderMotion = info.src; + lastLocalPos = pos; + + if (info.src.isIndirectlyEnabled()) { + toolkit.getSystemEventQueueImpl().postEvent( + new MouseEvent(info.src, event.getEventId(), + event.getTime(), + event.getInputModifiers(), + pos.x, pos.y, 0, false)); + } + } + } + + MouseWheelEvent createWheelEvent(Component src, NativeEvent event, + Point where) { + + Integer scrollAmountProperty = + (Integer)toolkit.getDesktopProperty("awt.wheelScrollingSize"); //$NON-NLS-1$ + int amount = 1; + int type = MouseWheelEvent.WHEEL_UNIT_SCROLL; + + if (scrollAmountProperty != null) { + amount = scrollAmountProperty.intValue(); + if (amount == -1) { + type = MouseWheelEvent.WHEEL_BLOCK_SCROLL; + amount = 1; + } + } + return new MouseWheelEvent(src, event.getEventId(), + event.getTime(), event.getInputModifiers(), + where.x, where.y, 0, false, type, amount, + event.getWheelRotation()); + } + +// BEGIN android-changed: AWT components not supported +// private void dispatchWheelEvent(Component src, NativeEvent event) { +// PointerInfo info = findComponentUnderPointer(); +// +// if (info.src == null) { +// info.src = src; +// info.position = event.getLocalPos(); +// } +// +// propagateEvent(info, AWTEvent.MOUSE_WHEEL_EVENT_MASK, +// MouseWheelListener.class, true); +// if ((info.src != null) && info.src.isIndirectlyEnabled()) { +// toolkit.getSystemEventQueueImpl().postEvent( +// createWheelEvent(info.src, event, info.position)); +// } +// } +// END android-changed + + private PointerInfo propagateEvent(PointerInfo info, long mask, + Class<? extends EventListener> type, boolean pierceHW) { + Component src = info.src; + while ((src != null) && + (src.isLightweight() || pierceHW) && + !(src.isMouseEventEnabled(mask) || + (src.getListeners(type).length > 0))) { + + info.position.translate(src.x, src.y); +// BEGIN android-changed: AWT components not supported +// src = src.parent; +// END android-changed + info.src = src; + } + + return info; + } + +// BEGIN android-changed: AWT components not supported +// Window findWindowAt(Point p) { +// NativeWindow nativeWindow = +// toolkit.getWindowFactory().getWindowFromPoint(p); +// +// Window window = null; +// if (nativeWindow != null) { +// Component comp = toolkit.getComponentById(nativeWindow.getId()); +// +// if (comp != null) { +// window = comp.getWindowAncestor(); +// } +// } +// return window; +// } +// END android-changed + + private class PointerInfo { + + Component src; + Point position; + + PointerInfo(Component src, Point position) { + this.src = src; + this.position = position; + } + + } + +} diff --git a/awt/java/awt/Paint.java b/awt/java/awt/Paint.java new file mode 100644 index 0000000..dfea3a7 --- /dev/null +++ b/awt/java/awt/Paint.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; + +/** + * The Paint interface provides possibility of generating color patterns in + * device space for fill, draw, or stroke operations in a Graphics2D. + * + * @since Android 1.0 + */ +public interface Paint extends Transparency { + + /** + * Creates the PaintContext which is used to generate color patterns for + * rendering operations of Graphics2D. + * + * @param cm + * the ColorModel object, or null. + * @param deviceBounds + * the Rectangle represents the bounding box of device space for + * the graphics rendering operations. + * @param userBounds + * the Rectangle represents bounding box of user space for the + * graphics rendering operations. + * @param xform + * the AffineTransform for translation from user space to device + * space. + * @param hints + * the RenderingHints preferences. + * @return the PaintContext for generating color patterns. + */ + PaintContext createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds, + AffineTransform xform, RenderingHints hints); +} diff --git a/awt/java/awt/PaintContext.java b/awt/java/awt/PaintContext.java new file mode 100644 index 0000000..966b6ca --- /dev/null +++ b/awt/java/awt/PaintContext.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt; + +import java.awt.image.ColorModel; +import java.awt.image.Raster; + +/** + * The PaintContext interface determines the specific environment for generating + * color patterns in device space for fill, draw, or stroke rendering operations + * using Graphics2D. This interface provides colors through the Raster object + * associated with the specific ColorModel for Graphics2D rendering operations. + * + * @since Android 1.0 + */ +public interface PaintContext { + + /** + * Releases the resources allocated for the operation. + */ + void dispose(); + + /** + * Gets the color model. + * + * @return the ColorModel object. + */ + ColorModel getColorModel(); + + /** + * Gets the Raster which defines the colors of the specified rectangular + * area for Graphics2D rendering operations. + * + * @param x + * the X coordinate of the device space area for which colors are + * generated. + * @param y + * the Y coordinate of the device space area for which colors are + * generated. + * @param w + * the width of the device space area for which colors are + * generated. + * @param h + * the height of the device space area for which colors are + * generated. + * @return the Raster object which contains the colors of the specified + * rectangular area for Graphics2D rendering operations. + */ + Raster getRaster(int x, int y, int w, int h); +} diff --git a/awt/java/awt/Point.java b/awt/java/awt/Point.java new file mode 100644 index 0000000..8ec4241 --- /dev/null +++ b/awt/java/awt/Point.java @@ -0,0 +1,211 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt; + +import java.awt.geom.Point2D; +import java.io.Serializable; + +/** + * The Point class represents a point location with coordinates X, Y in current + * coordinate system. + * + * @since Android 1.0 + */ +public class Point extends Point2D implements Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -5276940640259749850L; + + /** + * The X coordinate of Point. + */ + public int x; + + /** + * The Y coordinate of Point. + */ + public int y; + + /** + * Instantiates a new point with (0, O) coordinates, the origin of + * coordinate system. + */ + public Point() { + setLocation(0, 0); + } + + /** + * Instantiates a new point with (x, y) coordinates. + * + * @param x + * the X coordinate of Point. + * @param y + * the Y coordinate of Point. + */ + public Point(int x, int y) { + setLocation(x, y); + } + + /** + * Instantiates a new point, giving it the same location as the parameter p. + * + * @param p + * the Point object giving the coordinates of the new point. + */ + public Point(Point p) { + setLocation(p.x, p.y); + } + + /** + * Compares current Point with the specified object. + * + * @param obj + * the Object to be compared. + * @return true, if the Object being compared is a Point whose coordinates + * are equal to the coordinates of this Point, false otherwise. + * @see java.awt.geom.Point2D#equals(Object) + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Point) { + Point p = (Point)obj; + return x == p.x && y == p.y; + } + return false; + } + + /** + * Returns string representation of the current Point object. + * + * @return a string representation of the current Point object. + */ + @Override + public String toString() { + return getClass().getName() + "[x=" + x + ",y=" + y + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + /** + * Gets X coordinate of Point as a double. + * + * @return X coordinate of the point as a double. + * @see java.awt.geom.Point2D#getX() + */ + @Override + public double getX() { + return x; + } + + /** + * Gets Y coordinate of Point as a double. + * + * @return Y coordinate of the point as a double. + * @see java.awt.geom.Point2D#getY() + */ + @Override + public double getY() { + return y; + } + + /** + * Gets the location of the Point as a new Point object. + * + * @return a copy of the Point. + */ + public Point getLocation() { + return new Point(x, y); + } + + /** + * Sets the location of the Point to the same coordinates as p. + * + * @param p + * the Point that gives the new location. + */ + public void setLocation(Point p) { + setLocation(p.x, p.y); + } + + /** + * Sets the location of the Point to the coordinates X, Y. + * + * @param x + * the X coordinate of the Point's new location. + * @param y + * the Y coordinate of the Point's new location. + */ + public void setLocation(int x, int y) { + this.x = x; + this.y = y; + } + + /** + * Sets the location of Point to the specified double coordinates. + * + * @param x + * the X the Point's new location. + * @param y + * the Y the Point's new location. + * @see java.awt.geom.Point2D#setLocation(double, double) + */ + @Override + public void setLocation(double x, double y) { + x = x < Integer.MIN_VALUE ? Integer.MIN_VALUE : x > Integer.MAX_VALUE ? Integer.MAX_VALUE + : x; + y = y < Integer.MIN_VALUE ? Integer.MIN_VALUE : y > Integer.MAX_VALUE ? Integer.MAX_VALUE + : y; + setLocation((int)Math.round(x), (int)Math.round(y)); + } + + /** + * Moves the Point to the specified (x, y) location. + * + * @param x + * the X coordinate of the new location. + * @param y + * the Y coordinate of the new location. + */ + public void move(int x, int y) { + setLocation(x, y); + } + + /** + * Translates current Point moving it from the position (x, y) to the new + * position given by (x+dx, x+dy) coordinates. + * + * @param dx + * the horizontal delta - the Point is moved to this distance + * along X axis. + * @param dy + * the vertical delta - the Point is moved to this distance along + * Y axis. + */ + public void translate(int dx, int dy) { + x += dx; + y += dy; + } + +} diff --git a/awt/java/awt/Polygon.java b/awt/java/awt/Polygon.java new file mode 100644 index 0000000..de31eb9 --- /dev/null +++ b/awt/java/awt/Polygon.java @@ -0,0 +1,515 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt; + +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.io.Serializable; +import java.util.NoSuchElementException; + +import org.apache.harmony.awt.gl.*; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Polygon class defines an closed area specified by n vertices and n edges. + * The coordinates of the vertices are specified by x, y arrays. The edges are + * the line segments from the point (x[i], y[i]) to the point (x[i+1], y[i+1]), + * for -1 < i < (n-1) plus the line segment from the point (x[n-1], y[n-1]) to + * the point (x[0], y[0]) point. The Polygon is empty if the number of vertices + * is zero. + * + * @since Android 1.0 + */ +public class Polygon implements Shape, Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -6460061437900069969L; + + /** + * The points buffer capacity. + */ + private static final int BUFFER_CAPACITY = 4; + + /** + * The number of Polygon vertices. + */ + public int npoints; + + /** + * The array of X coordinates of the vertices. + */ + public int[] xpoints; + + /** + * The array of Y coordinates of the vertices. + */ + public int[] ypoints; + + /** + * The smallest Rectangle that completely contains this Polygon. + */ + protected Rectangle bounds; + + /* + * Polygon path iterator + */ + /** + * The internal Class Iterator. + */ + class Iterator implements PathIterator { + + /** + * The source Polygon object. + */ + public Polygon p; + + /** + * The path iterator transformation. + */ + public AffineTransform t; + + /** + * The current segment index. + */ + public int index; + + /** + * Constructs a new Polygon.Iterator for the given polygon and + * transformation + * + * @param at + * the AffineTransform object to apply rectangle path. + * @param p + * the p. + */ + public Iterator(AffineTransform at, Polygon p) { + this.p = p; + this.t = at; + if (p.npoints == 0) { + index = 1; + } + } + + public int getWindingRule() { + return WIND_EVEN_ODD; + } + + public boolean isDone() { + return index > p.npoints; + } + + public void next() { + index++; + } + + public int currentSegment(double[] coords) { + if (isDone()) { + // awt.110=Iterator out of bounds + throw new NoSuchElementException(Messages.getString("awt.110")); //$NON-NLS-1$ + } + if (index == p.npoints) { + return SEG_CLOSE; + } + coords[0] = p.xpoints[index]; + coords[1] = p.ypoints[index]; + if (t != null) { + t.transform(coords, 0, coords, 0, 1); + } + return index == 0 ? SEG_MOVETO : SEG_LINETO; + } + + public int currentSegment(float[] coords) { + if (isDone()) { + // awt.110=Iterator out of bounds + throw new NoSuchElementException(Messages.getString("awt.110")); //$NON-NLS-1$ + } + if (index == p.npoints) { + return SEG_CLOSE; + } + coords[0] = p.xpoints[index]; + coords[1] = p.ypoints[index]; + if (t != null) { + t.transform(coords, 0, coords, 0, 1); + } + return index == 0 ? SEG_MOVETO : SEG_LINETO; + } + } + + /** + * Instantiates a new empty polygon. + */ + public Polygon() { + xpoints = new int[BUFFER_CAPACITY]; + ypoints = new int[BUFFER_CAPACITY]; + } + + /** + * Instantiates a new polygon with the specified number of vertices, and the + * given arrays of x, y vertex coordinates. The length of each coordinate + * array may not be less than the specified number of vertices but may be + * greater. Only the first n elements are used from each coordinate array. + * + * @param xpoints + * the array of X vertex coordinates. + * @param ypoints + * the array of Y vertex coordinates. + * @param npoints + * the number vertices of the polygon. + * @throws IndexOutOfBoundsException + * if the length of xpoints or ypoints is less than n. + * @throws NegativeArraySizeException + * if n is negative. + */ + public Polygon(int[] xpoints, int[] ypoints, int npoints) { + if (npoints > xpoints.length || npoints > ypoints.length) { + // awt.111=Parameter npoints is greater than array length + throw new IndexOutOfBoundsException(Messages.getString("awt.111")); //$NON-NLS-1$ + } + if (npoints < 0) { + // awt.112=Negative number of points + throw new NegativeArraySizeException(Messages.getString("awt.112")); //$NON-NLS-1$ + } + this.npoints = npoints; + this.xpoints = new int[npoints]; + this.ypoints = new int[npoints]; + System.arraycopy(xpoints, 0, this.xpoints, 0, npoints); + System.arraycopy(ypoints, 0, this.ypoints, 0, npoints); + } + + /** + * Resets the current Polygon to an empty Polygon. More precisely, the + * number of Polygon vertices is set to zero, but x, y coordinates arrays + * are not affected. + */ + public void reset() { + npoints = 0; + bounds = null; + } + + /** + * Invalidates the data that depends on the vertex coordinates. This method + * should be called after direct manipulations of the x, y vertex + * coordinates arrays to avoid unpredictable results of methods which rely + * on the bounding box. + */ + public void invalidate() { + bounds = null; + } + + /** + * Adds the point to the Polygon and updates the bounding box accordingly. + * + * @param px + * the X coordinate of the added vertex. + * @param py + * the Y coordinate of the added vertex. + */ + public void addPoint(int px, int py) { + if (npoints == xpoints.length) { + int[] tmp; + + tmp = new int[xpoints.length + BUFFER_CAPACITY]; + System.arraycopy(xpoints, 0, tmp, 0, xpoints.length); + xpoints = tmp; + + tmp = new int[ypoints.length + BUFFER_CAPACITY]; + System.arraycopy(ypoints, 0, tmp, 0, ypoints.length); + ypoints = tmp; + } + + xpoints[npoints] = px; + ypoints[npoints] = py; + npoints++; + + if (bounds != null) { + bounds.setFrameFromDiagonal(Math.min(bounds.getMinX(), px), Math.min(bounds.getMinY(), + py), Math.max(bounds.getMaxX(), px), Math.max(bounds.getMaxY(), py)); + } + } + + /** + * Gets the bounding rectangle of the Polygon. The bounding rectangle is the + * smallest rectangle which contains the Polygon. + * + * @return the bounding rectangle of the Polygon. + * @see java.awt.Shape#getBounds() + */ + public Rectangle getBounds() { + if (bounds != null) { + return bounds; + } + if (npoints == 0) { + return new Rectangle(); + } + + int bx1 = xpoints[0]; + int by1 = ypoints[0]; + int bx2 = bx1; + int by2 = by1; + + for (int i = 1; i < npoints; i++) { + int x = xpoints[i]; + int y = ypoints[i]; + if (x < bx1) { + bx1 = x; + } else if (x > bx2) { + bx2 = x; + } + if (y < by1) { + by1 = y; + } else if (y > by2) { + by2 = y; + } + } + + return bounds = new Rectangle(bx1, by1, bx2 - bx1, by2 - by1); + } + + /** + * Gets the bounding rectangle of the Polygon. The bounding rectangle is the + * smallest rectangle which contains the Polygon. + * + * @return the bounding rectangle of the Polygon. + * @deprecated Use getBounds() method. + */ + @Deprecated + public Rectangle getBoundingBox() { + return getBounds(); + } + + /** + * Gets the Rectangle2D which represents Polygon bounds. The bounding + * rectangle is the smallest rectangle which contains the Polygon. + * + * @return the bounding rectangle of the Polygon. + * @see java.awt.Shape#getBounds2D() + */ + public Rectangle2D getBounds2D() { + return getBounds().getBounds2D(); + } + + /** + * Translates all vertices of Polygon the specified distances along X, Y + * axis. + * + * @param mx + * the distance to translate horizontally. + * @param my + * the distance to translate vertically. + */ + public void translate(int mx, int my) { + for (int i = 0; i < npoints; i++) { + xpoints[i] += mx; + ypoints[i] += my; + } + if (bounds != null) { + bounds.translate(mx, my); + } + } + + /** + * Checks whether or not the point given by the coordinates x, y lies inside + * the Polygon. + * + * @param x + * the X coordinate of the point to check. + * @param y + * the Y coordinate of the point to check. + * @return true, if the specified point lies inside the Polygon, false + * otherwise. + * @deprecated Use contains(int, int) method. + */ + @Deprecated + public boolean inside(int x, int y) { + return contains((double)x, (double)y); + } + + /** + * Checks whether or not the point given by the coordinates x, y lies inside + * the Polygon. + * + * @param x + * the X coordinate of the point to check. + * @param y + * the Y coordinate of the point to check. + * @return true, if the specified point lies inside the Polygon, false + * otherwise. + */ + public boolean contains(int x, int y) { + return contains((double)x, (double)y); + } + + /** + * Checks whether or not the point with specified double coordinates lies + * inside the Polygon. + * + * @param x + * the X coordinate of the point to check. + * @param y + * the Y coordinate of the point to check. + * @return true, if the point given by the double coordinates lies inside + * the Polygon, false otherwise. + * @see java.awt.Shape#contains(double, double) + */ + public boolean contains(double x, double y) { + return Crossing.isInsideEvenOdd(Crossing.crossShape(this, x, y)); + } + + /** + * Checks whether or not the rectangle determined by the parameters [x, y, + * width, height] lies inside the Polygon. + * + * @param x + * the X coordinate of the rectangles's left upper corner as a + * double. + * @param y + * the Y coordinate of the rectangles's left upper corner as a + * double. + * @param width + * the width of rectangle as a double. + * @param height + * the height of rectangle as a double. + * @return true, if the specified rectangle lies inside the Polygon, false + * otherwise. + * @see java.awt.Shape#contains(double, double, double, double) + */ + public boolean contains(double x, double y, double width, double height) { + int cross = Crossing.intersectShape(this, x, y, width, height); + return cross != Crossing.CROSSING && Crossing.isInsideEvenOdd(cross); + } + + /** + * Checks whether or not the rectangle determined by the parameters [x, y, + * width, height] intersects the interior of the Polygon. + * + * @param x + * the X coordinate of the rectangles's left upper corner as a + * double. + * @param y + * the Y coordinate of the rectangles's left upper corner as a + * double. + * @param width + * the width of rectangle as a double. + * @param height + * the height of rectangle as a double. + * @return true, if the specified rectangle intersects the interior of the + * Polygon, false otherwise. + * @see java.awt.Shape#intersects(double, double, double, double) + */ + public boolean intersects(double x, double y, double width, double height) { + int cross = Crossing.intersectShape(this, x, y, width, height); + return cross == Crossing.CROSSING || Crossing.isInsideEvenOdd(cross); + } + + /** + * Checks whether or not the specified rectangle lies inside the Polygon. + * + * @param rect + * the Rectangle2D object. + * @return true, if the specified rectangle lies inside the Polygon, false + * otherwise. + * @see java.awt.Shape#contains(java.awt.geom.Rectangle2D) + */ + public boolean contains(Rectangle2D rect) { + return contains(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); + } + + /** + * Checks whether or not the specified Point lies inside the Polygon. + * + * @param point + * the Point object. + * @return true, if the specified Point lies inside the Polygon, false + * otherwise. + */ + public boolean contains(Point point) { + return contains(point.getX(), point.getY()); + } + + /** + * Checks whether or not the specified Point2D lies inside the Polygon. + * + * @param point + * the Point2D object. + * @return true, if the specified Point2D lies inside the Polygon, false + * otherwise. + * @see java.awt.Shape#contains(java.awt.geom.Point2D) + */ + public boolean contains(Point2D point) { + return contains(point.getX(), point.getY()); + } + + /** + * Checks whether or not the interior of rectangle specified by the + * Rectangle2D object intersects the interior of the Polygon. + * + * @param rect + * the Rectangle2D object. + * @return true, if the Rectangle2D intersects the interior of the Polygon, + * false otherwise. + * @see java.awt.Shape#intersects(java.awt.geom.Rectangle2D) + */ + public boolean intersects(Rectangle2D rect) { + return intersects(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); + } + + /** + * Gets the PathIterator object which gives the coordinates of the polygon, + * transformed according to the specified AffineTransform. + * + * @param t + * the specified AffineTransform object or null. + * @return PathIterator object for the Polygon. + * @see java.awt.Shape#getPathIterator(java.awt.geom.AffineTransform) + */ + public PathIterator getPathIterator(AffineTransform t) { + return new Iterator(t, this); + } + + /** + * Gets the PathIterator object which gives the coordinates of the polygon, + * transformed according to the specified AffineTransform. The flatness + * parameter is ignored. + * + * @param t + * the specified AffineTransform object or null. + * @param flatness + * the maximum number of the control points for a given curve + * which varies from colinear before a subdivided curve is + * replaced by a straight line connecting the endpoints. This + * parameter is ignored for the Polygon class. + * @return PathIterator object for the Polygon. + * @see java.awt.Shape#getPathIterator(java.awt.geom.AffineTransform, + * double) + */ + public PathIterator getPathIterator(AffineTransform t, double flatness) { + return new Iterator(t, this); + } + +} diff --git a/awt/java/awt/Rectangle.java b/awt/java/awt/Rectangle.java new file mode 100644 index 0000000..d8ebb3a --- /dev/null +++ b/awt/java/awt/Rectangle.java @@ -0,0 +1,723 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt; + +import java.awt.geom.Rectangle2D; +import java.io.Serializable; + +/** + * The Rectangle class defines the rectangular area in terms of its upper left + * corner coordinates [x,y], its width, and its height. A Rectangle specified by + * [x, y, width, height] parameters has an outline path with corners at [x, y], + * [x + width,y], [x + width,y + height], and [x, y + height]. <br> + * <br> + * The rectangle is empty if the width or height is negative or zero. In this + * case the isEmpty method returns true. + * + * @since Android 1.0 + */ +public class Rectangle extends Rectangle2D implements Shape, Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -4345857070255674764L; + + /** + * The X coordinate of the rectangle's left upper corner. + */ + public int x; + + /** + * The Y coordinate of the rectangle's left upper corner. + */ + public int y; + + /** + * The width of rectangle. + */ + public int width; + + /** + * The height of rectangle. + */ + public int height; + + /** + * Instantiates a new rectangle with [0, 0] upper left corner coordinates, + * the width and the height are zero. + */ + public Rectangle() { + setBounds(0, 0, 0, 0); + } + + /** + * Instantiates a new rectangle whose upper left corner coordinates are + * given by the Point object (p.X and p.Y), and the width and the height are + * zero. + * + * @param p + * the Point specifies the upper left corner coordinates of the + * rectangle. + */ + public Rectangle(Point p) { + setBounds(p.x, p.y, 0, 0); + } + + /** + * Instantiates a new rectangle whose upper left corner coordinates are + * given by the Point object (p.X and p.Y), and the width and the height are + * given by Dimension object (d.width and d.height). + * + * @param p + * the point specifies the upper left corner coordinates of the + * rectangle. + * @param d + * the dimension specifies the width and the height of the + * rectangle. + */ + public Rectangle(Point p, Dimension d) { + setBounds(p.x, p.y, d.width, d.height); + } + + /** + * Instantiates a new rectangle determined by the upper left corner + * coordinates (x, y), width and height. + * + * @param x + * the X upper left corner coordinate of the rectangle. + * @param y + * the Y upper left corner coordinate of the rectangle. + * @param width + * the width of rectangle. + * @param height + * the height of rectangle. + */ + public Rectangle(int x, int y, int width, int height) { + setBounds(x, y, width, height); + } + + /** + * Instantiates a new rectangle with [0, 0] as its upper left corner + * coordinates and the specified width and height. + * + * @param width + * the width of rectangle. + * @param height + * the height of rectangle. + */ + public Rectangle(int width, int height) { + setBounds(0, 0, width, height); + } + + /** + * Instantiates a new rectangle with the same coordinates as the given + * source rectangle. + * + * @param r + * the Rectangle object which parameters will be used for + * instantiating a new Rectangle. + */ + public Rectangle(Rectangle r) { + setBounds(r.x, r.y, r.width, r.height); + } + + /* + * public Rectangle(Dimension d) { setBounds(0, 0, d.width, d.height); } + */ + /** + * Gets the X coordinate of bound as a double. + * + * @return the X coordinate of bound as a double. + * @see java.awt.geom.RectangularShape#getX() + */ + @Override + public double getX() { + return x; + } + + /** + * Gets the Y coordinate of bound as a double. + * + * @return the Y coordinate of bound as a double. + * @see java.awt.geom.RectangularShape#getY() + */ + @Override + public double getY() { + return y; + } + + /** + * Gets the height of the rectangle as a double. + * + * @return the height of the rectangle as a double. + * @see java.awt.geom.RectangularShape#getHeight() + */ + @Override + public double getHeight() { + return height; + } + + /** + * Gets the width of the rectangle as a double. + * + * @return the width of the rectangle as a double. + * @see java.awt.geom.RectangularShape#getWidth() + */ + @Override + public double getWidth() { + return width; + } + + /** + * Determines whether or not the rectangle is empty. The rectangle is empty + * if its width or height is negative or zero. + * + * @return true, if the rectangle is empty, otherwise false. + * @see java.awt.geom.RectangularShape#isEmpty() + */ + @Override + public boolean isEmpty() { + return width <= 0 || height <= 0; + } + + /** + * Gets the size of a Rectangle as Dimension object. + * + * @return a Dimension object which represents size of the rectangle. + */ + public Dimension getSize() { + return new Dimension(width, height); + } + + /** + * Sets the size of the Rectangle. + * + * @param width + * the new width of the rectangle. + * @param height + * the new height of the rectangle. + */ + public void setSize(int width, int height) { + this.width = width; + this.height = height; + } + + /** + * Sets the size of a Rectangle specified as Dimension object. + * + * @param d + * a Dimension object which represents new size of a rectangle. + */ + public void setSize(Dimension d) { + setSize(d.width, d.height); + } + + /** + * Gets the location of a rectangle's upper left corner as a Point object. + * + * @return the Point object with coordinates equal to the upper left corner + * of the rectangle. + */ + public Point getLocation() { + return new Point(x, y); + } + + /** + * Sets the location of the rectangle in terms of its upper left corner + * coordinates X and Y. + * + * @param x + * the X coordinate of the rectangle's upper left corner. + * @param y + * the Y coordinate of the rectangle's upper left corner. + */ + public void setLocation(int x, int y) { + this.x = x; + this.y = y; + } + + /** + * Sets the location of a rectangle using a Point object to give the + * coordinates of the upper left corner. + * + * @param p + * the Point object which represents the new upper left corner + * coordinates of rectangle. + */ + public void setLocation(Point p) { + setLocation(p.x, p.y); + } + + /** + * Moves a rectangle to the new location by moving its upper left corner to + * the point with coordinates X and Y. + * + * @param x + * the new X coordinate of the rectangle's upper left corner. + * @param y + * the new Y coordinate of the rectangle's upper left corner. + * @deprecated Use setLocation(int, int) method. + */ + @Deprecated + public void move(int x, int y) { + setLocation(x, y); + } + + /** + * Sets the rectangle to be the nearest rectangle with integer coordinates + * bounding the rectangle defined by the double-valued parameters. + * + * @param x + * the X coordinate of the upper left corner of the double-valued + * rectangle to be bounded. + * @param y + * the Y coordinate of the upper left corner of the double-valued + * rectangle to be bounded. + * @param width + * the width of the rectangle to be bounded. + * @param height + * the height of the rectangle to be bounded. + * @see java.awt.geom.Rectangle2D#setRect(double, double, double, double) + */ + @Override + public void setRect(double x, double y, double width, double height) { + int x1 = (int)Math.floor(x); + int y1 = (int)Math.floor(y); + int x2 = (int)Math.ceil(x + width); + int y2 = (int)Math.ceil(y + height); + setBounds(x1, y1, x2 - x1, y2 - y1); + } + + /** + * Sets a new size for the rectangle. + * + * @param width + * the rectangle's new width. + * @param height + * the rectangle's new height. + * @deprecated use the setSize(int, int) method. + */ + @Deprecated + public void resize(int width, int height) { + setBounds(x, y, width, height); + } + + /** + * Resets the bounds of a rectangle to the specified x, y, width and height + * parameters. + * + * @param x + * the new X coordinate of the upper left corner. + * @param y + * the new Y coordinate of the upper left corner. + * @param width + * the new width of rectangle. + * @param height + * the new height of rectangle. + * @deprecated use setBounds(int, int, int, int) method + */ + @Deprecated + public void reshape(int x, int y, int width, int height) { + setBounds(x, y, width, height); + } + + /** + * Gets bounds of the rectangle as a new Rectangle object. + * + * @return the Rectangle object with the same bounds as the original + * rectangle. + * @see java.awt.geom.RectangularShape#getBounds() + */ + @Override + public Rectangle getBounds() { + return new Rectangle(x, y, width, height); + } + + /** + * Gets the bounds of the original rectangle as a Rectangle2D object. + * + * @return the Rectangle2D object which represents the bounds of the + * original rectangle. + * @see java.awt.geom.Rectangle2D#getBounds2D() + */ + @Override + public Rectangle2D getBounds2D() { + return getBounds(); + } + + /** + * Sets the bounds of a rectangle to the specified x, y, width, and height + * parameters. + * + * @param x + * the X coordinate of the upper left corner. + * @param y + * the Y coordinate of the upper left corner. + * @param width + * the width of rectangle. + * @param height + * the height of rectangle. + */ + public void setBounds(int x, int y, int width, int height) { + this.x = x; + this.y = y; + this.height = height; + this.width = width; + } + + /** + * Sets the bounds of the rectangle to match the bounds of the Rectangle + * object sent as a parameter. + * + * @param r + * the Rectangle object which specifies the new bounds. + */ + public void setBounds(Rectangle r) { + setBounds(r.x, r.y, r.width, r.height); + } + + /** + * Enlarges the rectangle by moving each corner outward from the center by a + * distance of dx horizonally and a distance of dy vertically. Specifically, + * changes a rectangle with [x, y, width, height] parameters to a rectangle + * with [x-dx, y-dy, width+2*dx, height+2*dy] parameters. + * + * @param dx + * the horizontal distance to move each corner coordinate. + * @param dy + * the vertical distance to move each corner coordinate. + */ + public void grow(int dx, int dy) { + x -= dx; + y -= dy; + width += dx + dx; + height += dy + dy; + } + + /** + * Moves a rectangle a distance of mx along the x coordinate axis and a + * distance of my along y coordinate axis. + * + * @param mx + * the horizontal translation increment. + * @param my + * the vertical translation increment. + */ + public void translate(int mx, int my) { + x += mx; + y += my; + } + + /** + * Enlarges the rectangle to cover the specified point. + * + * @param px + * the X coordinate of the new point to be covered by the + * rectangle. + * @param py + * the Y coordinate of the new point to be covered by the + * rectangle. + */ + public void add(int px, int py) { + int x1 = Math.min(x, px); + int x2 = Math.max(x + width, px); + int y1 = Math.min(y, py); + int y2 = Math.max(y + height, py); + setBounds(x1, y1, x2 - x1, y2 - y1); + } + + /** + * Enlarges the rectangle to cover the specified point with the new point + * given as a Point object. + * + * @param p + * the Point object that specifies the new point to be covered by + * the rectangle. + */ + public void add(Point p) { + add(p.x, p.y); + } + + /** + * Adds a new rectangle to the original rectangle, the result is an union of + * the specified specified rectangle and original rectangle. + * + * @param r + * the Rectangle which is added to the original rectangle. + */ + public void add(Rectangle r) { + int x1 = Math.min(x, r.x); + int x2 = Math.max(x + width, r.x + r.width); + int y1 = Math.min(y, r.y); + int y2 = Math.max(y + height, r.y + r.height); + setBounds(x1, y1, x2 - x1, y2 - y1); + } + + /** + * Determines whether or not the point with specified coordinates [px, py] + * is within the bounds of the rectangle. + * + * @param px + * the X coordinate of point. + * @param py + * the Y coordinate of point. + * @return true, if the point with specified coordinates [px, py] is within + * the bounds of the rectangle, false otherwise. + */ + public boolean contains(int px, int py) { + if (isEmpty()) { + return false; + } + if (px < x || py < y) { + return false; + } + px -= x; + py -= y; + return px < width && py < height; + } + + /** + * Determines whether or not the point given as a Point object is within the + * bounds of the rectangle. + * + * @param p + * the Point object + * @return true, if the point p is within the bounds of the rectangle, + * otherwise false. + */ + public boolean contains(Point p) { + return contains(p.x, p.y); + } + + /** + * Determines whether or not the rectangle specified by [rx, ry, rw, rh] + * parameters is located inside the original rectangle. + * + * @param rx + * the X coordinate of the rectangle to compare. + * @param ry + * the Y coordinate of the rectangle to compare. + * @param rw + * the width of the rectangle to compare. + * @param rh + * the height of the rectangle to compare. + * @return true, if a rectangle with [rx, ry, rw, rh] parameters is entirely + * contained in the original rectangle, false otherwise. + */ + public boolean contains(int rx, int ry, int rw, int rh) { + return contains(rx, ry) && contains(rx + rw - 1, ry + rh - 1); + } + + /** + * Compares whether or not the rectangle specified by the Rectangle object + * is located inside the original rectangle. + * + * @param r + * the Rectangle object. + * @return true, if the rectangle specified by Rectangle object is entirely + * contained in the original rectangle, false otherwise. + */ + public boolean contains(Rectangle r) { + return contains(r.x, r.y, r.width, r.height); + } + + /** + * Compares whether or not a point with specified coordinates [px, py] + * belongs to a rectangle. + * + * @param px + * the X coordinate of a point. + * @param py + * the Y coordinate of a point. + * @return true, if a point with specified coordinates [px, py] belongs to a + * rectangle, otherwise false. + * @deprecated use contains(int, int) method. + */ + @Deprecated + public boolean inside(int px, int py) { + return contains(px, py); + } + + /** + * Returns the intersection of the original rectangle with the specified + * Rectangle2D. + * + * @param r + * the Rectangle2D object. + * @return the Rectangle2D object that is the result of intersecting the + * original rectangle with the specified Rectangle2D. + * @see java.awt.geom.Rectangle2D#createIntersection(java.awt.geom.Rectangle2D) + */ + @Override + public Rectangle2D createIntersection(Rectangle2D r) { + if (r instanceof Rectangle) { + return intersection((Rectangle)r); + } + Rectangle2D dst = new Rectangle2D.Double(); + Rectangle2D.intersect(this, r, dst); + return dst; + } + + /** + * Returns the intersection of the original rectangle with the specified + * rectangle. An empty rectangle is returned if there is no intersection. + * + * @param r + * the Rectangle object. + * @return the Rectangle object is result of the original rectangle with the + * specified rectangle. + */ + public Rectangle intersection(Rectangle r) { + int x1 = Math.max(x, r.x); + int y1 = Math.max(y, r.y); + int x2 = Math.min(x + width, r.x + r.width); + int y2 = Math.min(y + height, r.y + r.height); + return new Rectangle(x1, y1, x2 - x1, y2 - y1); + } + + /** + * Determines whether or not the original rectangle intersects the specified + * rectangle. + * + * @param r + * the Rectangle object. + * @return true, if the two rectangles overlap, false otherwise. + */ + public boolean intersects(Rectangle r) { + return !intersection(r).isEmpty(); + } + + /** + * Determines where the specified Point is located with respect to the + * rectangle. This method computes whether the point is to the right or to + * the left of the rectangle and whether it is above or below the rectangle, + * and packs the result into an integer by using a binary OR operation with + * the following masks: + * <ul> + *<li>Rectangle2D.OUT_LEFT</li> + *<li>Rectangle2D.OUT_TOP</li> + *<li>Rectangle2D.OUT_RIGHT</li> + *<li>Rectangle2D.OUT_BOTTOM</li> + *</ul> + * If the rectangle is empty, all masks are set, and if the point is inside + * the rectangle, none are set. + * + * @param px + * the X coordinate of the specified point. + * @param py + * the Y coordinate of the specified point. + * @return the location of the Point relative to the rectangle as the result + * of logical OR operation with all out masks. + * @see java.awt.geom.Rectangle2D#outcode(double, double) + */ + @Override + public int outcode(double px, double py) { + int code = 0; + + if (width <= 0) { + code |= OUT_LEFT | OUT_RIGHT; + } else if (px < x) { + code |= OUT_LEFT; + } else if (px > x + width) { + code |= OUT_RIGHT; + } + + if (height <= 0) { + code |= OUT_TOP | OUT_BOTTOM; + } else if (py < y) { + code |= OUT_TOP; + } else if (py > y + height) { + code |= OUT_BOTTOM; + } + + return code; + } + + /** + * Enlarges the rectangle to cover the specified Rectangle2D. + * + * @param r + * the Rectangle2D object. + * @return the union of the original and the specified Rectangle2D. + * @see java.awt.geom.Rectangle2D#createUnion(java.awt.geom.Rectangle2D) + */ + @Override + public Rectangle2D createUnion(Rectangle2D r) { + if (r instanceof Rectangle) { + return union((Rectangle)r); + } + Rectangle2D dst = new Rectangle2D.Double(); + Rectangle2D.union(this, r, dst); + return dst; + } + + /** + * Enlarges the rectangle to cover the specified rectangle. + * + * @param r + * the Rectangle. + * @return the union of the original and the specified rectangle. + */ + public Rectangle union(Rectangle r) { + Rectangle dst = new Rectangle(this); + dst.add(r); + return dst; + } + + /** + * Compares the original Rectangle with the specified object. + * + * @param obj + * the specified Object for comparison. + * @return true, if the specified Object is a rectangle with the same + * dimensions as the original rectangle, false otherwise. + * @see java.awt.geom.Rectangle2D#equals(Object) + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Rectangle) { + Rectangle r = (Rectangle)obj; + return r.x == x && r.y == y && r.width == width && r.height == height; + } + return false; + } + + /** + * Returns a string representation of the rectangle; the string contains [x, + * y, width, height] parameters of the rectangle. + * + * @return the string representation of the rectangle. + */ + @Override + public String toString() { + // The output format based on 1.5 release behaviour. It could be + // obtained in the following way + // System.out.println(new Rectangle().toString()) + return getClass().getName() + "[x=" + x + ",y=" + y + //$NON-NLS-1$ //$NON-NLS-2$ + ",width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + +} diff --git a/awt/java/awt/RenderingHints.java b/awt/java/awt/RenderingHints.java new file mode 100644 index 0000000..acf6fa1 --- /dev/null +++ b/awt/java/awt/RenderingHints.java @@ -0,0 +1,606 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * The RenderingHints class represents preferences for the rendering algorithms. + * The preferences are arbitrary and can be specified by Map objects or by + * key-value pairs. + * + * @since Android 1.0 + */ +public class RenderingHints implements Map<Object, Object>, Cloneable { + + /** + * The Constant KEY_ALPHA_INTERPOLATION - alpha interpolation rendering hint + * key. + */ + public static final Key KEY_ALPHA_INTERPOLATION = new KeyImpl(1); + + /** + * The Constant VALUE_ALPHA_INTERPOLATION_DEFAULT - alpha interpolation + * rendering hint value. + */ + public static final Object VALUE_ALPHA_INTERPOLATION_DEFAULT = new KeyValue( + KEY_ALPHA_INTERPOLATION); + + /** + * The Constant VALUE_ALPHA_INTERPOLATION_SPEED - alpha interpolation + * rendering hint value. + */ + public static final Object VALUE_ALPHA_INTERPOLATION_SPEED = new KeyValue( + KEY_ALPHA_INTERPOLATION); + + /** + * The Constant VALUE_ALPHA_INTERPOLATION_QUALITY - alpha interpolation + * rendering hint value. + */ + public static final Object VALUE_ALPHA_INTERPOLATION_QUALITY = new KeyValue( + KEY_ALPHA_INTERPOLATION); + + /** + * The Constant KEY_ANTIALIASING - antialiasing rendering hint key. + */ + public static final Key KEY_ANTIALIASING = new KeyImpl(2); + + /** + * The Constant VALUE_ANTIALIAS_DEFAULT - antialiasing rendering hint value. + */ + public static final Object VALUE_ANTIALIAS_DEFAULT = new KeyValue(KEY_ANTIALIASING); + + /** + * The Constant VALUE_ANTIALIAS_ON - antialiasing rendering hint value. + */ + public static final Object VALUE_ANTIALIAS_ON = new KeyValue(KEY_ANTIALIASING); + + /** + * The Constant VALUE_ANTIALIAS_OFF - antialiasing rendering hint value. + */ + public static final Object VALUE_ANTIALIAS_OFF = new KeyValue(KEY_ANTIALIASING); + + /** + * The Constant KEY_COLOR_RENDERING - color rendering hint key. + */ + public static final Key KEY_COLOR_RENDERING = new KeyImpl(3); + + /** + * The Constant VALUE_COLOR_RENDER_DEFAULT - color rendering hint value. + */ + public static final Object VALUE_COLOR_RENDER_DEFAULT = new KeyValue(KEY_COLOR_RENDERING); + + /** + * The Constant VALUE_COLOR_RENDER_SPEED - color rendering hint value. + */ + public static final Object VALUE_COLOR_RENDER_SPEED = new KeyValue(KEY_COLOR_RENDERING); + + /** + * The Constant VALUE_COLOR_RENDER_QUALITY - color rendering hint value. + */ + public static final Object VALUE_COLOR_RENDER_QUALITY = new KeyValue(KEY_COLOR_RENDERING); + + /** + * The Constant KEY_DITHERING - dithering rendering hint key. + */ + public static final Key KEY_DITHERING = new KeyImpl(4); + + /** + * The Constant VALUE_DITHER_DEFAULT - dithering rendering hint value. + */ + public static final Object VALUE_DITHER_DEFAULT = new KeyValue(KEY_DITHERING); + + /** + * The Constant VALUE_DITHER_DISABLE - dithering rendering hint value. + */ + public static final Object VALUE_DITHER_DISABLE = new KeyValue(KEY_DITHERING); + + /** + * The Constant VALUE_DITHER_DISABLE - dithering rendering hint value. + */ + public static final Object VALUE_DITHER_ENABLE = new KeyValue(KEY_DITHERING); + + /** + * The Constant KEY_FRACTIONALMETRICS - fractional metrics rendering hint + * key. + */ + public static final Key KEY_FRACTIONALMETRICS = new KeyImpl(5); + + /** + * The Constant VALUE_FRACTIONALMETRICS_DEFAULT - fractional metrics + * rendering hint value. + */ + public static final Object VALUE_FRACTIONALMETRICS_DEFAULT = new KeyValue(KEY_FRACTIONALMETRICS); + + /** + * The Constant VALUE_FRACTIONALMETRICS_ON - fractional metrics rendering + * hint value. + */ + public static final Object VALUE_FRACTIONALMETRICS_ON = new KeyValue(KEY_FRACTIONALMETRICS); + + /** + * The Constant VALUE_FRACTIONALMETRICS_OFF - fractional metrics rendering + * hint value. + */ + public static final Object VALUE_FRACTIONALMETRICS_OFF = new KeyValue(KEY_FRACTIONALMETRICS); + + /** + * The Constant KEY_INTERPOLATION - interpolation rendering hint key. + */ + public static final Key KEY_INTERPOLATION = new KeyImpl(6); + + /** + * The Constant VALUE_INTERPOLATION_BICUBIC - interpolation rendering hint + * value. + */ + public static final Object VALUE_INTERPOLATION_BICUBIC = new KeyValue(KEY_INTERPOLATION); + + /** + * The Constant VALUE_INTERPOLATION_BILINEAR - interpolation rendering hint + * value. + */ + public static final Object VALUE_INTERPOLATION_BILINEAR = new KeyValue(KEY_INTERPOLATION); + + /** + * The Constant VALUE_INTERPOLATION_NEAREST_NEIGHBOR - interpolation + * rendering hint value. + */ + public static final Object VALUE_INTERPOLATION_NEAREST_NEIGHBOR = new KeyValue( + KEY_INTERPOLATION); + + /** + * The Constant KEY_RENDERING - rendering hint key. + */ + public static final Key KEY_RENDERING = new KeyImpl(7); + + /** + * The Constant VALUE_RENDER_DEFAULT - rendering hint value. + */ + public static final Object VALUE_RENDER_DEFAULT = new KeyValue(KEY_RENDERING); + + /** + * The Constant VALUE_RENDER_SPEED - rendering hint value. + */ + public static final Object VALUE_RENDER_SPEED = new KeyValue(KEY_RENDERING); + + /** + * The Constant VALUE_RENDER_QUALITY - rendering hint value. + */ + public static final Object VALUE_RENDER_QUALITY = new KeyValue(KEY_RENDERING); + + /** + * The Constant KEY_STROKE_CONTROL - stroke control hint key. + */ + public static final Key KEY_STROKE_CONTROL = new KeyImpl(8); + + /** + * The Constant VALUE_STROKE_DEFAULT - stroke hint value. + */ + public static final Object VALUE_STROKE_DEFAULT = new KeyValue(KEY_STROKE_CONTROL); + + /** + * The Constant VALUE_STROKE_NORMALIZE - stroke hint value. + */ + public static final Object VALUE_STROKE_NORMALIZE = new KeyValue(KEY_STROKE_CONTROL); + + /** + * The Constant VALUE_STROKE_PURE - stroke hint value. + */ + public static final Object VALUE_STROKE_PURE = new KeyValue(KEY_STROKE_CONTROL); + + /** + * The Constant KEY_TEXT_ANTIALIASING - text antialiasing hint key. + */ + public static final Key KEY_TEXT_ANTIALIASING = new KeyImpl(9); + + /** + * The Constant VALUE_TEXT_ANTIALIAS_DEFAULT - text antialiasing hint key. + */ + public static final Object VALUE_TEXT_ANTIALIAS_DEFAULT = new KeyValue(KEY_TEXT_ANTIALIASING); + + /** + * The Constant VALUE_TEXT_ANTIALIAS_ON - text antialiasing hint key. + */ + public static final Object VALUE_TEXT_ANTIALIAS_ON = new KeyValue(KEY_TEXT_ANTIALIASING); + + /** + * The Constant VALUE_TEXT_ANTIALIAS_OFF - text antialiasing hint key. + */ + public static final Object VALUE_TEXT_ANTIALIAS_OFF = new KeyValue(KEY_TEXT_ANTIALIASING); + + /** The map. */ + private HashMap<Object, Object> map = new HashMap<Object, Object>(); + + /** + * Instantiates a new rendering hints object from specified Map object with + * defined key/value pairs or null for empty RenderingHints. + * + * @param map + * the Map object with defined key/value pairs or null for empty + * RenderingHints. + */ + public RenderingHints(Map<Key, ?> map) { + super(); + if (map != null) { + putAll(map); + } + } + + /** + * Instantiates a new rendering hints object with the specified key/value + * pair. + * + * @param key + * the key of hint property. + * @param value + * the value of hint property. + */ + public RenderingHints(Key key, Object value) { + super(); + put(key, value); + } + + /** + * Adds the properties represented by key/value pairs from the specified + * RenderingHints object to current object. + * + * @param hints + * the RenderingHints to be added. + */ + public void add(RenderingHints hints) { + map.putAll(hints.map); + } + + /** + * Puts the specified value to the specified key. Neither the key nor the + * value can be null. + * + * @param key + * the rendering hint key. + * @param value + * the rendering hint value. + * @return the previous rendering hint value assigned to the key or null. + */ + public Object put(Object key, Object value) { + if (!((Key)key).isCompatibleValue(value)) { + throw new IllegalArgumentException(); + } + + return map.put(key, value); + } + + /** + * Removes the specified key and corresponding value from the RenderingHints + * object. + * + * @param key + * the specified hint key to be removed. + * @return the object of previous rendering hint value which is assigned to + * the specified key, or null. + */ + public Object remove(Object key) { + return map.remove(key); + } + + /** + * Gets the value assigned to the specified key. + * + * @param key + * the rendering hint key. + * @return the object assigned to the specified key. + */ + public Object get(Object key) { + return map.get(key); + } + + /** + * Returns a set of rendering hints keys for current RenderingHints object. + * + * @return the set of rendering hints keys. + */ + public Set<Object> keySet() { + return map.keySet(); + } + + /** + * Returns a set of Map.Entry objects which contain current RenderingHint + * key/value pairs. + * + * @return the a set of mapped RenderingHint key/value pairs. + */ + public Set<Map.Entry<Object, Object>> entrySet() { + return map.entrySet(); + } + + /** + * Puts all of the preferences from the specified Map into the current + * RenderingHints object. These mappings replace all existing preferences. + * + * @param m + * the specified Map of preferences. + */ + public void putAll(Map<?, ?> m) { + if (m instanceof RenderingHints) { + map.putAll(((RenderingHints)m).map); + } else { + Set<?> entries = m.entrySet(); + + if (entries != null) { + Iterator<?> it = entries.iterator(); + while (it.hasNext()) { + Map.Entry<?, ?> entry = (Map.Entry<?, ?>)it.next(); + Key key = (Key)entry.getKey(); + Object val = entry.getValue(); + put(key, val); + } + } + } + } + + /** + * Returns a Collection of values contained in current RenderingHints + * object. + * + * @return the Collection of RenderingHints's values. + */ + public Collection<Object> values() { + return map.values(); + } + + /** + * Checks whether or not current RenderingHints object contains at least one + * the value which is equal to the specified Object. + * + * @param value + * the specified Object. + * @return true, if the specified object is assigned to at least one + * RenderingHint's key, false otherwise. + */ + public boolean containsValue(Object value) { + return map.containsValue(value); + } + + /** + * Checks whether or not current RenderingHints object contains the key + * which is equal to the specified Object. + * + * @param key + * the specified Object. + * @return true, if the RenderingHints object contains the specified Object + * as a key, false otherwise. + */ + public boolean containsKey(Object key) { + if (key == null) { + throw new NullPointerException(); + } + + return map.containsKey(key); + } + + /** + * Checks whether or not the RenderingHints object contains any key/value + * pairs. + * + * @return true, if the RenderingHints object is empty, false otherwise. + */ + public boolean isEmpty() { + return map.isEmpty(); + } + + /** + * Clears the RenderingHints of all key/value pairs. + */ + public void clear() { + map.clear(); + } + + /** + * Returns the number of key/value pairs in the RenderingHints. + * + * @return the number of key/value pairs. + */ + public int size() { + return map.size(); + } + + /** + * Compares the RenderingHints object with the specified object. + * + * @param o + * the specified Object to be compared. + * @return true, if the Object is a Map whose key/value pairs match this + * RenderingHints' key/value pairs, false otherwise. + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof Map)) { + return false; + } + + Map<?, ?> m = (Map<?, ?>)o; + Set<?> keys = keySet(); + if (!keys.equals(m.keySet())) { + return false; + } + + Iterator<?> it = keys.iterator(); + while (it.hasNext()) { + Key key = (Key)it.next(); + Object v1 = get(key); + Object v2 = m.get(key); + if (!(v1 == null ? v2 == null : v1.equals(v2))) { + return false; + } + } + return true; + } + + /** + * Returns the hash code for this RenderingHints object. + * + * @return the hash code for this RenderingHints object. + */ + @Override + public int hashCode() { + return map.hashCode(); + } + + /** + * Returns the clone of the RenderingHints object with the same contents. + * + * @return the clone of the RenderingHints instance. + */ + @SuppressWarnings("unchecked") + @Override + public Object clone() { + RenderingHints clone = new RenderingHints(null); + clone.map = (HashMap<Object, Object>)this.map.clone(); + return clone; + } + + /** + * Returns the string representation of the RenderingHints object. + * + * @return the String object which represents RenderingHints object. + */ + @Override + public String toString() { + return "RenderingHints[" + map.toString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * The RenderingHints.Key class is abstract and defines a base type for all + * RenderingHints keys. + * + * @since Android 1.0 + */ + public abstract static class Key { + + /** The key. */ + private final int key; + + /** + * Instantiates a new key with unique integer identifier. No two objects + * of the same subclass with the same integer key can be instantiated. + * + * @param key + * the unique key. + */ + protected Key(int key) { + this.key = key; + } + + /** + * Compares the Key object with the specified object. + * + * @param o + * the specified Object to be compared. + * @return true, if the Key is equal to the specified object, false + * otherwise. + */ + @Override + public final boolean equals(Object o) { + return this == o; + } + + /** + * Returns the hash code for this Key object. + * + * @return the hash code for this Key object. + */ + @Override + public final int hashCode() { + return System.identityHashCode(this); + } + + /** + * Returns integer unique key with which this Key object has been + * instantiated. + * + * @return the integer unique key with which this Key object has been + * instantiated. + */ + protected final int intKey() { + return key; + } + + /** + * Checks whether or not specified value is compatible with the Key. + * + * @param val + * the Object. + * @return true, if the specified value is compatible with the Key, + * false otherwise. + */ + public abstract boolean isCompatibleValue(Object val); + } + + /** + * Private implementation of Key class. + */ + private static class KeyImpl extends Key { + + /** + * Instantiates a new key implementation. + * + * @param key + * the key. + */ + protected KeyImpl(int key) { + super(key); + } + + @Override + public boolean isCompatibleValue(Object val) { + if (!(val instanceof KeyValue)) { + return false; + } + + return ((KeyValue)val).key == this; + } + } + + /** + * Private class KeyValue is used as value for Key class instance. + */ + private static class KeyValue { + + /** + * The key. + */ + private final Key key; + + /** + * Instantiates a new key value. + * + * @param key + * the key. + */ + protected KeyValue(Key key) { + this.key = key; + } + } +} diff --git a/awt/java/awt/Shape.java b/awt/java/awt/Shape.java new file mode 100644 index 0000000..59bc623 --- /dev/null +++ b/awt/java/awt/Shape.java @@ -0,0 +1,162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * The Shape interface defines a geometric shape defined by a boundary (outline) + * path. The path outline can be accessed through a PathIterator object. The + * Shape interface provides methods for obtaining the bounding box (which is the + * smallest rectangle containing the shape and for obtaining a PathIterator + * object for current Shape, as well as utility methods which determine if the + * Shape contains or intersects a Rectangle or contains a Point. + * + * @since Android 1.0 + */ +public interface Shape { + + /** + * Checks whether or not the point with specified coordinates lies inside + * the Shape. + * + * @param x + * the X coordinate. + * @param y + * the Y coordinate. + * @return true, if the specified coordinates lie inside the Shape, false + * otherwise. + */ + public boolean contains(double x, double y); + + /** + * Checks whether or not the rectangle with specified [x, y, width, height] + * parameters lies inside the Shape. + * + * @param x + * the X double coordinate of the rectangle's upper left corner. + * @param y + * the Y double coordinate of the rectangle's upper left corner. + * @param w + * the width of rectangle. + * @param h + * the height of rectangle. + * @return true, if the specified rectangle lies inside the Shape, false + * otherwise. + */ + public boolean contains(double x, double y, double w, double h); + + /** + * Checks whether or not the specified Point2D lies inside the Shape. + * + * @param point + * the Point2D object. + * @return true, if the specified Point2D lies inside the Shape, false + * otherwise. + */ + public boolean contains(Point2D point); + + /** + * Checks whether or not the specified rectangle lies inside the Shape. + * + * @param r + * the Rectangle2D object. + * @return true, if the specified rectangle lies inside the Shape, false + * otherwise. + */ + public boolean contains(Rectangle2D r); + + /** + * Gets the bounding rectangle of the Shape. The bounding rectangle is the + * smallest rectangle which contains the Shape. + * + * @return the bounding rectangle of the Shape. + */ + public Rectangle getBounds(); + + /** + * Gets the Rectangle2D which represents Shape bounds. The bounding + * rectangle is the smallest rectangle which contains the Shape. + * + * @return the bounding rectangle of the Shape. + */ + public Rectangle2D getBounds2D(); + + /** + * Gets the PathIterator object of the Shape which provides access to the + * shape's boundary modified by the specified AffineTransform. + * + * @param at + * the specified AffineTransform object or null. + * @return PathIterator object for the Shape. + */ + public PathIterator getPathIterator(AffineTransform at); + + /** + * Gets the PathIterator object of the Shape which provides access to the + * coordinates of the shapes boundary modified by the specified + * AffineTransform. The flatness parameter defines the amount of subdivision + * of the curved segments and specifies the maximum distance which every + * point on the unflattened transformed curve can deviate from the returned + * flattened path segments. + * + * @param at + * the specified AffineTransform object or null. + * @param flatness + * the maximum number of the control points for a given curve + * which varies from colinear before a subdivided curve is + * replaced by a straight line connecting the endpoints. + * @return PathIterator object for the Shape. + */ + public PathIterator getPathIterator(AffineTransform at, double flatness); + + /** + * Checks whether or not the interior of rectangular specified by [x, y, + * width, height] parameters intersects the interior of the Shape. + * + * @param x + * the X double coordinate of the rectangle's upper left corner. + * @param y + * the Y double coordinate of the rectangle's upper left corner. + * @param w + * the width of rectangle. + * @param h + * the height of rectangle. + * @return true, if the rectangle specified by [x, y, width, height] + * parameters intersects the interior of the Shape, false otherwise. + */ + public boolean intersects(double x, double y, double w, double h); + + /** + * Checks whether or not the interior of rectangle specified by Rectangle2D + * object intersects the interior of the Shape. + * + * @param r + * the Rectangle2D object. + * @return true, if the Rectangle2D intersects the interior of the Shape, + * otherwise false. + */ + public boolean intersects(Rectangle2D r); +} diff --git a/awt/java/awt/Stroke.java b/awt/java/awt/Stroke.java new file mode 100644 index 0000000..6d17a23 --- /dev/null +++ b/awt/java/awt/Stroke.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt; + +/** + * The Stroke interface gives a pen style to be used by the Graphics2D + * interface. It provides a means for getting a stroked version of a shape, + * which is the version that is suitable for drawing via the Graphics2D + * interface. Stroking a shape gives the shape's outline a width or drawing + * style. + * <p> + * The Draw methods from Graphics2D interface should use the Stroke object for + * rendering the shape's outline. The stroke should be set by + * setStroke(java.awt.Stroke) method of the Graphics2D interface. + * + * @see java.awt.Graphics2D#setStroke(java.awt.Stroke) + * @since Android 1.0 + */ +public interface Stroke { + + /** + * Creates the stroked shape, which is the version that is suitable for + * drawing via the Graphics2D interface. Stroking a shape gives the shape's + * outline a width or drawing style. + * + * @param p + * the original shape. + * @return the stroked shape. + */ + public Shape createStrokedShape(Shape p); +} diff --git a/awt/java/awt/Toolkit.java b/awt/java/awt/Toolkit.java new file mode 100644 index 0000000..e38d524 --- /dev/null +++ b/awt/java/awt/Toolkit.java @@ -0,0 +1,1444 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.awt; + +import java.awt.event.AWTEventListener; +import java.awt.event.AWTEventListenerProxy; +import java.awt.event.InputEvent; +import java.awt.im.InputMethodHighlight; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.peer.FontPeer; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; + +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Collections; +import java.util.EventListener; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.Properties; +import java.util.ResourceBundle; + +import org.apache.harmony.awt.ChoiceStyle; +import org.apache.harmony.awt.ComponentInternals; +import org.apache.harmony.awt.ContextStorage; +import org.apache.harmony.awt.ReadOnlyIterator; +import org.apache.harmony.awt.internal.nls.Messages; +import org.apache.harmony.awt.wtk.CreationParams; +import org.apache.harmony.awt.wtk.GraphicsFactory; +import org.apache.harmony.awt.wtk.NativeCursor; + +import org.apache.harmony.awt.wtk.NativeEventQueue; +import org.apache.harmony.awt.wtk.NativeEventThread; +import org.apache.harmony.awt.wtk.ShutdownWatchdog; +import org.apache.harmony.awt.wtk.Synchronizer; +import org.apache.harmony.awt.wtk.WTK; +import org.apache.harmony.luni.util.NotImplementedException; + +/** + * The Toolkit class is the representation of the platform-specific Abstract + * Window Toolkit implementation. Toolkit's subclasses are used to bind the + * various components to particular native toolkit implementations. + * + * @since Android 1.0 + */ +public abstract class Toolkit { + + /** + * The Constant RECOURCE_PATH. + */ + private static final String RECOURCE_PATH = "org.apache.harmony.awt.resources.AWTProperties"; //$NON-NLS-1$ + + /** + * The Constant properties. + */ + private static final ResourceBundle properties = loadResources(RECOURCE_PATH); + + /** + * The dispatcher. + */ + Dispatcher dispatcher; + + /** + * The system event queue core. + */ + private EventQueueCore systemEventQueueCore; + + /** + * The dispatch thread. + */ + EventDispatchThread dispatchThread; + + /** + * The native thread. + */ + NativeEventThread nativeThread; + + /** + * The AWT events manager. + */ + protected AWTEventsManager awtEventsManager; + + /** + * The Class AWTTreeLock. + */ + private class AWTTreeLock { + } + + /** + * The AWT tree lock. + */ + final Object awtTreeLock = new AWTTreeLock(); + + /** + * The synchronizer. + */ + private final Synchronizer synchronizer = ContextStorage.getSynchronizer(); + + /** + * The shutdown watchdog. + */ + final ShutdownWatchdog shutdownWatchdog = new ShutdownWatchdog(); + + /** + * The auto number. + */ + final AutoNumber autoNumber = new AutoNumber(); + + /** + * The event type lookup. + */ + final AWTEvent.EventTypeLookup eventTypeLookup = new AWTEvent.EventTypeLookup(); + + /** + * The b dynamic layout set. + */ + private boolean bDynamicLayoutSet = true; + + /** + * The set of desktop properties that user set directly. + */ + private final HashSet<String> userPropSet = new HashSet<String>(); + + /** + * The desktop properties. + */ + protected Map<String, Object> desktopProperties; + + /** + * The desktop props support. + */ + protected PropertyChangeSupport desktopPropsSupport; + + /** + * For this component the native window is being created It is used in the + * callback-driven window creation (e.g. on Windows in the handler of + * WM_CREATE event) to establish the connection between this component and + * its native window. + */ + private Object recentNativeWindowComponent; + + /** + * The wtk. + */ + private WTK wtk; + + /** + * The Class ComponentInternalsImpl. + * + * @since Android 1.0 + */ + protected final class ComponentInternalsImpl extends ComponentInternals { + + /** + * Shutdown. + */ + @Override + public void shutdown() { + dispatchThread.shutdown(); + } + + /** + * Sets the desktop property to the specified value and fires a property + * change event. + * + * @param name + * the name of property. + * @param value + * the new value of property. + */ + @Override + public void setDesktopProperty(String name, Object value) { + Toolkit.this.setDesktopProperty(name, value); + } + } + + /** + * A lot of methods must throw HeadlessException if + * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>. + * + * @throws HeadlessException + * the headless exception. + */ + static void checkHeadless() throws HeadlessException { + if (GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance()) + throw new HeadlessException(); + } + + /** + * Lock AWT. + */ + final void lockAWT() { + synchronizer.lock(); + } + + /** + * Static lock AWT. + */ + static final void staticLockAWT() { + ContextStorage.getSynchronizer().lock(); + } + + /** + * Unlock AWT. + */ + final void unlockAWT() { + synchronizer.unlock(); + } + + /** + * Static unlock AWT. + */ + static final void staticUnlockAWT() { + ContextStorage.getSynchronizer().unlock(); + } + + /** + * InvokeAndWait under AWT lock. W/o this method system can hang up. Added + * to support modality (Dialog.show() & PopupMenu.show()) from not event + * dispatch thread. Use in other cases is not recommended. Still can be + * called only for whole API methods that cannot be called from other + * classes API methods. Examples: show() for modal dialogs - correct, only + * user can call it, directly or through setVisible(true) setBounds() for + * components - incorrect, setBounds() can be called from layoutContainer() + * for layout managers + * + * @param runnable + * the runnable. + * @throws InterruptedException + * the interrupted exception. + * @throws InvocationTargetException + * the invocation target exception. + */ + final void unsafeInvokeAndWait(Runnable runnable) throws InterruptedException, + InvocationTargetException { + synchronizer.storeStateAndFree(); + try { + EventQueue.invokeAndWait(runnable); + } finally { + synchronizer.lockAndRestoreState(); + } + } + + /** + * Gets the synchronizer. + * + * @return the synchronizer. + */ + final Synchronizer getSynchronizer() { + return synchronizer; + } + + /** + * Gets the wTK. + * + * @return the wTK. + */ + final WTK getWTK() { + return wtk; + } + + /** + * Gets the property with the specified key and default value. This method + * returns the defValue if the property is not found. + * + * @param propName + * the name of property. + * @param defVal + * the default value. + * @return the property value. + */ + public static String getProperty(String propName, String defVal) { + if (propName == null) { + // awt.7D=Property name is null + throw new NullPointerException(Messages.getString("awt.7D")); //$NON-NLS-1$ + } + staticLockAWT(); + try { + String retVal = null; + if (properties != null) { + try { + retVal = properties.getString(propName); + } catch (MissingResourceException e) { + } catch (ClassCastException e) { + } + } + return (retVal == null) ? defVal : retVal; + } finally { + staticUnlockAWT(); + } + } + + /** + * Gets the default Toolkit. + * + * @return the default Toolkit. + */ + public static Toolkit getDefaultToolkit() { + synchronized (ContextStorage.getContextLock()) { + if (ContextStorage.shutdownPending()) { + return null; + } + Toolkit defToolkit = ContextStorage.getDefaultToolkit(); + if (defToolkit != null) { + return defToolkit; + } + staticLockAWT(); + try { + defToolkit = GraphicsEnvironment.isHeadless() ? new HeadlessToolkit() + : new ToolkitImpl(); + ContextStorage.setDefaultToolkit(defToolkit); + return defToolkit; + } finally { + staticUnlockAWT(); + } + // TODO: read system property named awt.toolkit + // and create an instance of the specified class, + // by default use ToolkitImpl + } + } + + /** + * Gets the default Font. + * + * @return the default Font for Toolkit. + */ + Font getDefaultFont() { + return wtk.getSystemProperties().getDefaultFont(); + } + + /** + * Load resources. + * + * @param path + * the path. + * @return the resource bundle. + */ + private static ResourceBundle loadResources(String path) { + try { + return ResourceBundle.getBundle(path); + } catch (MissingResourceException e) { + return null; + } + } + + /** + * Gets the wTK class name. + * + * @return the wTK class name. + */ + private static String getWTKClassName() { + return "com.android.internal.awt.AndroidWTK"; + } + + /** + * Gets the component by id. + * + * @param id + * the id. + * @return the component by id. + */ + Component getComponentById(long id) { + if (id == 0) { + return null; + } + return null; + } + + /** + * Gets the GraphicsFactory. + * + * @return the GraphicsFactory object. + */ + public GraphicsFactory getGraphicsFactory() { + return wtk.getGraphicsFactory(); + } + + /** + * Instantiates a new toolkit. + */ + public Toolkit() { + init(); + } + + /** + * Initiates AWT. + */ + protected void init() { + lockAWT(); + try { + ComponentInternals.setComponentInternals(new ComponentInternalsImpl()); + new EventQueue(this); // create the system EventQueue + dispatcher = new Dispatcher(this); + final String className = getWTKClassName(); + desktopProperties = new HashMap<String, Object>(); + desktopPropsSupport = new PropertyChangeSupport(this); + awtEventsManager = new AWTEventsManager(); + dispatchThread = new EventDispatchThread(this, dispatcher); + nativeThread = new NativeEventThread(); + NativeEventThread.Init init = new NativeEventThread.Init() { + public WTK init() { + wtk = createWTK(className); + wtk.getNativeEventQueue().setShutdownWatchdog(shutdownWatchdog); + synchronizer.setEnvironment(wtk, dispatchThread); + ContextStorage.setWTK(wtk); + return wtk; + } + }; + nativeThread.start(init); + dispatchThread.start(); + wtk.getNativeEventQueue().awake(); + } finally { + unlockAWT(); + } + } + + /** + * Synchronizes this toolkit's graphics. + */ + public abstract void sync(); + + /** + * Returns the construction status of a specified image that is being + * created. + * + * @param a0 + * the image to be checked. + * @param a1 + * the width of scaled image for which the status is being + * checked or -1. + * @param a2 + * the height of scaled image for which the status is being + * checked or -1. + * @param a3 + * the ImageObserver object to be notified while the image is + * being prepared. + * @return the ImageObserver flags which give the current state of the image + * data. + */ + public abstract int checkImage(Image a0, int a1, int a2, ImageObserver a3); + + /** + * Creates the image with the specified ImageProducer. + * + * @param a0 + * the ImageProducer to be used for image creation. + * @return the image with the specified ImageProducer. + */ + public abstract Image createImage(ImageProducer a0); + + /** + * Creates the image from the specified byte array, offset and length. The + * byte array should contain data with image format supported by Toolkit + * such as JPEG, GIF, or PNG. + * + * @param a0 + * the byte array with the image data. + * @param a1 + * the offset of the beginning the image data in the byte array. + * @param a2 + * the length of the image data in the byte array. + * @return the created Image. + */ + public abstract Image createImage(byte[] a0, int a1, int a2); + + /** + * Creates the image using image data from the specified URL. + * + * @param a0 + * the URL for extracting image data. + * @return the Image. + */ + public abstract Image createImage(URL a0); + + /** + * Creates the image using image data from the specified file. + * + * @param a0 + * the file name which contains image data of supported format. + * @return the Image. + */ + public abstract Image createImage(String a0); + + /** + * Gets the color model. + * + * @return the ColorModel of Toolkit's screen. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + public abstract ColorModel getColorModel() throws HeadlessException; + + /** + * Gets the screen device metrics for the specified font. + * + * @param font + * the Font. + * @return the FontMetrics for the specified Font. + * @deprecated Use getLineMetrics method from Font class. + */ + + @Deprecated + public abstract FontMetrics getFontMetrics(Font font); + + /** + * Prepares the specified image for rendering on the screen with the + * specified size. + * + * @param a0 + * the Image to be prepared. + * @param a1 + * the width of the screen representation or -1 for the current + * screen. + * @param a2 + * the height of the screen representation or -1 for the current + * screen. + * @param a3 + * the ImageObserver object to be notified as soon as the image + * is prepared. + * @return true, if image is fully prepared, false otherwise. + */ + public abstract boolean prepareImage(Image a0, int a1, int a2, ImageObserver a3); + + /** + * Creates an audio beep. + */ + public abstract void beep(); + + /** + * Returns the array of font names which are available in this Toolkit. + * + * @return the array of font names which are available in this Toolkit. + * @deprecated use GraphicsEnvironment.getAvailableFontFamilyNames() method. + */ + @Deprecated + public abstract String[] getFontList(); + + /** + * Gets the the Font implementation using the specified peer interface. + * + * @param a0 + * the Font name to be implemented. + * @param a1 + * the the font style: PLAIN, BOLD, ITALIC. + * @return the FontPeer implementation of the specified Font. + * @deprecated use java.awt.GraphicsEnvironment.getAllFonts method. + */ + + @Deprecated + protected abstract FontPeer getFontPeer(String a0, int a1); + + /** + * Gets the image from the specified file which contains image data in a + * supported image format (such as JPEG, GIF, or PNG); this method should + * return the same Image for multiple calls of this method with the same + * image file name. + * + * @param a0 + * the file name which contains image data in a supported image + * format (such as JPEG, GIF, or PNG). + * @return the Image. + */ + public abstract Image getImage(String a0); + + /** + * Gets the image from the specified URL which contains image data in a + * supported image format (such as JPEG, GIF, or PNG); this method should + * return the same Image for multiple calls of this method with the same + * image URL. + * + * @param a0 + * the URL which contains image data in a supported image format + * (such as JPEG, GIF, or PNG). + * @return the Image. + */ + public abstract Image getImage(URL a0); + + /** + * Gets the screen resolution. + * + * @return the screen resolution. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + public abstract int getScreenResolution() throws HeadlessException; + + /** + * Gets the screen size. + * + * @return a Dimension object containing the width and height of the screen. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + public abstract Dimension getScreenSize() throws HeadlessException; + + /** + * Gets the EventQueue instance without checking access. + * + * @return the system EventQueue. + */ + protected abstract EventQueue getSystemEventQueueImpl(); + + /** + * Returns a map of text attributes for the abstract level description of + * the specified input method highlight, or null if no mapping is found. + * + * @param highlight + * the InputMethodHighlight. + * @return the Map<java.awt.font. text attribute,?>. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + public abstract Map<java.awt.font.TextAttribute, ?> mapInputMethodHighlight( + InputMethodHighlight highlight) throws HeadlessException; + + /** + * Map input method highlight impl. + * + * @param highlight + * the highlight. + * @return the map<java.awt.font. text attribute,?>. + * @throws HeadlessException + * the headless exception. + */ + Map<java.awt.font.TextAttribute, ?> mapInputMethodHighlightImpl(InputMethodHighlight highlight) + throws HeadlessException { + HashMap<java.awt.font.TextAttribute, ?> map = new HashMap<java.awt.font.TextAttribute, Object>(); + wtk.getSystemProperties().mapInputMethodHighlight(highlight, map); + return Collections.<java.awt.font.TextAttribute, Object> unmodifiableMap(map); + } + + /** + * Adds the specified PropertyChangeListener listener for the specified + * property. + * + * @param propName + * the property name for which the specified + * PropertyChangeListener will be added. + * @param l + * the PropertyChangeListener object. + */ + public void addPropertyChangeListener(String propName, PropertyChangeListener l) { + lockAWT(); + try { + if (desktopProperties.isEmpty()) { + initializeDesktopProperties(); + } + } finally { + unlockAWT(); + } + if (l != null) { // there is no guarantee that null listener will not be + // added + desktopPropsSupport.addPropertyChangeListener(propName, l); + } + } + + /** + * Returns an array of the property change listeners registered with this + * Toolkit. + * + * @return an array of the property change listeners registered with this + * Toolkit. + */ + public PropertyChangeListener[] getPropertyChangeListeners() { + return desktopPropsSupport.getPropertyChangeListeners(); + } + + /** + * Returns an array of the property change listeners registered with this + * Toolkit for notification regarding the specified property. + * + * @param propName + * the property name for which the PropertyChangeListener was + * registered. + * @return the array of PropertyChangeListeners registered for the specified + * property name. + */ + public PropertyChangeListener[] getPropertyChangeListeners(String propName) { + return desktopPropsSupport.getPropertyChangeListeners(propName); + } + + /** + * Removes the specified property change listener registered for the + * specified property name. + * + * @param propName + * the property name. + * @param l + * the PropertyChangeListener registered for the specified + * property name. + */ + public void removePropertyChangeListener(String propName, PropertyChangeListener l) { + desktopPropsSupport.removePropertyChangeListener(propName, l); + } + + /** + * Creates a custom cursor with the specified Image, hot spot, and cursor + * description. + * + * @param img + * the image of activated cursor. + * @param hotSpot + * the Point giving the coordinates of the cursor's hot spot. + * @param name + * the cursor description. + * @return the cursor with the specified Image, hot spot, and cursor + * description. + * @throws IndexOutOfBoundsException + * if the hot spot values are outside the bounds of the cursor. + * @throws HeadlessException + * if isHeadless() method of GraphicsEnvironment class returns + * true. + */ + public Cursor createCustomCursor(Image img, Point hotSpot, String name) + throws IndexOutOfBoundsException, HeadlessException { + lockAWT(); + try { + int w = img.getWidth(null), x = hotSpot.x; + int h = img.getHeight(null), y = hotSpot.y; + if (x < 0 || x >= w || y < 0 || y >= h) { + // awt.7E=invalid hotSpot + throw new IndexOutOfBoundsException(Messages.getString("awt.7E")); //$NON-NLS-1$ + } + return new Cursor(name, img, hotSpot); + } finally { + unlockAWT(); + } + } + + /** + * Returns the supported cursor dimension which is closest to the specified + * width and height. If the Toolkit only supports a single cursor size, this + * method should return the supported cursor size. If custom cursor is not + * supported, a dimension of 0, 0 should be returned. + * + * @param prefWidth + * the preferred cursor width. + * @param prefHeight + * the preferred cursor height. + * @return the supported cursor dimension which is closest to the specified + * width and height. + * @throws HeadlessException + * if GraphicsEnvironment.isHeadless() returns true. + */ + public Dimension getBestCursorSize(int prefWidth, int prefHeight) throws HeadlessException { + lockAWT(); + try { + return wtk.getCursorFactory().getBestCursorSize(prefWidth, prefHeight); + } finally { + unlockAWT(); + } + } + + /** + * Gets the value for the specified desktop property. + * + * @param propName + * the property name. + * @return the Object that is the property's value. + */ + public final Object getDesktopProperty(String propName) { + lockAWT(); + try { + if (desktopProperties.isEmpty()) { + initializeDesktopProperties(); + } + if (propName.equals("awt.dynamicLayoutSupported")) { //$NON-NLS-1$ + // dynamicLayoutSupported is special case + return Boolean.valueOf(isDynamicLayoutActive()); + } + Object val = desktopProperties.get(propName); + if (val == null) { + // try to lazily load prop value + // just for compatibility, our lazilyLoad is empty + val = lazilyLoadDesktopProperty(propName); + } + return val; + } finally { + unlockAWT(); + } + } + + /** + * Returns the locking key state for the specified key. + * + * @param a0 + * the key code: VK_CAPS_LOCK, VK_NUM_LOCK, VK_SCROLL_LOCK, or + * VK_KANA_LOCK. + * @return true if the specified key code is in the locked state, false + * otherwise. + * @throws UnsupportedOperationException + * if the state of this key can't be retrieved, or if the + * keyboard doesn't have this key. + * @throws NotImplementedException + * if this method is not implemented. + */ + public boolean getLockingKeyState(int a0) throws UnsupportedOperationException, + org.apache.harmony.luni.util.NotImplementedException { + lockAWT(); + try { + } finally { + unlockAWT(); + } + if (true) { + throw new RuntimeException("Method is not implemented"); //TODO: implement //$NON-NLS-1$ + } + return true; + } + + /** + * Returns the maximum number of colors which the Toolkit supports for + * custom cursor. + * + * @return the maximum cursor colors. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + public int getMaximumCursorColors() throws HeadlessException { + lockAWT(); + try { + return wtk.getCursorFactory().getMaximumCursorColors(); + } finally { + unlockAWT(); + } + } + + /** + * Gets the menu shortcut key mask. + * + * @return the menu shortcut key mask. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + public int getMenuShortcutKeyMask() throws HeadlessException { + lockAWT(); + try { + return InputEvent.CTRL_MASK; + } finally { + unlockAWT(); + } + } + + /** + * Gets the screen insets. + * + * @param gc + * the GraphicsConfiguration. + * @return the insets of this toolkit. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + public Insets getScreenInsets(GraphicsConfiguration gc) throws HeadlessException { + if (gc == null) { + throw new NullPointerException(); + } + lockAWT(); + try { + return new Insets(0, 0, 0, 0); // TODO: get real screen insets + } finally { + unlockAWT(); + } + } + + /** + * Gets the system EventQueue instance. If the default implementation of + * checkAwtEventQueueAccess is used, then this results of a call to the + * security manager's checkPermission method with an + * AWTPermission("accessEventQueue") permission. + * + * @return the system EventQueue instance. + */ + public final EventQueue getSystemEventQueue() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkAwtEventQueueAccess(); + } + return getSystemEventQueueImpl(); + } + + /** + * Gets the system event queue core. + * + * @return the system event queue core. + */ + EventQueueCore getSystemEventQueueCore() { + return systemEventQueueCore; + } + + /** + * Sets the system event queue core. + * + * @param core + * the new system event queue core. + */ + void setSystemEventQueueCore(EventQueueCore core) { + systemEventQueueCore = core; + } + + /** + * Initialize the desktop properties. + */ + protected void initializeDesktopProperties() { + lockAWT(); + try { + wtk.getSystemProperties().init(desktopProperties); + } finally { + unlockAWT(); + } + } + + /** + * Checks if dynamic layout of Containers is active or not. + * + * @return true, if is dynamic layout of Containers is active, false + * otherwise. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + public boolean isDynamicLayoutActive() throws HeadlessException { + lockAWT(); + try { + // always return true + return true; + } finally { + unlockAWT(); + } + } + + /** + * Returns if the layout of Containers is checked dynamically during + * resizing, or statically after resizing is completed. + * + * @return true, if if the layout of Containers is checked dynamically + * during resizing; false, if the layout of Containers is checked + * statically after resizing is completed. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + protected boolean isDynamicLayoutSet() throws HeadlessException { + lockAWT(); + try { + return bDynamicLayoutSet; + } finally { + unlockAWT(); + } + } + + /** + * Checks if the specified frame state is supported by Toolkit or not. + * + * @param state + * the frame state. + * @return true, if frame state is supported, false otherwise. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + public boolean isFrameStateSupported(int state) throws HeadlessException { + lockAWT(); + try { + return wtk.getWindowFactory().isWindowStateSupported(state); + } finally { + unlockAWT(); + } + } + + /** + * Loads the value of the desktop property with the specified property name. + * + * @param propName + * the property name. + * @return the desktop property values. + */ + protected Object lazilyLoadDesktopProperty(String propName) { + return null; + } + + /** + * Loads the current system color values to the specified array. + * + * @param colors + * the array where the current system color values are written by + * this method. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + protected void loadSystemColors(int[] colors) throws HeadlessException { + lockAWT(); + try { + } finally { + unlockAWT(); + } + } + + /** + * Sets the value of the desktop property with the specified name. + * + * @param propName + * the property's name. + * @param value + * the property's value. + */ + protected final void setDesktopProperty(String propName, Object value) { + Object oldVal; + lockAWT(); + try { + oldVal = getDesktopProperty(propName); + userPropSet.add(propName); + desktopProperties.put(propName, value); + } finally { + unlockAWT(); + } + desktopPropsSupport.firePropertyChange(propName, oldVal, value); + } + + /** + * Sets the layout state, whether the Container layout is checked + * dynamically during resizing, or statically after resizing is completed. + * + * @param dynamic + * the new dynamic layout state - if true the layout of + * Containers is checked dynamically during resizing, if false - + * statically after resizing is completed. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + public void setDynamicLayout(boolean dynamic) throws HeadlessException { + lockAWT(); + try { + bDynamicLayoutSet = dynamic; + } finally { + unlockAWT(); + } + } + + /** + * Sets the locking key state for the specified key code. + * + * @param a0 + * the key code: VK_CAPS_LOCK, VK_NUM_LOCK, VK_SCROLL_LOCK, or + * VK_KANA_LOCK. + * @param a1 + * the state - true to set the specified key code to the locked + * state, false - to unlock it. + * @throws UnsupportedOperationException + * if the state of this key can't be set, or if the keyboard + * doesn't have this key. + * @throws NotImplementedException + * if this method is not implemented. + */ + public void setLockingKeyState(int a0, boolean a1) throws UnsupportedOperationException, + org.apache.harmony.luni.util.NotImplementedException { + lockAWT(); + try { + } finally { + unlockAWT(); + } + if (true) { + throw new RuntimeException("Method is not implemented"); //TODO: implement //$NON-NLS-1$ + } + return; + } + + /** + * On queue empty. + */ + void onQueueEmpty() { + throw new RuntimeException("Not implemented!"); + } + + /** + * Creates the wtk. + * + * @param clsName + * the cls name. + * @return the wTK. + */ + private WTK createWTK(String clsName) { + WTK newWTK = null; + try { + newWTK = (WTK)Class.forName(clsName).newInstance(); + } catch (Exception e) { + throw new RuntimeException(e); + } + return newWTK; + } + + /** + * Connect the component to its native window + * + * @param winId + * the id of native window just created. + */ + boolean onWindowCreated(long winId) { + return false; + } + + /** + * Gets the native event queue. + * + * @return the native event queue. + */ + NativeEventQueue getNativeEventQueue() { + return wtk.getNativeEventQueue(); + } + + /** + * Returns a shared instance of implementation of + * org.apache.harmony.awt.wtk.NativeCursor for current platform for. + * + * @param type + * the Java Cursor type. + * @return new instance of implementation of NativeCursor. + */ + NativeCursor createNativeCursor(int type) { + return wtk.getCursorFactory().getCursor(type); + } + + /** + * Returns a shared instance of implementation of + * org.apache.harmony.awt.wtk.NativeCursor for current platform for custom + * cursor + * + * @param img + * the img. + * @param hotSpot + * the hot spot. + * @param name + * the name. + * @return new instance of implementation of NativeCursor. + */ + NativeCursor createCustomNativeCursor(Image img, Point hotSpot, String name) { + return wtk.getCursorFactory().createCustomCursor(img, hotSpot.x, hotSpot.y); + } + + /** + * Adds an AWTEventListener to the Toolkit to listen for events of types + * corresponding to bits in the specified event mask. Event masks are + * defined in AWTEvent class. + * + * @param listener + * the AWTEventListener. + * @param eventMask + * the bitmask of event types. + */ + public void addAWTEventListener(AWTEventListener listener, long eventMask) { + lockAWT(); + try { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkPermission(awtEventsManager.permission); + } + awtEventsManager.addAWTEventListener(listener, eventMask); + } finally { + unlockAWT(); + } + } + + /** + * Removes the specified AWT event listener. + * + * @param listener + * the AWTEventListener to be removed. + */ + public void removeAWTEventListener(AWTEventListener listener) { + lockAWT(); + try { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkPermission(awtEventsManager.permission); + } + awtEventsManager.removeAWTEventListener(listener); + } finally { + unlockAWT(); + } + } + + /** + * Gets the array of all AWT event listeners registered with this Toolkit. + * + * @return the array of all AWT event listeners registered with this + * Toolkit. + */ + public AWTEventListener[] getAWTEventListeners() { + lockAWT(); + try { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkPermission(awtEventsManager.permission); + } + return awtEventsManager.getAWTEventListeners(); + } finally { + unlockAWT(); + } + } + + /** + * Returns the array of the AWT event listeners registered with this Toolkit + * for the event types corresponding to the specified event mask. + * + * @param eventMask + * the bit mask of event type. + * @return the array of the AWT event listeners registered in this Toolkit + * for the event types corresponding to the specified event mask. + */ + public AWTEventListener[] getAWTEventListeners(long eventMask) { + lockAWT(); + try { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkPermission(awtEventsManager.permission); + } + return awtEventsManager.getAWTEventListeners(eventMask); + } finally { + unlockAWT(); + } + } + + /** + * Dispatch AWT event. + * + * @param event + * the event. + */ + void dispatchAWTEvent(AWTEvent event) { + awtEventsManager.dispatchAWTEvent(event); + } + + /** + * The Class AWTEventsManager. + */ + final class AWTEventsManager { + + /** + * The permission. + */ + AWTPermission permission = new AWTPermission("listenToAllAWTEvents"); //$NON-NLS-1$ + + /** + * The listeners. + */ + private final AWTListenerList<AWTEventListenerProxy> listeners = new AWTListenerList<AWTEventListenerProxy>(); + + /** + * Adds the AWT event listener. + * + * @param listener + * the listener. + * @param eventMask + * the event mask. + */ + void addAWTEventListener(AWTEventListener listener, long eventMask) { + if (listener != null) { + listeners.addUserListener(new AWTEventListenerProxy(eventMask, listener)); + } + } + + /** + * Removes the AWT event listener. + * + * @param listener + * the listener. + */ + void removeAWTEventListener(AWTEventListener listener) { + if (listener != null) { + for (AWTEventListenerProxy proxy : listeners.getUserListeners()) { + if (listener == proxy.getListener()) { + listeners.removeUserListener(proxy); + return; + } + } + } + } + + /** + * Gets the AWT event listeners. + * + * @return the AWT event listeners. + */ + AWTEventListener[] getAWTEventListeners() { + HashSet<EventListener> listenersSet = new HashSet<EventListener>(); + for (AWTEventListenerProxy proxy : listeners.getUserListeners()) { + listenersSet.add(proxy.getListener()); + } + return listenersSet.toArray(new AWTEventListener[listenersSet.size()]); + } + + /** + * Gets the AWT event listeners. + * + * @param eventMask + * the event mask. + * @return the AWT event listeners. + */ + AWTEventListener[] getAWTEventListeners(long eventMask) { + HashSet<EventListener> listenersSet = new HashSet<EventListener>(); + for (AWTEventListenerProxy proxy : listeners.getUserListeners()) { + if ((proxy.getEventMask() & eventMask) == eventMask) { + listenersSet.add(proxy.getListener()); + } + } + return listenersSet.toArray(new AWTEventListener[listenersSet.size()]); + } + + /** + * Dispatch AWT event. + * + * @param event + * the event. + */ + void dispatchAWTEvent(AWTEvent event) { + AWTEvent.EventDescriptor descriptor = eventTypeLookup.getEventDescriptor(event); + if (descriptor == null) { + return; + } + for (AWTEventListenerProxy proxy : listeners.getUserListeners()) { + if ((proxy.getEventMask() & descriptor.eventMask) != 0) { + proxy.eventDispatched(event); + } + } + } + } + + /** + * The Class AutoNumber. + */ + static final class AutoNumber { + + /** + * The next component. + */ + int nextComponent = 0; + + /** + * The next canvas. + */ + int nextCanvas = 0; + + /** + * The next panel. + */ + int nextPanel = 0; + + /** + * The next window. + */ + int nextWindow = 0; + + /** + * The next frame. + */ + int nextFrame = 0; + + /** + * The next dialog. + */ + int nextDialog = 0; + + /** + * The next button. + */ + int nextButton = 0; + + /** + * The next menu component. + */ + int nextMenuComponent = 0; + + /** + * The next label. + */ + int nextLabel = 0; + + /** + * The next check box. + */ + int nextCheckBox = 0; + + /** + * The next scrollbar. + */ + int nextScrollbar = 0; + + /** + * The next scroll pane. + */ + int nextScrollPane = 0; + + /** + * The next list. + */ + int nextList = 0; + + /** + * The next choice. + */ + int nextChoice = 0; + + /** + * The next file dialog. + */ + int nextFileDialog = 0; + + /** + * The next text area. + */ + int nextTextArea = 0; + + /** + * The next text field. + */ + int nextTextField = 0; + } + + private class Lock { + } + + /** + * The lock. + */ + private final Object lock = new Lock(); + +} diff --git a/awt/java/awt/ToolkitImpl.java b/awt/java/awt/ToolkitImpl.java new file mode 100644 index 0000000..5015aef --- /dev/null +++ b/awt/java/awt/ToolkitImpl.java @@ -0,0 +1,255 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.awt; + +import java.awt.im.InputMethodHighlight; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.peer.*; +import java.io.Serializable; +import java.net.URL; +import java.util.Hashtable; +import java.util.Map; +import org.apache.harmony.awt.gl.image.*; +import org.apache.harmony.awt.wtk.GraphicsFactory; + +class ToolkitImpl extends Toolkit { + + static final Hashtable<Serializable, Image> imageCache = new Hashtable<Serializable, Image>(); + + @Override + public void sync() { + lockAWT(); + try { + } finally { + unlockAWT(); + } + } + + @Override + public int checkImage(Image image, int width, int height, ImageObserver observer) { + lockAWT(); + try { + if (width == 0 || height == 0) { + return ImageObserver.ALLBITS; + } + if (!(image instanceof OffscreenImage)) { + return ImageObserver.ALLBITS; + } + OffscreenImage oi = (OffscreenImage) image; + return oi.checkImage(observer); + } finally { + unlockAWT(); + } + } + + @Override + public Image createImage(ImageProducer producer) { + lockAWT(); + try { + return new OffscreenImage(producer); + } finally { + unlockAWT(); + } + } + + @Override + public Image createImage(byte[] imagedata, int imageoffset, int imagelength) { + lockAWT(); + try { + return new OffscreenImage(new ByteArrayDecodingImageSource(imagedata, imageoffset, + imagelength)); + } finally { + unlockAWT(); + } + } + + @Override + public Image createImage(URL url) { + lockAWT(); + try { + return new OffscreenImage(new URLDecodingImageSource(url)); + } finally { + unlockAWT(); + } + } + + @Override + public Image createImage(String filename) { + lockAWT(); + try { + return new OffscreenImage(new FileDecodingImageSource(filename)); + } finally { + unlockAWT(); + } + } + + @Override + public ColorModel getColorModel() { + lockAWT(); + try { + return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice() + .getDefaultConfiguration().getColorModel(); + } finally { + unlockAWT(); + } + } + + @SuppressWarnings("deprecation") + @Override + @Deprecated + public FontMetrics getFontMetrics(Font font) { + lockAWT(); + try { + GraphicsFactory gf = getGraphicsFactory(); + return gf.getFontMetrics(font); + } finally { + unlockAWT(); + } + } + + @Override + public boolean prepareImage(Image image, int width, int height, ImageObserver observer) { + lockAWT(); + try { + if (width == 0 || height == 0) { + return true; + } + if (!(image instanceof OffscreenImage)) { + return true; + } + OffscreenImage oi = (OffscreenImage) image; + return oi.prepareImage(observer); + } finally { + unlockAWT(); + } + } + + @Override + public void beep() { + lockAWT(); + try { + // ???AWT: is there nothing to be implemented here? + } finally { + unlockAWT(); + } + } + + @SuppressWarnings("deprecation") + @Override + @Deprecated + public String[] getFontList() { + lockAWT(); + try { + } finally { + unlockAWT(); + } + return null; + } + + @SuppressWarnings("deprecation") + @Override + @Deprecated + protected FontPeer getFontPeer(String a0, int a1) { + lockAWT(); + try { + return null; + } finally { + unlockAWT(); + } + } + + @Override + public Image getImage(String filename) { + return getImage(filename, this); + } + + static Image getImage(String filename, Toolkit toolkit) { + synchronized (imageCache) { + Image im = (filename == null ? null : imageCache.get(filename)); + + if (im == null) { + try { + im = toolkit.createImage(filename); + imageCache.put(filename, im); + } catch (Exception e) { + } + } + + return im; + } + } + + @Override + public Image getImage(URL url) { + return getImage(url, this); + } + + static Image getImage(URL url, Toolkit toolkit) { + synchronized (imageCache) { + Image im = imageCache.get(url); + if (im == null) { + try { + im = toolkit.createImage(url); + imageCache.put(url, im); + } catch (Exception e) { + } + } + return im; + } + } + + @Override + public int getScreenResolution() throws HeadlessException { + lockAWT(); + try { + return 62; + } finally { + unlockAWT(); + } + } + + @Override + public Dimension getScreenSize() { + lockAWT(); + try { + DisplayMode dm = GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDisplayMode(); + return new Dimension(dm.getWidth(), dm.getHeight()); + } finally { + unlockAWT(); + } + } + + @Override + public Map<java.awt.font.TextAttribute, ?> mapInputMethodHighlight( + InputMethodHighlight highlight) throws HeadlessException { + lockAWT(); + try { + return mapInputMethodHighlightImpl(highlight); + } finally { + unlockAWT(); + } + } + + @Override + protected EventQueue getSystemEventQueueImpl() { + return getSystemEventQueueCore().getActiveEventQueue(); + } +} diff --git a/awt/java/awt/Transparency.java b/awt/java/awt/Transparency.java new file mode 100644 index 0000000..44a1e7f --- /dev/null +++ b/awt/java/awt/Transparency.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ + +package java.awt; + +/** + * The Transparency interface defines transparency's general modes. + * + * @since Android 1.0 + */ +public interface Transparency { + + /** + * The Constant OPAQUE represents completely opaque data, all pixels have an + * alpha value of 1.0. + */ + public static final int OPAQUE = 1; + + /** + * The Constant BITMASK represents data which can be either completely + * opaque, with an alpha value of 1.0, or completely transparent, with an + * alpha value of 0.0. + */ + public static final int BITMASK = 2; + + /** + * The Constant TRANSLUCENT represents data which alpha value can vary + * between and including 0.0 and 1.0. + */ + public static final int TRANSLUCENT = 3; + + /** + * Gets the transparency mode. + * + * @return the transparency mode: OPAQUE, BITMASK or TRANSLUCENT. + */ + public int getTransparency(); + +} diff --git a/awt/java/awt/color/CMMException.java b/awt/java/awt/color/CMMException.java new file mode 100644 index 0000000..18b9a7e --- /dev/null +++ b/awt/java/awt/color/CMMException.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +package java.awt.color; + +/** + * The CMMException is thrown as soon as a native CMM error occurs. + * + * @since Android 1.0 + */ +public class CMMException extends java.lang.RuntimeException { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 5775558044142994965L; + + /** + * Instantiates a new CMM exception with detail message. + * + * @param s + * the detail message of the exception. + */ + public CMMException (String s) { + super (s); + } +} diff --git a/awt/java/awt/color/ColorSpace.java b/awt/java/awt/color/ColorSpace.java new file mode 100644 index 0000000..44c491b --- /dev/null +++ b/awt/java/awt/color/ColorSpace.java @@ -0,0 +1,414 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +package java.awt.color; + +import java.io.Serializable; + +import org.apache.harmony.awt.gl.color.LUTColorConverter; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The ColorSpace class defines a color space type for a Color and provides + * methods for arrays of color component operations. + * + * @since Android 1.0 + */ +public abstract class ColorSpace implements Serializable { + + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = -409452704308689724L; + + /** + * The Constant TYPE_XYZ indicates XYZ color space type. + */ + public static final int TYPE_XYZ = 0; + + /** + * The Constant TYPE_Lab indicates Lab color space type. + */ + public static final int TYPE_Lab = 1; + + /** + * The Constant TYPE_Luv indicates Luv color space type. + */ + public static final int TYPE_Luv = 2; + + /** + * The Constant TYPE_YCbCr indicates YCbCr color space type. + */ + public static final int TYPE_YCbCr = 3; + + /** + * The Constant TYPE_Yxy indicates Yxy color space type. + */ + public static final int TYPE_Yxy = 4; + + /** + * The Constant TYPE_RGB indicates RGB color space type. + */ + public static final int TYPE_RGB = 5; + + /** + * The Constant TYPE_GRAY indicates Gray color space type. + */ + public static final int TYPE_GRAY = 6; + + /** + * The Constant TYPE_HSV indicates HSV color space type. + */ + public static final int TYPE_HSV = 7; + + /** + * The Constant TYPE_HLS indicates HLS color space type. + */ + public static final int TYPE_HLS = 8; + + /** + * The Constant TYPE_CMYK indicates CMYK color space type. + */ + public static final int TYPE_CMYK = 9; + + /** + * The Constant TYPE_CMY indicates CMY color space type. + */ + public static final int TYPE_CMY = 11; + + /** + * The Constant TYPE_2CLR indicates color spaces with 2 components. + */ + public static final int TYPE_2CLR = 12; + + /** + * The Constant TYPE_3CLR indicates color spaces with 3 components. + */ + public static final int TYPE_3CLR = 13; + + /** + * The Constant TYPE_4CLR indicates color spaces with 4 components. + */ + public static final int TYPE_4CLR = 14; + + /** + * The Constant TYPE_5CLR indicates color spaces with 5 components. + */ + public static final int TYPE_5CLR = 15; + + /** + * The Constant TYPE_6CLR indicates color spaces with 6 components. + */ + public static final int TYPE_6CLR = 16; + + /** + * The Constant TYPE_7CLR indicates color spaces with 7 components. + */ + public static final int TYPE_7CLR = 17; + + /** + * The Constant TYPE_8CLR indicates color spaces with 8 components. + */ + public static final int TYPE_8CLR = 18; + + /** + * The Constant TYPE_9CLR indicates color spaces with 9 components. + */ + public static final int TYPE_9CLR = 19; + + /** + * The Constant TYPE_ACLR indicates color spaces with 10 components. + */ + public static final int TYPE_ACLR = 20; + + /** + * The Constant TYPE_BCLR indicates color spaces with 11 components. + */ + public static final int TYPE_BCLR = 21; + + /** + * The Constant TYPE_CCLR indicates color spaces with 12 components. + */ + public static final int TYPE_CCLR = 22; + + /** + * The Constant TYPE_DCLR indicates color spaces with 13 components. + */ + public static final int TYPE_DCLR = 23; + + /** + * The Constant TYPE_ECLR indicates color spaces with 14 components. + */ + public static final int TYPE_ECLR = 24; + + /** + * The Constant TYPE_FCLR indicates color spaces with 15 components. + */ + public static final int TYPE_FCLR = 25; + + /** + * The Constant CS_sRGB indicates standard RGB color space. + */ + public static final int CS_sRGB = 1000; + + /** + * The Constant CS_LINEAR_RGB indicates linear RGB color space. + */ + public static final int CS_LINEAR_RGB = 1004; + + /** + * The Constant CS_CIEXYZ indicates CIEXYZ conversion color space. + */ + public static final int CS_CIEXYZ = 1001; + + /** + * The Constant CS_PYCC indicates Photo YCC conversion color space. + */ + public static final int CS_PYCC = 1002; + + /** + * The Constant CS_GRAY indicates linear gray scale color space. + */ + public static final int CS_GRAY = 1003; + + /** + * The cs_ gray. + */ + private static ColorSpace cs_Gray = null; + + /** + * The cs_ pycc. + */ + private static ColorSpace cs_PYCC = null; + + /** + * The cs_ ciexyz. + */ + private static ColorSpace cs_CIEXYZ = null; + + /** + * The cs_ lrgb. + */ + private static ColorSpace cs_LRGB = null; + + /** + * The cs_s rgb. + */ + private static ColorSpace cs_sRGB = null; + + /** + * The type. + */ + private int type; + + /** + * The num components. + */ + private int numComponents; + + /** + * Instantiates a ColorSpace with the specified ColorSpace type and number + * of components. + * + * @param type + * the type of color space. + * @param numcomponents + * the number of components. + */ + protected ColorSpace(int type, int numcomponents) { + this.numComponents = numcomponents; + this.type = type; + } + + /** + * Gets the name of the component for the specified component index. + * + * @param idx + * the index of the component. + * @return the name of the component. + */ + public String getName(int idx) { + if (idx < 0 || idx > numComponents - 1) { + // awt.16A=Invalid component index: {0} + throw new IllegalArgumentException(Messages.getString("awt.16A", idx)); //$NON-NLS-1$ + } + + return "Unnamed color component #" + idx; //$NON-NLS-1$ + } + + /** + * Performs the transformation of a color from this ColorSpace into the RGB + * color space. + * + * @param colorvalue + * the color value in this ColorSpace. + * @return the float array with color components in the RGB color space. + */ + public abstract float[] toRGB(float[] colorvalue); + + /** + * Performs the transformation of a color from this ColorSpace into the + * CS_CIEXYZ color space. + * + * @param colorvalue + * the color value in this ColorSpace. + * @return the float array with color components in the CS_CIEXYZ color + * space. + */ + public abstract float[] toCIEXYZ(float[] colorvalue); + + /** + * Performs the transformation of a color from the RGB color space into this + * ColorSpace. + * + * @param rgbvalue + * the float array representing a color in the RGB color space. + * @return the float array with the transformed color components. + */ + public abstract float[] fromRGB(float[] rgbvalue); + + /** + * Performs the transformation of a color from the CS_CIEXYZ color space + * into this ColorSpace. + * + * @param colorvalue + * the float array representing a color in the CS_CIEXYZ color + * space. + * @return the float array with the transformed color components. + */ + public abstract float[] fromCIEXYZ(float[] colorvalue); + + /** + * Gets the minimum normalized color component value for the specified + * component. + * + * @param component + * the component to determine the minimum value. + * @return the minimum normalized value of the component. + */ + public float getMinValue(int component) { + if (component < 0 || component > numComponents - 1) { + // awt.16A=Invalid component index: {0} + throw new IllegalArgumentException(Messages.getString("awt.16A", component)); //$NON-NLS-1$ + } + return 0; + } + + /** + * Gets the maximum normalized color component value for the specified + * component. + * + * @param component + * the component to determine the maximum value. + * @return the maximum normalized value of the component. + */ + public float getMaxValue(int component) { + if (component < 0 || component > numComponents - 1) { + // awt.16A=Invalid component index: {0} + throw new IllegalArgumentException(Messages.getString("awt.16A", component)); //$NON-NLS-1$ + } + return 1; + } + + /** + * Checks if this ColorSpace has CS_sRGB type or not. + * + * @return true, if this ColorSpace has CS_sRGB type, false otherwise. + */ + public boolean isCS_sRGB() { + // If our color space is sRGB, then cs_sRGB + // is already initialized + return (this == cs_sRGB); + } + + /** + * Gets the type of the ColorSpace. + * + * @return the type of the ColorSpace. + */ + public int getType() { + return type; + } + + /** + * Gets the number of components for this ColorSpace. + * + * @return the number of components. + */ + public int getNumComponents() { + return numComponents; + } + + + /** + * Gets the single instance of ColorSpace with the specified ColorSpace: + * CS_sRGB, CS_LINEAR_RGB, CS_CIEXYZ, CS_GRAY, or CS_PYCC. + * + * @param colorspace + * the identifier of the specified Colorspace. + * @return the single instance of the desired ColorSpace. + */ + public static ColorSpace getInstance(int colorspace) { + switch (colorspace) { + case CS_sRGB: + if (cs_sRGB == null) { + cs_sRGB = new ICC_ColorSpace( + new ICC_ProfileStub(CS_sRGB)); + LUTColorConverter.sRGB_CS = cs_sRGB; + //ICC_Profile.getInstance (CS_sRGB)); + } + return cs_sRGB; + case CS_CIEXYZ: + if (cs_CIEXYZ == null) { + cs_CIEXYZ = new ICC_ColorSpace( + new ICC_ProfileStub(CS_CIEXYZ)); + //ICC_Profile.getInstance (CS_CIEXYZ)); + } + return cs_CIEXYZ; + case CS_GRAY: + if (cs_Gray == null) { + cs_Gray = new ICC_ColorSpace( + new ICC_ProfileStub(CS_GRAY)); + LUTColorConverter.LINEAR_GRAY_CS = cs_Gray; + //ICC_Profile.getInstance (CS_GRAY)); + } + return cs_Gray; + case CS_PYCC: + if (cs_PYCC == null) { + cs_PYCC = new ICC_ColorSpace( + new ICC_ProfileStub(CS_PYCC)); + //ICC_Profile.getInstance (CS_PYCC)); + } + return cs_PYCC; + case CS_LINEAR_RGB: + if (cs_LRGB == null) { + cs_LRGB = new ICC_ColorSpace( + new ICC_ProfileStub(CS_LINEAR_RGB)); + LUTColorConverter.LINEAR_GRAY_CS = cs_Gray; + //ICC_Profile.getInstance (CS_LINEAR_RGB)); + } + return cs_LRGB; + default: + } + + // Unknown argument passed + // awt.16B=Not a predefined colorspace + throw new IllegalArgumentException(Messages.getString("Not a predefined colorspace")); //$NON-NLS-1$ + } + +}
\ No newline at end of file diff --git a/awt/java/awt/color/ICC_ColorSpace.java b/awt/java/awt/color/ICC_ColorSpace.java new file mode 100644 index 0000000..5b4d7e9 --- /dev/null +++ b/awt/java/awt/color/ICC_ColorSpace.java @@ -0,0 +1,468 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +package java.awt.color; + +import org.apache.harmony.awt.gl.color.ColorConverter; +import org.apache.harmony.awt.gl.color.ColorScaler; +import org.apache.harmony.awt.gl.color.ICC_Transform; +import org.apache.harmony.awt.internal.nls.Messages; + +import java.io.*; + +/** + * This class implements the abstract class ColorSpace and represents device + * independent and device dependent color spaces. This color space is based on + * the International Color Consortium Specification (ICC) File Format for Color + * Profiles: <a href="http://www.color.org">http://www.color.org</a> + * + * @since Android 1.0 + */ +public class ICC_ColorSpace extends ColorSpace { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 3455889114070431483L; + + // Need to keep compatibility with serialized form + /** + * The Constant serialPersistentFields. + */ + private static final ObjectStreamField[] + serialPersistentFields = { + new ObjectStreamField("thisProfile", ICC_Profile.class), //$NON-NLS-1$ + new ObjectStreamField("minVal", float[].class), //$NON-NLS-1$ + new ObjectStreamField("maxVal", float[].class), //$NON-NLS-1$ + new ObjectStreamField("diffMinMax", float[].class), //$NON-NLS-1$ + new ObjectStreamField("invDiffMinMax", float[].class), //$NON-NLS-1$ + new ObjectStreamField("needScaleInit", Boolean.TYPE) //$NON-NLS-1$ + }; + + + /** + * According to ICC specification (from http://www.color.org) "For the + * CIEXYZ encoding, each component (X, Y, and Z) is encoded as a + * u1Fixed15Number". This means that max value for this encoding is 1 + + * (32767/32768) + */ + private static final float MAX_XYZ = 1f + (32767f/32768f); + + /** + * The Constant MAX_SHORT. + */ + private static final float MAX_SHORT = 65535f; + + /** + * The Constant INV_MAX_SHORT. + */ + private static final float INV_MAX_SHORT = 1f/MAX_SHORT; + + /** + * The Constant SHORT2XYZ_FACTOR. + */ + private static final float SHORT2XYZ_FACTOR = MAX_XYZ/MAX_SHORT; + + /** + * The Constant XYZ2SHORT_FACTOR. + */ + private static final float XYZ2SHORT_FACTOR = MAX_SHORT/MAX_XYZ; + + /** + * The profile. + */ + private ICC_Profile profile = null; + + /** + * The min values. + */ + private float minValues[] = null; + + /** + * The max values. + */ + private float maxValues[] = null; + + // cache transforms here - performance gain + /** + * The to rgb transform. + */ + private ICC_Transform toRGBTransform = null; + + /** + * The from rgb transform. + */ + private ICC_Transform fromRGBTransform = null; + + /** + * The to xyz transform. + */ + private ICC_Transform toXYZTransform = null; + + /** + * The from xyz transform. + */ + private ICC_Transform fromXYZTransform = null; + + /** + * The converter. + */ + private final ColorConverter converter = new ColorConverter(); + + /** + * The scaler. + */ + private final ColorScaler scaler = new ColorScaler(); + + /** + * The scaling data loaded. + */ + private boolean scalingDataLoaded = false; + + /** + * The resolved deserialized inst. + */ + private ICC_ColorSpace resolvedDeserializedInst; + + /** + * Instantiates a new ICC color space from an ICC_Profile object. + * + * @param pf + * the ICC_Profile object. + */ + public ICC_ColorSpace(ICC_Profile pf) { + super(pf.getColorSpaceType(), pf.getNumComponents()); + + int pfClass = pf.getProfileClass(); + + switch (pfClass) { + case ICC_Profile.CLASS_COLORSPACECONVERSION: + case ICC_Profile.CLASS_DISPLAY: + case ICC_Profile.CLASS_OUTPUT: + case ICC_Profile.CLASS_INPUT: + break; // OK, it is color conversion profile + default: + // awt.168=Invalid profile class. + throw new IllegalArgumentException(Messages.getString("awt.168")); //$NON-NLS-1$ + } + + profile = pf; + fillMinMaxValues(); + } + + /** + * Gets the ICC_Profile for this ICC_ColorSpace. + * + * @return the ICC_Profile for this ICC_ColorSpace. + */ + public ICC_Profile getProfile() { + if (profile instanceof ICC_ProfileStub) { + profile = ((ICC_ProfileStub) profile).loadProfile(); + } + + return profile; + } + + /** + * Performs the transformation of a color from this ColorSpace into the RGB + * color space. + * + * @param colorvalue + * the color value in this ColorSpace. + * @return the float array with color components in the RGB color space. + */ + @Override + public float[] toRGB(float[] colorvalue) { + if (toRGBTransform == null) { + ICC_Profile sRGBProfile = + ((ICC_ColorSpace) ColorSpace.getInstance(CS_sRGB)).getProfile(); + ICC_Profile[] profiles = {getProfile(), sRGBProfile}; + toRGBTransform = new ICC_Transform(profiles); + if (!scalingDataLoaded) { + scaler.loadScalingData(this); + scalingDataLoaded = true; + } + } + + short[] data = new short[getNumComponents()]; + + scaler.scale(colorvalue, data, 0); + + short[] converted = + converter.translateColor(toRGBTransform, data, null); + + // unscale to sRGB + float[] res = new float[3]; + + res[0] = ((converted[0] & 0xFFFF)) * INV_MAX_SHORT; + res[1] = ((converted[1] & 0xFFFF)) * INV_MAX_SHORT; + res[2] = ((converted[2] & 0xFFFF)) * INV_MAX_SHORT; + + return res; + } + + /** + * Performs the transformation of a color from this ColorSpace into the + * CS_CIEXYZ color space. + * + * @param colorvalue + * the color value in this ColorSpace. + * @return the float array with color components in the CS_CIEXYZ color + * space. + */ + @Override + public float[] toCIEXYZ(float[] colorvalue) { + if (toXYZTransform == null) { + ICC_Profile xyzProfile = + ((ICC_ColorSpace) ColorSpace.getInstance(CS_CIEXYZ)).getProfile(); + ICC_Profile[] profiles = {getProfile(), xyzProfile}; + try { + int[] intents = { + ICC_Profile.icRelativeColorimetric, + ICC_Profile.icPerceptual}; + toXYZTransform = new ICC_Transform(profiles, intents); + } catch (CMMException e) { // No such tag, use what we can + toXYZTransform = new ICC_Transform(profiles); + } + + if (!scalingDataLoaded) { + scaler.loadScalingData(this); + scalingDataLoaded = true; + } + } + + short[] data = new short[getNumComponents()]; + + scaler.scale(colorvalue, data, 0); + + short[] converted = + converter.translateColor(toXYZTransform, data, null); + + // unscale to XYZ + float[] res = new float[3]; + + res[0] = ((converted[0] & 0xFFFF)) * SHORT2XYZ_FACTOR; + res[1] = ((converted[1] & 0xFFFF)) * SHORT2XYZ_FACTOR; + res[2] = ((converted[2] & 0xFFFF)) * SHORT2XYZ_FACTOR; + + return res; + } + + /** + * Performs the transformation of a color from the RGB color space into this + * ColorSpace. + * + * @param rgbvalue + * the float array representing a color in the RGB color space. + * @return the float array with the transformed color components. + */ + @Override + public float[] fromRGB(float[] rgbvalue) { + if (fromRGBTransform == null) { + ICC_Profile sRGBProfile = + ((ICC_ColorSpace) ColorSpace.getInstance(CS_sRGB)).getProfile(); + ICC_Profile[] profiles = {sRGBProfile, getProfile()}; + fromRGBTransform = new ICC_Transform(profiles); + if (!scalingDataLoaded) { + scaler.loadScalingData(this); + scalingDataLoaded = true; + } + } + + // scale rgb value to short + short[] scaledRGBValue = new short[3]; + scaledRGBValue[0] = (short)(rgbvalue[0] * MAX_SHORT + 0.5f); + scaledRGBValue[1] = (short)(rgbvalue[1] * MAX_SHORT + 0.5f); + scaledRGBValue[2] = (short)(rgbvalue[2] * MAX_SHORT + 0.5f); + + short[] converted = + converter.translateColor(fromRGBTransform, scaledRGBValue, null); + + float[] res = new float[getNumComponents()]; + + scaler.unscale(res, converted, 0); + + return res; + } + + /** + * Performs the transformation of a color from the CS_CIEXYZ color space + * into this ColorSpace. + * + * @param xyzvalue + * the float array representing a color in the CS_CIEXYZ color + * space. + * @return the float array with the transformed color components. + */ + @Override + public float[] fromCIEXYZ(float[] xyzvalue) { + if (fromXYZTransform == null) { + ICC_Profile xyzProfile = + ((ICC_ColorSpace) ColorSpace.getInstance(CS_CIEXYZ)).getProfile(); + ICC_Profile[] profiles = {xyzProfile, getProfile()}; + try { + int[] intents = { + ICC_Profile.icPerceptual, + ICC_Profile.icRelativeColorimetric}; + fromXYZTransform = new ICC_Transform(profiles, intents); + } catch (CMMException e) { // No such tag, use what we can + fromXYZTransform = new ICC_Transform(profiles); + } + + if (!scalingDataLoaded) { + scaler.loadScalingData(this); + scalingDataLoaded = true; + } + + } + + // scale xyz value to short + short[] scaledXYZValue = new short[3]; + scaledXYZValue[0] = (short)(xyzvalue[0] * XYZ2SHORT_FACTOR + 0.5f); + scaledXYZValue[1] = (short)(xyzvalue[1] * XYZ2SHORT_FACTOR + 0.5f); + scaledXYZValue[2] = (short)(xyzvalue[2] * XYZ2SHORT_FACTOR + 0.5f); + + short[] converted = + converter.translateColor(fromXYZTransform, scaledXYZValue, null); + + float[] res = new float[getNumComponents()]; + + scaler.unscale(res, converted, 0); + + return res; + } + + /** + * Gets the minimum normalized color component value for the specified + * component. + * + * @param component + * the component to determine the minimum value. + * @return the minimum normalized value of the component. + */ + @Override + public float getMinValue(int component) { + if ((component < 0) || (component > this.getNumComponents() - 1)) { + // awt.169=Component index out of range + throw new IllegalArgumentException(Messages.getString("awt.169")); //$NON-NLS-1$ + } + + return minValues[component]; + } + + /** + * Gets the maximum normalized color component value for the specified + * component. + * + * @param component + * the component to determine the maximum value. + * @return the maximum normalized value of the component. + */ + @Override + public float getMaxValue(int component) { + if ((component < 0) || (component > this.getNumComponents() - 1)) { + // awt.169=Component index out of range + throw new IllegalArgumentException(Messages.getString("awt.169")); //$NON-NLS-1$ + } + + return maxValues[component]; + } + + /** + * Fill min max values. + */ + private void fillMinMaxValues() { + int n = getNumComponents(); + maxValues = new float[n]; + minValues = new float[n]; + switch (getType()) { + case ColorSpace.TYPE_XYZ: + minValues[0] = 0; + minValues[1] = 0; + minValues[2] = 0; + maxValues[0] = MAX_XYZ; + maxValues[1] = MAX_XYZ; + maxValues[2] = MAX_XYZ; + break; + case ColorSpace.TYPE_Lab: + minValues[0] = 0; + minValues[1] = -128; + minValues[2] = -128; + maxValues[0] = 100; + maxValues[1] = 127; + maxValues[2] = 127; + break; + default: + for(int i=0; i<n; i++) { + minValues[i] = 0; + maxValues[i] = 1; + } + } + } + + /** + * Write object. + * + * @param out + * the out + * @throws IOException + * Signals that an I/O exception has occurred. + */ + private void writeObject(ObjectOutputStream out) throws IOException { + ObjectOutputStream.PutField fields = out.putFields(); + + fields.put("thisProfile", profile); //$NON-NLS-1$ + fields.put("minVal", null); //$NON-NLS-1$ + fields.put("maxVal", null); //$NON-NLS-1$ + fields.put("diffMinMax", null); //$NON-NLS-1$ + fields.put("invDiffMinMax", null); //$NON-NLS-1$ + fields.put("needScaleInit", true); //$NON-NLS-1$ + + out.writeFields(); + } + + /** + * Read object. + * + * @param in + * the in + * @throws IOException + * Signals that an I/O exception has occurred. + * @throws ClassNotFoundException + * the class not found exception + */ + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + ObjectInputStream.GetField fields = in.readFields(); + resolvedDeserializedInst = + new ICC_ColorSpace((ICC_Profile) fields.get("thisProfile", null)); //$NON-NLS-1$ + } + + /** + * Read resolve. + * + * @return the object + * @throws ObjectStreamException + * the object stream exception + */ + Object readResolve() throws ObjectStreamException { + return resolvedDeserializedInst; + } +} + diff --git a/awt/java/awt/color/ICC_Profile.java b/awt/java/awt/color/ICC_Profile.java new file mode 100644 index 0000000..8ffee6c --- /dev/null +++ b/awt/java/awt/color/ICC_Profile.java @@ -0,0 +1,1477 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt.color; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; +import java.io.OutputStream; +import java.io.Serializable; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.StringTokenizer; + +import org.apache.harmony.awt.gl.color.ICC_ProfileHelper; +import org.apache.harmony.awt.gl.color.NativeCMM; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The ICC_Profile class represents a color profile data for color spaces based + * on the International Color Consortium Specification ICC.1:2001-12, File + * Format for Color Profiles. + * + * @since Android 1.0 + */ +public class ICC_Profile implements Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -3938515861990936766L; + + // NOTE: Constant field values are noted in 1.5 specification. + + /** + * The Constant CLASS_INPUT indicates that profile class is input. + */ + public static final int CLASS_INPUT = 0; + + /** + * The Constant CLASS_DISPLAY indicates that profile class is display. + */ + public static final int CLASS_DISPLAY = 1; + + /** + * The Constant CLASS_OUTPUT indicates that profile class is output. + */ + public static final int CLASS_OUTPUT = 2; + + /** + * The Constant CLASS_DEVICELINK indicates that profile class is device + * link. + */ + public static final int CLASS_DEVICELINK = 3; + + /** + * The Constant CLASS_COLORSPACECONVERSION indicates that profile class is + * color space conversion. + */ + public static final int CLASS_COLORSPACECONVERSION = 4; + + /** + * The Constant CLASS_ABSTRACT indicates that profile class is abstract. + */ + public static final int CLASS_ABSTRACT = 5; + + /** + * The Constant CLASS_NAMEDCOLOR indicates that profile class is named + * color. + */ + public static final int CLASS_NAMEDCOLOR = 6; + + /** + * The Constant icSigXYZData - ICC Profile Color Space Type Signature. + */ + public static final int icSigXYZData = 1482250784; + + /** + * The Constant icSigLabData - ICC Profile Color Space Type Signature. + */ + public static final int icSigLabData = 1281450528; + + /** + * The Constant icSigLuvData - ICC Profile Color Space Type Signature. + */ + public static final int icSigLuvData = 1282766368; + + /** + * The Constant icSigYCbCrData - ICC Profile Color Space Type Signature. + */ + public static final int icSigYCbCrData = 1497588338; + + /** + * The Constant icSigYxyData - ICC Profile Color Space Type Signature. + */ + public static final int icSigYxyData = 1501067552; + + /** + * The Constant icSigRgbData - ICC Profile Color Space Type Signature. + */ + public static final int icSigRgbData = 1380401696; + + /** + * The Constant icSigGrayData - ICC Profile Color Space Type Signature. + */ + public static final int icSigGrayData = 1196573017; + + /** + * The Constant icSigHsvData - ICC Profile Color Space Type Signature. + */ + public static final int icSigHsvData = 1213421088; + + /** + * The Constant icSigHlsData - ICC Profile Color Space Type Signature. + */ + public static final int icSigHlsData = 1212961568; + + /** + * The Constant icSigCmykData - ICC Profile Color Space Type Signature. + */ + public static final int icSigCmykData = 1129142603; + + /** + * The Constant icSigCmyData - ICC Profile Color Space Type Signature. + */ + public static final int icSigCmyData = 1129142560; + + /** + * The Constant icSigSpace2CLR - ICC Profile Color Space Type Signature. + */ + public static final int icSigSpace2CLR = 843271250; + + /** + * The Constant icSigSpace3CLR - ICC Profile Color Space Type Signature. + */ + public static final int icSigSpace3CLR = 860048466; + + /** + * The Constant icSigSpace4CLR - ICC Profile Color Space Type Signature. + */ + public static final int icSigSpace4CLR = 876825682; + + /** + * The Constant icSigSpace5CLR - ICC Profile Color Space Type Signature. + */ + public static final int icSigSpace5CLR = 893602898; + + /** + * The Constant icSigSpace6CLR - ICC Profile Color Space Type Signature. + */ + public static final int icSigSpace6CLR = 910380114; + + /** + * The Constant icSigSpace7CLR - ICC Profile Color Space Type Signature. + */ + public static final int icSigSpace7CLR = 927157330; + + /** + * The Constant icSigSpace8CLR - ICC Profile Color Space Type Signature. + */ + public static final int icSigSpace8CLR = 943934546; + + /** + * The Constant icSigSpace9CLR - ICC Profile Color Space Type Signature. + */ + public static final int icSigSpace9CLR = 960711762; + + /** + * The Constant icSigSpaceACLR - ICC Profile Color Space Type Signature. + */ + public static final int icSigSpaceACLR = 1094929490; + + /** + * The Constant icSigSpaceBCLR - ICC Profile Color Space Type Signature. + */ + public static final int icSigSpaceBCLR = 1111706706; + + /** + * The Constant icSigSpaceCCLR - ICC Profile Color Space Type Signature. + */ + public static final int icSigSpaceCCLR = 1128483922; + + /** + * The Constant icSigSpaceDCLR - ICC Profile Color Space Type Signature. + */ + public static final int icSigSpaceDCLR = 1145261138; + + /** + * The Constant icSigSpaceECLR - ICC Profile Color Space Type Signature. + */ + public static final int icSigSpaceECLR = 1162038354; + + /** + * The Constant icSigSpaceFCLR - ICC Profile Color Space Type Signature. + */ + public static final int icSigSpaceFCLR = 1178815570; + + /** + * The Constant icSigInputClass - ICC Profile Class Signature. + */ + public static final int icSigInputClass = 1935896178; + + /** + * The Constant icSigDisplayClass - ICC Profile Class Signature. + */ + public static final int icSigDisplayClass = 1835955314; + + /** + * The Constant icSigOutputClass - ICC Profile Class Signature. + */ + public static final int icSigOutputClass = 1886549106; + + /** + * The Constant icSigLinkClass - ICC Profile Class Signature. + */ + public static final int icSigLinkClass = 1818848875; + + /** + * The Constant icSigAbstractClass - ICC Profile Class Signature. + */ + public static final int icSigAbstractClass = 1633842036; + + /** + * The Constant icSigColorantOrderTag - ICC Profile Tag Signature. + */ + public static final int icSigColorantOrderTag = 1668051567; + + /** + * The Constant icSigColorantTableTag - ICC Profile Tag Signature. + */ + public static final int icSigColorantTableTag = 1668051572; + + /** + * The Constant icSigColorSpaceClass - ICC Profile Tag Signature. + */ + public static final int icSigColorSpaceClass = 1936744803; + + /** + * The Constant icSigNamedColorClass - ICC Profile Tag Signature. + */ + public static final int icSigNamedColorClass = 1852662636; + + /** + * The Constant icPerceptual - ICC Profile Rendering Intent. + */ + public static final int icPerceptual = 0; + + /** + * The Constant icRelativeColorimetric - ICC Profile Rendering Intent. + */ + public static final int icRelativeColorimetric = 1; + + /** + * The Constant icSaturation - ICC Profile Rendering Intent. + */ + public static final int icSaturation = 2; + + /** + * The Constant icAbsoluteColorimetric - ICC Profile Rendering Intent. + */ + public static final int icAbsoluteColorimetric = 3; + + /** + * The Constant icSigHead - ICC Profile Tag Signature. + */ + public static final int icSigHead = 1751474532; + + /** + * The Constant icSigAToB0Tag - ICC Profile Tag Signature. + */ + public static final int icSigAToB0Tag = 1093812784; + + /** + * The Constant icSigAToB1Tag - ICC Profile Tag Signature. + */ + public static final int icSigAToB1Tag = 1093812785; + + /** + * The Constant icSigAToB2Tag - ICC Profile Tag Signature. + */ + public static final int icSigAToB2Tag = 1093812786; + + /** + * The Constant icSigBlueColorantTag - ICC Profile Tag Signature. + */ + public static final int icSigBlueColorantTag = 1649957210; + + /** + * The Constant icSigBlueMatrixColumnTag - ICC Profile Tag Signature. + */ + public static final int icSigBlueMatrixColumnTag = 1649957210; + + /** + * The Constant icSigBlueTRCTag - ICC Profile Tag Signature. + */ + public static final int icSigBlueTRCTag = 1649693251; + + /** + * The Constant icSigBToA0Tag - ICC Profile Tag Signature. + */ + public static final int icSigBToA0Tag = 1110589744; + + /** + * The Constant icSigBToA1Tag - ICC Profile Tag Signature. + */ + public static final int icSigBToA1Tag = 1110589745; + + /** + * The Constant icSigBToA2Tag - ICC Profile Tag Signature. + */ + public static final int icSigBToA2Tag = 1110589746; + + /** + * The Constant icSigCalibrationDateTimeTag - ICC Profile Tag Signature. + */ + public static final int icSigCalibrationDateTimeTag = 1667329140; + + /** + * The Constant icSigCharTargetTag - ICC Profile Tag Signature. + */ + public static final int icSigCharTargetTag = 1952543335; + + /** + * The Constant icSigCopyrightTag - ICC Profile Tag Signature. + */ + public static final int icSigCopyrightTag = 1668313716; + + /** + * The Constant icSigCrdInfoTag - ICC Profile Tag Signature. + */ + public static final int icSigCrdInfoTag = 1668441193; + + /** + * The Constant icSigDeviceMfgDescTag - ICC Profile Tag Signature. + */ + public static final int icSigDeviceMfgDescTag = 1684893284; + + /** + * The Constant icSigDeviceModelDescTag - ICC Profile Tag Signature. + */ + public static final int icSigDeviceModelDescTag = 1684890724; + + /** + * The Constant icSigDeviceSettingsTag - ICC Profile Tag Signature. + */ + public static final int icSigDeviceSettingsTag = 1684371059; + + /** + * The Constant icSigGamutTag - ICC Profile Tag Signature. + */ + public static final int icSigGamutTag = 1734438260; + + /** + * The Constant icSigGrayTRCTag - ICC Profile Tag Signature. + */ + public static final int icSigGrayTRCTag = 1800688195; + + /** + * The Constant icSigGreenColorantTag - ICC Profile Tag Signature. + */ + public static final int icSigGreenColorantTag = 1733843290; + + /** + * The Constant icSigGreenMatrixColumnTag - ICC Profile Tag Signature. + */ + public static final int icSigGreenMatrixColumnTag = 1733843290; + + /** + * The Constant icSigGreenTRCTag - ICC Profile Tag Signature. + */ + public static final int icSigGreenTRCTag = 1733579331; + + /** + * The Constant icSigLuminanceTag - ICC Profile Tag Signature. + */ + public static final int icSigLuminanceTag = 1819635049; + + /** + * The Constant icSigMeasurementTag - ICC Profile Tag Signature. + */ + public static final int icSigMeasurementTag = 1835360627; + + /** + * The Constant icSigMediaBlackPointTag - ICC Profile Tag Signature. + */ + public static final int icSigMediaBlackPointTag = 1651208308; + + /** + * The Constant icSigMediaWhitePointTag - ICC Profile Tag Signature. + */ + public static final int icSigMediaWhitePointTag = 2004119668; + + /** + * The Constant icSigNamedColor2Tag - ICC Profile Tag Signature. + */ + public static final int icSigNamedColor2Tag = 1852009522; + + /** + * The Constant icSigOutputResponseTag - ICC Profile Tag Signature. + */ + public static final int icSigOutputResponseTag = 1919251312; + + /** + * The Constant icSigPreview0Tag - ICC Profile Tag Signature. + */ + public static final int icSigPreview0Tag = 1886545200; + + /** + * The Constant icSigPreview1Tag - ICC Profile Tag Signature. + */ + public static final int icSigPreview1Tag = 1886545201; + + /** + * The Constant icSigPreview2Tag - ICC Profile Tag Signature. + */ + public static final int icSigPreview2Tag = 1886545202; + + /** + * The Constant icSigProfileDescriptionTag - ICC Profile Tag Signature. + */ + public static final int icSigProfileDescriptionTag = 1684370275; + + /** + * The Constant icSigProfileSequenceDescTag - ICC Profile Tag Signature. + */ + public static final int icSigProfileSequenceDescTag = 1886610801; + + /** + * The Constant icSigPs2CRD0Tag - ICC Profile Tag Signature. + */ + public static final int icSigPs2CRD0Tag = 1886610480; + + /** + * The Constant icSigPs2CRD1Tag - ICC Profile Tag Signature. + */ + public static final int icSigPs2CRD1Tag = 1886610481; + + /** + * The Constant icSigPs2CRD2Tag - ICC Profile Tag Signature. + */ + public static final int icSigPs2CRD2Tag = 1886610482; + + /** + * The Constant icSigPs2CRD3Tag - ICC Profile Tag Signature. + */ + public static final int icSigPs2CRD3Tag = 1886610483; + + /** + * The Constant icSigPs2CSATag - ICC Profile Tag Signature. + */ + public static final int icSigPs2CSATag = 1886597747; + + /** + * The Constant icSigPs2RenderingIntentTag - ICC Profile Tag Signature. + */ + public static final int icSigPs2RenderingIntentTag = 1886597737; + + /** + * The Constant icSigRedColorantTag - ICC Profile Tag Signature. + */ + public static final int icSigRedColorantTag = 1918392666; + + /** + * The Constant icSigRedMatrixColumnTag - ICC Profile Tag Signature. + */ + public static final int icSigRedMatrixColumnTag = 1918392666; + + /** + * The Constant icSigRedTRCTag - ICC Profile Tag Signature. + */ + public static final int icSigRedTRCTag = 1918128707; + + /** + * The Constant icSigScreeningDescTag - ICC Profile Tag Signature. + */ + public static final int icSigScreeningDescTag = 1935897188; + + /** + * The Constant icSigScreeningTag - ICC Profile Tag Signature. + */ + public static final int icSigScreeningTag = 1935897198; + + /** + * The Constant icSigTechnologyTag - ICC Profile Tag Signature. + */ + public static final int icSigTechnologyTag = 1952801640; + + /** + * The Constant icSigUcrBgTag - ICC Profile Tag Signature. + */ + public static final int icSigUcrBgTag = 1650877472; + + /** + * The Constant icSigViewingCondDescTag - ICC Profile Tag Signature. + */ + public static final int icSigViewingCondDescTag = 1987405156; + + /** + * The Constant icSigViewingConditionsTag - ICC Profile Tag Signature. + */ + public static final int icSigViewingConditionsTag = 1986618743; + + /** + * The Constant icSigChromaticAdaptationTag - ICC Profile Tag Signature. + */ + public static final int icSigChromaticAdaptationTag = 1667785060; + + /** + * The Constant icSigChromaticityTag - ICC Profile Tag Signature. + */ + public static final int icSigChromaticityTag = 1667789421; + + /** + * The Constant icHdrSize - ICC Profile Header Location. + */ + public static final int icHdrSize = 0; + + /** + * The Constant icHdrCmmId - ICC Profile Header Location. + */ + public static final int icHdrCmmId = 4; + + /** + * The Constant icHdrVersion - ICC Profile Header Location. + */ + public static final int icHdrVersion = 8; + + /** + * The Constant icHdrDeviceClass - ICC Profile Header Location. + */ + public static final int icHdrDeviceClass = 12; + + /** + * The Constant icHdrColorSpace - ICC Profile Header Location. + */ + public static final int icHdrColorSpace = 16; + + /** + * The Constant icHdrPcs - ICC Profile Header Location. + */ + public static final int icHdrPcs = 20; + + /** + * The Constant icHdrDate - ICC Profile Header Location. + */ + public static final int icHdrDate = 24; + + /** + * The Constant icHdrMagic - ICC Profile Header Location. + */ + public static final int icHdrMagic = 36; + + /** + * The Constant icHdrPlatform - ICC Profile Header Location. + */ + public static final int icHdrPlatform = 40; + + /** + * The Constant icHdrProfileID - ICC Profile Header Location. + */ + public static final int icHdrProfileID = 84; + + /** + * The Constant icHdrFlags - ICC Profile Header Location. + */ + public static final int icHdrFlags = 44; + + /** + * The Constant icHdrManufacturer - ICC Profile Header Location. + */ + public static final int icHdrManufacturer = 48; + + /** + * The Constant icHdrModel - ICC Profile Header Location. + */ + public static final int icHdrModel = 52; + + /** + * The Constant icHdrAttributes - ICC Profile Header Location. + */ + public static final int icHdrAttributes = 56; + + /** + * The Constant icHdrRenderingIntent - ICC Profile Header Location. + */ + public static final int icHdrRenderingIntent = 64; + + /** + * The Constant icHdrIlluminant - ICC Profile Header Location. + */ + public static final int icHdrIlluminant = 68; + + /** + * The Constant icHdrCreator - ICC Profile Header Location. + */ + public static final int icHdrCreator = 80; + + /** + * The Constant icICCAbsoluteColorimetric - ICC Profile Rendering Intent. + */ + public static final int icICCAbsoluteColorimetric = 3; + + /** + * The Constant icMediaRelativeColorimetric - ICC Profile Rendering Intent. + */ + public static final int icMediaRelativeColorimetric = 1; + + /** + * The Constant icTagType - ICC Profile Constant. + */ + public static final int icTagType = 0; + + /** + * The Constant icTagReserved - ICC Profile Constant. + */ + public static final int icTagReserved = 4; + + /** + * The Constant icCurveCount - ICC Profile Constant. + */ + public static final int icCurveCount = 8; + + /** + * The Constant icCurveData - ICC Profile Constant. + */ + public static final int icCurveData = 12; + + /** + * The Constant icXYZNumberX - ICC Profile Constant. + */ + public static final int icXYZNumberX = 8; + + /** + * Size of a profile header. + */ + private static final int headerSize = 128; + + /** + * header magic number. + */ + private static final int headerMagicNumber = 0x61637370; + + // Cache of predefined profiles + /** + * The s rgb profile. + */ + private static ICC_Profile sRGBProfile; + + /** + * The xyz profile. + */ + private static ICC_Profile xyzProfile; + + /** + * The gray profile. + */ + private static ICC_Profile grayProfile; + + /** + * The pycc profile. + */ + private static ICC_Profile pyccProfile; + + /** + * The linear rgb profile. + */ + private static ICC_Profile linearRGBProfile; + + /** + * Handle to the current profile. + */ + private transient long profileHandle = 0; + + /** + * If handle is used by another class this object is not responsible for + * closing profile. + */ + private transient boolean handleStolen = false; + + /** + * Cached header data. + */ + private transient byte[] headerData = null; + + /** + * Serialization support. + */ + private transient ICC_Profile openedProfileObject; + + /** + * Instantiates a new ICC profile with the given data. + * + * @param data + * the data. + */ + private ICC_Profile(byte[] data) { + profileHandle = NativeCMM.cmmOpenProfile(data); + NativeCMM.addHandle(this, profileHandle); + } + + /** + * Used to instantiate dummy ICC_ProfileStub objects. + */ + ICC_Profile() { + } + + /** + * Used to instantiate subclasses (ICC_ProfileGrey and ICC_ProfileRGB). + * + * @param profileHandle + * - should be valid handle to opened color profile + */ + ICC_Profile(long profileHandle) { + this.profileHandle = profileHandle; + // A new object reference, need to add it. + NativeCMM.addHandle(this, profileHandle); + } + + /** + * Writes the ICC_Profile to a file with the specified name. + * + * @param fileName + * the file name. + * @throws IOException + * if an I/O exception has occurred during writing or opening + * the file. + */ + public void write(String fileName) throws IOException { + FileOutputStream oStream = new FileOutputStream(fileName); + oStream.write(getData()); + oStream.close(); + } + + /** + * Serializable implementation. + * + * @param s + * the s + * @throws IOException + * Signals that an I/O exception has occurred. + */ + private void writeObject(ObjectOutputStream s) throws IOException { + s.defaultWriteObject(); + s.writeObject(null); + s.writeObject(getData()); + } + + /** + * Serializable implementation. + * + * @param s + * the s + * @throws IOException + * Signals that an I/O exception has occurred. + * @throws ClassNotFoundException + * the class not found exception + */ + private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { + s.defaultReadObject(); + String colorSpaceStr = (String)s.readObject(); + byte[] data = (byte[])s.readObject(); + + if (colorSpaceStr != null) { + if (colorSpaceStr.equals("CS_sRGB")) { //$NON-NLS-1$ + openedProfileObject = getInstance(ColorSpace.CS_sRGB); + } else if (colorSpaceStr.equals("CS_GRAY")) { //$NON-NLS-1$ + openedProfileObject = getInstance(ColorSpace.CS_GRAY); + } else if (colorSpaceStr.equals("CS_LINEAR_RGB")) { //$NON-NLS-1$ + openedProfileObject = getInstance(ColorSpace.CS_LINEAR_RGB); + } else if (colorSpaceStr.equals("CS_CIEXYZ")) { //$NON-NLS-1$ + openedProfileObject = getInstance(ColorSpace.CS_CIEXYZ); + } else if (colorSpaceStr.equals("CS_PYCC")) { //$NON-NLS-1$ + openedProfileObject = getInstance(ColorSpace.CS_PYCC); + } else { + openedProfileObject = ICC_Profile.getInstance(data); + } + } else { + openedProfileObject = ICC_Profile.getInstance(data); + } + } + + /** + * Resolves instances being deserialized into instances registered with CMM. + * + * @return ICC_Profile object for profile registered with CMM. + * @throws ObjectStreamException + * if there is an error in the serialized files or during the + * process of reading them. + */ + protected Object readResolve() throws ObjectStreamException { + return openedProfileObject; + } + + /** + * Writes the ICC_Profile to an OutputStream. + * + * @param s + * the OutputStream. + * @throws IOException + * signals that an I/O exception has occurred during writing or + * opening OutputStream. + */ + public void write(OutputStream s) throws IOException { + s.write(getData()); + } + + /** + * Sets a tagged data element in the profile from a byte array. + * + * @param tagSignature + * the ICC tag signature for the data element to be set. + * @param tagData + * the data to be set for the specified tag signature. + */ + public void setData(int tagSignature, byte[] tagData) { + NativeCMM.cmmSetProfileElement(profileHandle, tagSignature, tagData); + // Remove cached header data if header is modified + if (tagSignature == icSigHead) { + headerData = null; + } + } + + /** + * Gets a tagged data element from the profile as a byte array. Elements are + * identified by tag signatures as defined in the ICC specification. + * + * @param tagSignature + * the ICC tag signature for the data element to get. + * @return a byte array that contains the tagged data element. + */ + public byte[] getData(int tagSignature) { + int tagSize = 0; + try { + tagSize = NativeCMM.cmmGetProfileElementSize(profileHandle, tagSignature); + } catch (CMMException e) { + // We'll get this exception if there's no element with + // the specified tag signature + return null; + } + + byte[] data = new byte[tagSize]; + NativeCMM.cmmGetProfileElement(profileHandle, tagSignature, data); + return data; + } + + /** + * Gets a data byte array of this ICC_Profile. + * + * @return a byte array that contains the ICC Profile data. + */ + public byte[] getData() { + int profileSize = NativeCMM.cmmGetProfileSize(profileHandle); + byte[] data = new byte[profileSize]; + NativeCMM.cmmGetProfile(profileHandle, data); + return data; + } + + /** + * Frees the resources associated with an ICC_Profile object. + */ + @Override + protected void finalize() { + if (profileHandle != 0 && !handleStolen) { + NativeCMM.cmmCloseProfile(profileHandle); + } + + // Always remove because key no more exist + // when object is destroyed + NativeCMM.removeHandle(this); + } + + /** + * Gets the profile class. + * + * @return the profile class constant. + */ + public int getProfileClass() { + int deviceClassSignature = getIntFromHeader(icHdrDeviceClass); + + switch (deviceClassSignature) { + case icSigColorSpaceClass: + return CLASS_COLORSPACECONVERSION; + case icSigDisplayClass: + return CLASS_DISPLAY; + case icSigOutputClass: + return CLASS_OUTPUT; + case icSigInputClass: + return CLASS_INPUT; + case icSigLinkClass: + return CLASS_DEVICELINK; + case icSigAbstractClass: + return CLASS_ABSTRACT; + case icSigNamedColorClass: + return CLASS_NAMEDCOLOR; + default: + } + + // Not an ICC profile class + // awt.15F=Profile class does not comply with ICC specification + throw new IllegalArgumentException(Messages.getString("awt.15F")); //$NON-NLS-1$ + + } + + /** + * Gets the color space type of the Profile Connection Space (PCS). + * + * @return the PCS type. + */ + public int getPCSType() { + return csFromSignature(getIntFromHeader(icHdrPcs)); + } + + /** + * Gets the number of components of this ICC Profile. + * + * @return the number of components of this ICC Profile. + */ + public int getNumComponents() { + switch (getIntFromHeader(icHdrColorSpace)) { + // The most common cases go first to increase speed + case icSigRgbData: + case icSigXYZData: + case icSigLabData: + return 3; + case icSigCmykData: + return 4; + // Then all other + case icSigGrayData: + return 1; + case icSigSpace2CLR: + return 2; + case icSigYCbCrData: + case icSigLuvData: + case icSigYxyData: + case icSigHlsData: + case icSigHsvData: + case icSigCmyData: + case icSigSpace3CLR: + return 3; + case icSigSpace4CLR: + return 4; + case icSigSpace5CLR: + return 5; + case icSigSpace6CLR: + return 6; + case icSigSpace7CLR: + return 7; + case icSigSpace8CLR: + return 8; + case icSigSpace9CLR: + return 9; + case icSigSpaceACLR: + return 10; + case icSigSpaceBCLR: + return 11; + case icSigSpaceCCLR: + return 12; + case icSigSpaceDCLR: + return 13; + case icSigSpaceECLR: + return 14; + case icSigSpaceFCLR: + return 15; + default: + } + + // awt.160=Color space doesn't comply with ICC specification + throw new ProfileDataException(Messages.getString("awt.160") //$NON-NLS-1$ + ); + } + + /** + * Gets the minor version of this ICC profile. + * + * @return the minor version of this ICC profile. + */ + public int getMinorVersion() { + return getByteFromHeader(icHdrVersion + 1); + } + + /** + * Gets the major version of this ICC profile. + * + * @return the major version of this ICC profile. + */ + public int getMajorVersion() { + return getByteFromHeader(icHdrVersion); + } + + /** + * Gets the color space type of this ICC_Profile. + * + * @return the color space type. + */ + public int getColorSpaceType() { + return csFromSignature(getIntFromHeader(icHdrColorSpace)); + } + + /** + * Tries to open the file at the specified path. Path entries can be divided + * by a separator character. + * + * @param path + * the path to the file. + * @param fileName + * the file name. + * @return the input stream to read the file. + */ + private static FileInputStream tryPath(String path, String fileName) { + FileInputStream fiStream = null; + + if (path == null) { + return null; + } + + StringTokenizer st = new StringTokenizer(path, File.pathSeparator); + + while (st.hasMoreTokens()) { + String pathEntry = st.nextToken(); + try { + fiStream = new FileInputStream(pathEntry + File.separatorChar + fileName); + if (fiStream != null) { + return fiStream; + } + } catch (FileNotFoundException e) { + } + } + + return fiStream; + } + + /** + * Gets the single instance of ICC_Profile from data in the specified file. + * + * @param fileName + * the specified name of file with ICC profile data. + * @return single instance of ICC_Profile. + * @throws IOException + * signals that an I/O error occurred while reading the file or + * the file does not exist. + */ + public static ICC_Profile getInstance(String fileName) throws IOException { + final String fName = fileName; // to use in the privileged block + + FileInputStream fiStream = (FileInputStream)AccessController + .doPrivileged(new PrivilegedAction<FileInputStream>() { + public FileInputStream run() { + FileInputStream fiStream = null; + + // Open absolute path + try { + fiStream = new FileInputStream(fName); + if (fiStream != null) { + return fiStream; + } + } catch (FileNotFoundException e) { + } + + // Check java.iccprofile.path entries + fiStream = tryPath(System.getProperty("java.iccprofile.path"), fName); //$NON-NLS-1$ + if (fiStream != null) { + return fiStream; + } + + // Check java.class.path entries + fiStream = tryPath(System.getProperty("java.class.path"), fName); //$NON-NLS-1$ + if (fiStream != null) { + return fiStream; + } + + // Check directory with java sample profiles + String home = System.getProperty("java.home"); //$NON-NLS-1$ + if (home != null) { + fiStream = tryPath(home + File.separatorChar + + "lib" + File.separatorChar + "cmm", fName //$NON-NLS-1$ //$NON-NLS-2$ + ); + } + + return fiStream; + } + }); + + if (fiStream == null) { + // awt.161=Unable to open file {0} + throw new IOException(Messages.getString("awt.161", fileName)); //$NON-NLS-1$ + } + + ICC_Profile pf = getInstance(fiStream); + fiStream.close(); + return pf; + } + + /** + * Gets the single instance of ICC_Profile with data in the specified + * InputStream. + * + * @param s + * the InputStream with ICC profile data. + * @return single instance of ICC_Profile. + * @throws IOException + * if an I/O exception has occurred during reading from + * InputStream. + * @throws IllegalArgumentException + * if the file does not contain valid ICC Profile data. + */ + public static ICC_Profile getInstance(InputStream s) throws IOException { + byte[] header = new byte[headerSize]; + // awt.162=Invalid ICC Profile Data + String invalidDataMessage = Messages.getString("awt.162"); //$NON-NLS-1$ + + // Get header from the input stream + if (s.read(header) != headerSize) { + throw new IllegalArgumentException(invalidDataMessage); + } + + // Check the profile data for consistency + if (ICC_ProfileHelper.getBigEndianFromByteArray(header, icHdrMagic) != headerMagicNumber) { + throw new IllegalArgumentException(invalidDataMessage); + } + + // Get profile size from header, create an array for profile data + int profileSize = ICC_ProfileHelper.getBigEndianFromByteArray(header, icHdrSize); + byte[] profileData = new byte[profileSize]; + + // Copy header into it + System.arraycopy(header, 0, profileData, 0, headerSize); + + // Read the profile itself + if (s.read(profileData, headerSize, profileSize - headerSize) != profileSize - headerSize) { + throw new IllegalArgumentException(invalidDataMessage); + } + + return getInstance(profileData); + } + + /** + * Gets the single instance of ICC_Profile from the specified data in a byte + * array. + * + * @param data + * the byte array of ICC profile. + * @return single instance of ICC_Profile from the specified data in a byte + * array. + * @throws IllegalArgumentException + * if the file does not contain valid ICC Profile data. + */ + public static ICC_Profile getInstance(byte[] data) { + ICC_Profile res = null; + + try { + res = new ICC_Profile(data); + } catch (CMMException e) { + // awt.162=Invalid ICC Profile Data + throw new IllegalArgumentException(Messages.getString("awt.162")); //$NON-NLS-1$ + } + + if (System.getProperty("os.name").toLowerCase().indexOf("windows") >= 0) { //$NON-NLS-1$ //$NON-NLS-2$ + try { + if (res.getColorSpaceType() == ColorSpace.TYPE_RGB + && res.getDataSize(icSigMediaWhitePointTag) > 0 + && res.getDataSize(icSigRedColorantTag) > 0 + && res.getDataSize(icSigGreenColorantTag) > 0 + && res.getDataSize(icSigBlueColorantTag) > 0 + && res.getDataSize(icSigRedTRCTag) > 0 + && res.getDataSize(icSigGreenTRCTag) > 0 + && res.getDataSize(icSigBlueTRCTag) > 0) { + res = new ICC_ProfileRGB(res.getProfileHandle()); + } else if (res.getColorSpaceType() == ColorSpace.TYPE_GRAY + && res.getDataSize(icSigMediaWhitePointTag) > 0 + && res.getDataSize(icSigGrayTRCTag) > 0) { + res = new ICC_ProfileGray(res.getProfileHandle()); + } + + } catch (CMMException e) { /* return res in this case */ + } + } + + return res; + } + + /** + * Gets the single instance of ICC_Profile with the specific color space + * defined by the ColorSpace class: CS_sRGB, CS_LINEAR_RGB, CS_CIEXYZ, + * CS_PYCC, CS_GRAY. + * + * @param cspace + * the type of color space defined in the ColorSpace class. + * @return single instance of ICC_Profile. + * @throws IllegalArgumentException + * is not one of the defined color space types. + */ + public static ICC_Profile getInstance(int cspace) { + try { + switch (cspace) { + + case ColorSpace.CS_sRGB: + if (sRGBProfile == null) { + sRGBProfile = getInstance("sRGB.pf"); //$NON-NLS-1$ + } + return sRGBProfile; + + case ColorSpace.CS_CIEXYZ: + if (xyzProfile == null) { + xyzProfile = getInstance("CIEXYZ.pf"); //$NON-NLS-1$ + } + return xyzProfile; + + case ColorSpace.CS_GRAY: + if (grayProfile == null) { + grayProfile = getInstance("GRAY.pf"); //$NON-NLS-1$ + } + return grayProfile; + + case ColorSpace.CS_PYCC: + if (pyccProfile == null) { + pyccProfile = getInstance("PYCC.pf"); //$NON-NLS-1$ + } + return pyccProfile; + + case ColorSpace.CS_LINEAR_RGB: + if (linearRGBProfile == null) { + linearRGBProfile = getInstance("LINEAR_RGB.pf"); //$NON-NLS-1$ + } + return linearRGBProfile; + } + + } catch (IOException e) { + // awt.163=Can't open color profile + throw new IllegalArgumentException(Messages.getString("Can't open color profile")); //$NON-NLS-1$ + } + + // awt.164=Not a predefined color space + throw new IllegalArgumentException(Messages.getString("Not a predefined color space")); //$NON-NLS-1$ + } + + /** + * Reads an integer from the profile header at the specified position. + * + * @param idx + * - offset in bytes from the beginning of the header + * @return the integer value from header + */ + private int getIntFromHeader(int idx) { + if (headerData == null) { + headerData = getData(icSigHead); + } + + return ((headerData[idx] & 0xFF) << 24) | ((headerData[idx + 1] & 0xFF) << 16) + | ((headerData[idx + 2] & 0xFF) << 8) | ((headerData[idx + 3] & 0xFF)); + } + + /** + * Reads byte from the profile header at the specified position. + * + * @param idx + * - offset in bytes from the beginning of the header + * @return the byte from header + */ + private byte getByteFromHeader(int idx) { + if (headerData == null) { + headerData = getData(icSigHead); + } + + return headerData[idx]; + } + + /** + * Converts ICC color space signature to the java predefined color space + * type. + * + * @param signature + * the signature + * @return the int + */ + private int csFromSignature(int signature) { + switch (signature) { + case icSigRgbData: + return ColorSpace.TYPE_RGB; + case icSigXYZData: + return ColorSpace.TYPE_XYZ; + case icSigCmykData: + return ColorSpace.TYPE_CMYK; + case icSigLabData: + return ColorSpace.TYPE_Lab; + case icSigGrayData: + return ColorSpace.TYPE_GRAY; + case icSigHlsData: + return ColorSpace.TYPE_HLS; + case icSigLuvData: + return ColorSpace.TYPE_Luv; + case icSigYCbCrData: + return ColorSpace.TYPE_YCbCr; + case icSigYxyData: + return ColorSpace.TYPE_Yxy; + case icSigHsvData: + return ColorSpace.TYPE_HSV; + case icSigCmyData: + return ColorSpace.TYPE_CMY; + case icSigSpace2CLR: + return ColorSpace.TYPE_2CLR; + case icSigSpace3CLR: + return ColorSpace.TYPE_3CLR; + case icSigSpace4CLR: + return ColorSpace.TYPE_4CLR; + case icSigSpace5CLR: + return ColorSpace.TYPE_5CLR; + case icSigSpace6CLR: + return ColorSpace.TYPE_6CLR; + case icSigSpace7CLR: + return ColorSpace.TYPE_7CLR; + case icSigSpace8CLR: + return ColorSpace.TYPE_8CLR; + case icSigSpace9CLR: + return ColorSpace.TYPE_9CLR; + case icSigSpaceACLR: + return ColorSpace.TYPE_ACLR; + case icSigSpaceBCLR: + return ColorSpace.TYPE_BCLR; + case icSigSpaceCCLR: + return ColorSpace.TYPE_CCLR; + case icSigSpaceDCLR: + return ColorSpace.TYPE_DCLR; + case icSigSpaceECLR: + return ColorSpace.TYPE_ECLR; + case icSigSpaceFCLR: + return ColorSpace.TYPE_FCLR; + default: + } + + // awt.165=Color space doesn't comply with ICC specification + throw new IllegalArgumentException(Messages.getString("awt.165")); //$NON-NLS-1$ + } + + /** + * Gets the profile handle. + * + * @return the profile handle + */ + private long getProfileHandle() { + handleStolen = true; + return profileHandle; + } + + /** + * Gets the data size. + * + * @param tagSignature + * the tag signature + * @return the data size + */ + private int getDataSize(int tagSignature) { + return NativeCMM.cmmGetProfileElementSize(profileHandle, tagSignature); + } + + /** + * Reads XYZ value from the tag data. + * + * @param tagSignature + * the tag signature + * @return the XYZ value + */ + float[] getXYZValue(int tagSignature) { + float[] res = new float[3]; + byte[] data = getData(tagSignature); + + // Convert from ICC s15Fixed16Number type + // 1 (float) = 0x10000 (s15Fixed16Number), + // hence dividing by 0x10000 + res[0] = ICC_ProfileHelper.getIntFromByteArray(data, 0) / 65536.f; + res[1] = ICC_ProfileHelper.getIntFromByteArray(data, 4) / 65536.f; + res[2] = ICC_ProfileHelper.getIntFromByteArray(data, 8) / 65536.f; + + return res; + } + + /** + * Gets the media white point. + * + * @return the media white point. + */ + float[] getMediaWhitePoint() { + return getXYZValue(icSigMediaWhitePointTag); + } + + /** + * If TRC is not a table returns gamma via return value and sets dataTRC to + * null. If TRC is a table returns 0 and fills dataTRC with values. + * + * @param tagSignature + * the tag signature + * @param dataTRC + * the data trc + * @return - gamma or zero if TRC is a table + */ + private float getGammaOrTRC(int tagSignature, short[] dataTRC) { + byte[] data = getData(tagSignature); + int trcSize = ICC_ProfileHelper.getIntFromByteArray(data, icCurveCount); + + dataTRC = null; + + if (trcSize == 0) { + return 1.0f; + } + + if (trcSize == 1) { + // Cast from ICC u8Fixed8Number to float + return ICC_ProfileHelper.getShortFromByteArray(data, icCurveData) / 256.f; + } + + // TRC is a table + dataTRC = new short[trcSize]; + for (int i = 0, pos = icCurveData; i < trcSize; i++, pos += 2) { + dataTRC[i] = ICC_ProfileHelper.getShortFromByteArray(data, pos); + } + return 0; + } + + /** + * Gets the gamma. + * + * @param tagSignature + * the tag signature + * @return the gamma + */ + float getGamma(int tagSignature) { + short[] dataTRC = null; + float gamma = getGammaOrTRC(tagSignature, dataTRC); + + if (dataTRC == null) { + return gamma; + } + // awt.166=TRC is not a simple gamma value. + throw new ProfileDataException(Messages.getString("awt.166")); //$NON-NLS-1$ + } + + /** + * Gets the TRC. + * + * @param tagSignature + * the tag signature + * @return the tRC + */ + short[] getTRC(int tagSignature) { + short[] dataTRC = null; + getGammaOrTRC(tagSignature, dataTRC); + + if (dataTRC == null) { + // awt.167=TRC is a gamma value, not a table. + throw new ProfileDataException(Messages.getString("awt.167")); //$NON-NLS-1$ + } + return dataTRC; + } +} diff --git a/awt/java/awt/color/ICC_ProfileGray.java b/awt/java/awt/color/ICC_ProfileGray.java new file mode 100644 index 0000000..f748101 --- /dev/null +++ b/awt/java/awt/color/ICC_ProfileGray.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +package java.awt.color; + +/** + * The ICC_ProfileGray class represent profiles with TYPE_GRAY color space type, + * and includes the grayTRCTag and mediaWhitePointTag tags. The gray component + * can be transformed from a GRAY device profile color space to the CIEXYZ + * Profile through the tone reproduction curve (TRC): + * <p> + * PCSY = grayTRC[deviceGray] + * + * @since Android 1.0 + */ +public class ICC_ProfileGray extends ICC_Profile { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -1124721290732002649L; + + /** + * Instantiates a new iC c_ profile gray. + * + * @param profileHandle + * the profile handle + */ + ICC_ProfileGray(long profileHandle) { + super(profileHandle); + } + + /** + * Gets the TRC as an array of shorts. + * + * @return the short array of the TRC. + */ + public short[] getTRC() { + return super.getTRC(icSigGrayTRCTag); + } + + /** + * Gets the media white point. + * + * @return the media white point + */ + @Override + public float[] getMediaWhitePoint() { + return super.getMediaWhitePoint(); + } + + /** + * Gets a gamma value representing the tone reproduction curve (TRC). + * + * @return the gamma value representing the tone reproduction curve (TRC). + */ + public float getGamma() { + return super.getGamma(icSigGrayTRCTag); + } +} + diff --git a/awt/java/awt/color/ICC_ProfileRGB.java b/awt/java/awt/color/ICC_ProfileRGB.java new file mode 100644 index 0000000..9c6010f --- /dev/null +++ b/awt/java/awt/color/ICC_ProfileRGB.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +package java.awt.color; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The ICC_ProfileRGB class represents profiles with RGB color space type and + * contains the redColorantTag, greenColorantTag, blueColorantTag, redTRCTag, + * greenTRCTag, blueTRCTag, and mediaWhitePointTag tags. + * + * @since Android 1.0 + */ +public class ICC_ProfileRGB extends ICC_Profile { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 8505067385152579334L; + + /** + * Instantiates a new RGB ICC_Profile. + * + * @param profileHandle + * the profile handle + */ + ICC_ProfileRGB(long profileHandle) { + super(profileHandle); + } + + /** + * The Constant REDCOMPONENT indicates the red component. + */ + public static final int REDCOMPONENT = 0; + + /** + * The Constant GREENCOMPONENT indicates the green component. + */ + public static final int GREENCOMPONENT = 1; + + /** + * The Constant BLUECOMPONENT indicates the blue component. + */ + public static final int BLUECOMPONENT = 2; + + // awt.15E=Unknown component. Must be REDCOMPONENT, GREENCOMPONENT or BLUECOMPONENT. + /** + * The Constant UNKNOWN_COMPONENT_MSG. + */ + private static final String UNKNOWN_COMPONENT_MSG = Messages + .getString("awt.15E"); //$NON-NLS-1$ + + /** + * Gets the TRC. + * + * @param component + * the tag signature. + * @return the TRC value. + */ + @Override + public short[] getTRC(int component) { + switch (component) { + case REDCOMPONENT: + return super.getTRC(icSigRedTRCTag); + case GREENCOMPONENT: + return super.getTRC(icSigGreenTRCTag); + case BLUECOMPONENT: + return super.getTRC(icSigBlueTRCTag); + default: + } + + throw new IllegalArgumentException(UNKNOWN_COMPONENT_MSG); + } + + /** + * Gets the gamma. + * + * @param component + * the tag signature. + * @return the gamma value. + */ + @Override + public float getGamma(int component) { + switch (component) { + case REDCOMPONENT: + return super.getGamma(icSigRedTRCTag); + case GREENCOMPONENT: + return super.getGamma(icSigGreenTRCTag); + case BLUECOMPONENT: + return super.getGamma(icSigBlueTRCTag); + default: + } + + throw new IllegalArgumentException(UNKNOWN_COMPONENT_MSG); + } + + /** + * Gets a float matrix which contains the X, Y, and Z components of the + * profile's redColorantTag, greenColorantTag, and blueColorantTag. + * + * @return the float matrix which contains the X, Y, and Z components of the + * profile's redColorantTag, greenColorantTag, and blueColorantTag. + */ + public float[][] getMatrix() { + float [][] m = new float[3][3]; // The matrix + + float[] redXYZ = getXYZValue(icSigRedColorantTag); + float[] greenXYZ = getXYZValue(icSigGreenColorantTag); + float[] blueXYZ = getXYZValue(icSigBlueColorantTag); + + m[0][0] = redXYZ[0]; + m[1][0] = redXYZ[1]; + m[2][0] = redXYZ[2]; + + m[0][1] = greenXYZ[0]; + m[1][1] = greenXYZ[1]; + m[2][1] = greenXYZ[2]; + + m[0][2] = blueXYZ[0]; + m[1][2] = blueXYZ[1]; + m[2][2] = blueXYZ[2]; + + return m; + } + + /** + * Gets the media white point. + * + * @return the media white point. + */ + @Override + public float[] getMediaWhitePoint() { + return super.getMediaWhitePoint(); + } +} + diff --git a/awt/java/awt/color/ICC_ProfileStub.java b/awt/java/awt/color/ICC_ProfileStub.java new file mode 100644 index 0000000..bc04c8a --- /dev/null +++ b/awt/java/awt/color/ICC_ProfileStub.java @@ -0,0 +1,173 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt.color; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectStreamException; +import java.io.OutputStream; + +import org.apache.harmony.awt.internal.nls.Messages; + +final class ICC_ProfileStub extends ICC_Profile { + private static final long serialVersionUID = 501389760875253507L; + + transient int colorspace; + + public ICC_ProfileStub(int csSpecifier) { + switch (csSpecifier) { + case ColorSpace.CS_sRGB: + case ColorSpace.CS_CIEXYZ: + case ColorSpace.CS_LINEAR_RGB: + case ColorSpace.CS_PYCC: + case ColorSpace.CS_GRAY: + break; + default: + // awt.15D=Invalid colorspace + throw new IllegalArgumentException(Messages.getString("awt.15D")); //$NON-NLS-1$ + } + colorspace = csSpecifier; + } + + @Override + public void write(String fileName) throws IOException { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + /** + * Serializable implementation + * + * @throws ObjectStreamException + */ + private Object writeReplace() throws ObjectStreamException { + return loadProfile(); + } + + @Override + public void write(OutputStream s) throws IOException { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + @Override + public void setData(int tagSignature, byte[] tagData) { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + @Override + public byte[] getData(int tagSignature) { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + @Override + public byte[] getData() { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + @Override + protected void finalize() { + } + + @Override + public int getProfileClass() { + return CLASS_COLORSPACECONVERSION; + } + + @Override + public int getPCSType() { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + @Override + public int getNumComponents() { + switch (colorspace) { + case ColorSpace.CS_sRGB: + case ColorSpace.CS_CIEXYZ: + case ColorSpace.CS_LINEAR_RGB: + case ColorSpace.CS_PYCC: + return 3; + case ColorSpace.CS_GRAY: + return 1; + default: + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + } + + @Override + public int getMinorVersion() { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + @Override + public int getMajorVersion() { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + @Override + public int getColorSpaceType() { + switch (colorspace) { + case ColorSpace.CS_sRGB: + case ColorSpace.CS_LINEAR_RGB: + return ColorSpace.TYPE_RGB; + case ColorSpace.CS_CIEXYZ: + return ColorSpace.TYPE_XYZ; + case ColorSpace.CS_PYCC: + return ColorSpace.TYPE_3CLR; + case ColorSpace.CS_GRAY: + return ColorSpace.TYPE_GRAY; + default: + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + } + + public static ICC_Profile getInstance(String fileName) throws IOException { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + public static ICC_Profile getInstance(InputStream s) throws IOException { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + public static ICC_Profile getInstance(byte[] data) { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + public static ICC_Profile getInstance(int cspace) { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + public ICC_Profile loadProfile() { + switch (colorspace) { + case ColorSpace.CS_sRGB: + return ICC_Profile.getInstance(ColorSpace.CS_sRGB); + case ColorSpace.CS_GRAY: + return ICC_Profile.getInstance(ColorSpace.CS_GRAY); + case ColorSpace.CS_CIEXYZ: + return ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ); + case ColorSpace.CS_LINEAR_RGB: + return ICC_Profile.getInstance(ColorSpace.CS_LINEAR_RGB); + case ColorSpace.CS_PYCC: + return ICC_Profile.getInstance(ColorSpace.CS_PYCC); + default: + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + } +}
\ No newline at end of file diff --git a/awt/java/awt/color/ProfileDataException.java b/awt/java/awt/color/ProfileDataException.java new file mode 100644 index 0000000..335f314 --- /dev/null +++ b/awt/java/awt/color/ProfileDataException.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +package java.awt.color; + +/** + * The ProfileDataException class represents an error which occurs while + * accessing or processing an ICC_Profile object. + * + * @since Android 1.0 + */ +public class ProfileDataException extends RuntimeException { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 7286140888240322498L; + + /** + * Instantiates a new profile data exception with detailed message. + * + * @param s + * the detailed message of the exception. + */ + public ProfileDataException(String s) { + super(s); + } + +} + diff --git a/awt/java/awt/color/package.html b/awt/java/awt/color/package.html new file mode 100644 index 0000000..609d963 --- /dev/null +++ b/awt/java/awt/color/package.html @@ -0,0 +1,8 @@ +<html> + <body> + <p> + This package contains classes representing color spaces and profiles based on the International Color Consortium (ICC) Profile Format Specification. + </p> + @since Android 1.0 + </body> +</html> diff --git a/awt/java/awt/event/AWTEventListener.java b/awt/java/awt/event/AWTEventListener.java new file mode 100644 index 0000000..76293b3 --- /dev/null +++ b/awt/java/awt/event/AWTEventListener.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.AWTEvent; +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface AWTEventListener extends EventListener { + + public void eventDispatched(AWTEvent event); + +} diff --git a/awt/java/awt/event/AWTEventListenerProxy.java b/awt/java/awt/event/AWTEventListenerProxy.java new file mode 100644 index 0000000..3edc41f --- /dev/null +++ b/awt/java/awt/event/AWTEventListenerProxy.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.AWTEvent; + +import java.util.EventListenerProxy; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class AWTEventListenerProxy extends EventListenerProxy implements AWTEventListener { + + private AWTEventListener listener; + private long eventMask; + + public AWTEventListenerProxy(long eventMask, AWTEventListener listener) { + super(listener); + + // awt.193=Listener can't be zero + assert listener != null : Messages.getString("awt.193"); //$NON-NLS-1$ + + this.listener = listener; + this.eventMask = eventMask; + } + + public void eventDispatched(AWTEvent evt) { + listener.eventDispatched(evt); + } + + public long getEventMask() { + return eventMask; + } + +} diff --git a/awt/java/awt/event/ActionEvent.java b/awt/java/awt/event/ActionEvent.java new file mode 100644 index 0000000..e882e0d --- /dev/null +++ b/awt/java/awt/event/ActionEvent.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.AWTEvent; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class ActionEvent extends AWTEvent { + + private static final long serialVersionUID = -7671078796273832149L; + + public static final int SHIFT_MASK = 1; + + public static final int CTRL_MASK = 2; + + public static final int META_MASK = 4; + + public static final int ALT_MASK = 8; + + public static final int ACTION_FIRST = 1001; + + public static final int ACTION_LAST = 1001; + + public static final int ACTION_PERFORMED = 1001; + + private long when; + private int modifiers; + private String command; + + public ActionEvent(Object source, int id, String command) { + this(source, id, command, 0); + } + + public ActionEvent(Object source, int id, String command, int modifiers) { + this(source, id, command, 0l, modifiers); + } + + public ActionEvent(Object source, int id, String command, long when, int modifiers) { + super(source, id); + + this.command = command; + this.when = when; + this.modifiers = modifiers; + } + + public int getModifiers() { + return modifiers; + } + + public String getActionCommand() { + return command; + } + + public long getWhen() { + return when; + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * ActionEvent e = new ActionEvent(new Component(){}, + * ActionEvent.ACTION_PERFORMED, "Command", + * ActionEvent.SHIFT_MASK|ActionEvent.CTRL_MASK| + * ActionEvent.META_MASK|ActionEvent.ALT_MASK); + * System.out.println(e); + */ + + String idString = (id == ACTION_PERFORMED) ? + "ACTION_PERFORMED" : "unknown type"; //$NON-NLS-1$ //$NON-NLS-2$ + String modifiersString = ""; //$NON-NLS-1$ + + if ((modifiers & SHIFT_MASK) > 0) { + modifiersString += "Shift"; //$NON-NLS-1$ + } + if ((modifiers & CTRL_MASK) > 0) { + modifiersString += modifiersString.length() == 0 ? "Ctrl" : "+Ctrl"; //$NON-NLS-1$ //$NON-NLS-2$ + } + if ((modifiers & META_MASK) > 0) { + modifiersString += modifiersString.length() == 0 ? "Meta" : "+Meta"; //$NON-NLS-1$ //$NON-NLS-2$ + } + if ((modifiers & ALT_MASK) > 0) { + modifiersString += modifiersString.length() == 0 ? "Alt" : "+Alt"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + return (idString + ",cmd=" + command + ",when=" + when + //$NON-NLS-1$ //$NON-NLS-2$ + ",modifiers=" + modifiersString); //$NON-NLS-1$ + } + +} diff --git a/awt/java/awt/event/ActionListener.java b/awt/java/awt/event/ActionListener.java new file mode 100644 index 0000000..a6eee7a --- /dev/null +++ b/awt/java/awt/event/ActionListener.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface ActionListener extends EventListener { + + public void actionPerformed(ActionEvent e); + +} diff --git a/awt/java/awt/event/AdjustmentEvent.java b/awt/java/awt/event/AdjustmentEvent.java new file mode 100644 index 0000000..be2d6c4 --- /dev/null +++ b/awt/java/awt/event/AdjustmentEvent.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.AWTEvent; +import java.awt.Adjustable; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class AdjustmentEvent extends AWTEvent { + + private static final long serialVersionUID = 5700290645205279921L; + + public static final int ADJUSTMENT_FIRST = 601; + + public static final int ADJUSTMENT_LAST = 601; + + public static final int ADJUSTMENT_VALUE_CHANGED = 601; + + public static final int UNIT_INCREMENT = 1; + + public static final int UNIT_DECREMENT = 2; + + public static final int BLOCK_DECREMENT = 3; + + public static final int BLOCK_INCREMENT = 4; + + public static final int TRACK = 5; + + private int type; + private int value; + private boolean isAdjusting; + + public AdjustmentEvent(Adjustable source, int id, int type, int value) { + this(source, id, type, value, false); + } + + public AdjustmentEvent(Adjustable source, int id, int type, int value, + boolean isAdjusting) { + super(source, id); + this.type = type; + this.value = value; + this.isAdjusting = isAdjusting; + } + + public int getValue() { + return value; + } + + public int getAdjustmentType() { + return type; + } + + public boolean getValueIsAdjusting() { + return isAdjusting; + } + + public Adjustable getAdjustable() { + return (Adjustable) source; + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * AdjustmentEvent e = new AdjustmentEvent(new Scrollbar(), + * AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + * AdjustmentEvent.UNIT_INCREMENT, 1); + * System.out.println(e); + */ + + String idString = (id == ADJUSTMENT_VALUE_CHANGED ? + "ADJUSTMENT_VALUE_CHANGED" : "unknown type"); //$NON-NLS-1$ //$NON-NLS-2$ + String adjType = null; + + switch (type) { + case UNIT_INCREMENT: + adjType = "UNIT_INCREMENT"; //$NON-NLS-1$ + break; + case UNIT_DECREMENT: + adjType = "UNIT_DECREMENT"; //$NON-NLS-1$ + break; + case BLOCK_INCREMENT: + adjType = "BLOCK_INCREMENT"; //$NON-NLS-1$ + break; + case BLOCK_DECREMENT: + adjType = "BLOCK_DECREMENT"; //$NON-NLS-1$ + break; + case TRACK: + adjType = "TRACK"; //$NON-NLS-1$ + break; + default: + adjType = "unknown type"; //$NON-NLS-1$ + } + + return (idString + ",adjType=" + adjType + ",value=" + value + //$NON-NLS-1$ //$NON-NLS-2$ + ",isAdjusting=" + isAdjusting); //$NON-NLS-1$ + } + +} diff --git a/awt/java/awt/event/AdjustmentListener.java b/awt/java/awt/event/AdjustmentListener.java new file mode 100644 index 0000000..5f6a724 --- /dev/null +++ b/awt/java/awt/event/AdjustmentListener.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface AdjustmentListener extends EventListener { + + public void adjustmentValueChanged(AdjustmentEvent e); + +} diff --git a/awt/java/awt/event/ComponentAdapter.java b/awt/java/awt/event/ComponentAdapter.java new file mode 100644 index 0000000..c42235f --- /dev/null +++ b/awt/java/awt/event/ComponentAdapter.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public abstract class ComponentAdapter implements ComponentListener { + + public ComponentAdapter() { + } + + public void componentHidden(ComponentEvent e) { + } + + public void componentMoved(ComponentEvent e) { + } + + public void componentResized(ComponentEvent e) { + } + + public void componentShown(ComponentEvent e) { + } + +} diff --git a/awt/java/awt/event/ComponentEvent.java b/awt/java/awt/event/ComponentEvent.java new file mode 100644 index 0000000..760d3ab --- /dev/null +++ b/awt/java/awt/event/ComponentEvent.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.AWTEvent; +import java.awt.Component; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class ComponentEvent extends AWTEvent { + + private static final long serialVersionUID = 8101406823902992965L; + + public static final int COMPONENT_FIRST = 100; + + public static final int COMPONENT_LAST = 103; + + public static final int COMPONENT_MOVED = 100; + + public static final int COMPONENT_RESIZED = 101; + + public static final int COMPONENT_SHOWN = 102; + + public static final int COMPONENT_HIDDEN = 103; + + public ComponentEvent(Component source, int id) { + super(source, id); + } + + public Component getComponent() { + return (Component) source; + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * ComponentEvent e = new ComponentEvent(new Button("Button"), + * ComponentEvent.COMPONENT_SHOWN); + * System.out.println(e); + */ + + String idString = null; + Component c = getComponent(); + + switch (id) { + case COMPONENT_MOVED: + idString = "COMPONENT_MOVED"; //$NON-NLS-1$ + break; + case COMPONENT_RESIZED: + idString = "COMPONENT_RESIZED"; //$NON-NLS-1$ + break; + case COMPONENT_SHOWN: + return "COMPONENT_SHOWN"; //$NON-NLS-1$ + case COMPONENT_HIDDEN: + return "COMPONENT_HIDDEN"; //$NON-NLS-1$ + default: + return "unknown type"; //$NON-NLS-1$ + } + + return (idString + " (" + c.getX() + "," + c.getY() + //$NON-NLS-1$ //$NON-NLS-2$ + " " + c.getWidth()+ "x" + c.getHeight() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + +} diff --git a/awt/java/awt/event/ComponentListener.java b/awt/java/awt/event/ComponentListener.java new file mode 100644 index 0000000..a5adba2 --- /dev/null +++ b/awt/java/awt/event/ComponentListener.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface ComponentListener extends EventListener { + + public void componentHidden(ComponentEvent e); + + public void componentMoved(ComponentEvent e); + + public void componentResized(ComponentEvent e); + + public void componentShown(ComponentEvent e); + +} diff --git a/awt/java/awt/event/ContainerAdapter.java b/awt/java/awt/event/ContainerAdapter.java new file mode 100644 index 0000000..44983c7 --- /dev/null +++ b/awt/java/awt/event/ContainerAdapter.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public abstract class ContainerAdapter implements ContainerListener { + + public ContainerAdapter() { + } + + public void componentAdded(ContainerEvent e) { + } + + public void componentRemoved(ContainerEvent e) { + } + +} diff --git a/awt/java/awt/event/ContainerEvent.java b/awt/java/awt/event/ContainerEvent.java new file mode 100644 index 0000000..372c9e4 --- /dev/null +++ b/awt/java/awt/event/ContainerEvent.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.Component; +//???AWT: import java.awt.Container; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class ContainerEvent extends ComponentEvent { + + private static final long serialVersionUID = -4114942250539772041L; + + public static final int CONTAINER_FIRST = 300; + + public static final int CONTAINER_LAST = 301; + + public static final int COMPONENT_ADDED = 300; + + public static final int COMPONENT_REMOVED = 301; + + private Component child; + + public ContainerEvent(Component src, int id, Component child) { + super(src, id); + this.child = child; + } + + public Component getChild() { + return child; + } + + //???AWT + /* + public Container getContainer() { + return (Container) source; + } + */ + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * ContainerEvent e = new ContainerEvent(new Panel(), + * ContainerEvent.COMPONENT_ADDED, + * new Button("Button")); + * System.out.println(e); + */ + + String idString = null; + + switch (id) { + case COMPONENT_ADDED: + idString = "COMPONENT_ADDED"; //$NON-NLS-1$ + break; + case COMPONENT_REMOVED: + idString = "COMPONENT_REMOVED"; //$NON-NLS-1$ + break; + default: + idString = "unknown type"; //$NON-NLS-1$ + } + + return (idString + ",child=" + child.getName()); //$NON-NLS-1$ + } + +} diff --git a/awt/java/awt/event/ContainerListener.java b/awt/java/awt/event/ContainerListener.java new file mode 100644 index 0000000..517859e --- /dev/null +++ b/awt/java/awt/event/ContainerListener.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface ContainerListener extends EventListener { + + public void componentAdded(ContainerEvent e); + + public void componentRemoved(ContainerEvent e); + +} diff --git a/awt/java/awt/event/FocusAdapter.java b/awt/java/awt/event/FocusAdapter.java new file mode 100644 index 0000000..3a3e37f --- /dev/null +++ b/awt/java/awt/event/FocusAdapter.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public abstract class FocusAdapter implements FocusListener { + + public FocusAdapter() { + } + + public void focusGained(FocusEvent e) { + } + + public void focusLost(FocusEvent e) { + } + +} diff --git a/awt/java/awt/event/FocusEvent.java b/awt/java/awt/event/FocusEvent.java new file mode 100644 index 0000000..4a18689 --- /dev/null +++ b/awt/java/awt/event/FocusEvent.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.Component; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class FocusEvent extends ComponentEvent { + + private static final long serialVersionUID = 523753786457416396L; + + public static final int FOCUS_FIRST = 1004; + + public static final int FOCUS_LAST = 1005; + + public static final int FOCUS_GAINED = 1004; + + public static final int FOCUS_LOST = 1005; + + private boolean temporary; + private Component opposite; + + public FocusEvent(Component source, int id) { + this(source, id, false); + } + + public FocusEvent(Component source, int id, boolean temporary) { + this(source, id, temporary, null); + } + + public FocusEvent(Component source, int id, boolean temporary, Component opposite) { + super(source, id); + this.temporary = temporary; + this.opposite = opposite; + } + + public Component getOppositeComponent() { + return opposite; + } + + public boolean isTemporary() { + return temporary; + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * FocusEvent e = new FocusEvent(new Button("Button0"), + * FocusEvent.FOCUS_GAINED, false, new Button("Button1")); + * System.out.println(e); + */ + + String idString = null; + + switch (id) { + case FOCUS_GAINED: + idString = "FOCUS_GAINED"; //$NON-NLS-1$ + break; + case FOCUS_LOST: + idString = "FOCUS_LOST"; //$NON-NLS-1$ + break; + default: + idString = "unknown type"; //$NON-NLS-1$ + } + + return (idString + + (temporary ? ",temporary" : ",permanent") + //$NON-NLS-1$ //$NON-NLS-2$ + ",opposite=" + opposite); //$NON-NLS-1$ + } + +} diff --git a/awt/java/awt/event/FocusListener.java b/awt/java/awt/event/FocusListener.java new file mode 100644 index 0000000..6bbbd00 --- /dev/null +++ b/awt/java/awt/event/FocusListener.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface FocusListener extends EventListener { + + public void focusGained(FocusEvent e); + + public void focusLost(FocusEvent e); + +} diff --git a/awt/java/awt/event/HierarchyBoundsAdapter.java b/awt/java/awt/event/HierarchyBoundsAdapter.java new file mode 100644 index 0000000..bbfe8ff --- /dev/null +++ b/awt/java/awt/event/HierarchyBoundsAdapter.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public abstract class HierarchyBoundsAdapter implements HierarchyBoundsListener { + + public HierarchyBoundsAdapter() { + } + + public void ancestorMoved(HierarchyEvent e) { + } + + public void ancestorResized(HierarchyEvent e) { + } + +} diff --git a/awt/java/awt/event/HierarchyBoundsListener.java b/awt/java/awt/event/HierarchyBoundsListener.java new file mode 100644 index 0000000..3e8f2e7 --- /dev/null +++ b/awt/java/awt/event/HierarchyBoundsListener.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface HierarchyBoundsListener extends EventListener { + + public void ancestorMoved(HierarchyEvent e); + + public void ancestorResized(HierarchyEvent e); + +} diff --git a/awt/java/awt/event/HierarchyEvent.java b/awt/java/awt/event/HierarchyEvent.java new file mode 100644 index 0000000..c1d22f4 --- /dev/null +++ b/awt/java/awt/event/HierarchyEvent.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.AWTEvent; +import java.awt.Component; +//???AWT: import java.awt.Container; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class HierarchyEvent extends AWTEvent { + + private static final long serialVersionUID = -5337576970038043990L; + + public static final int HIERARCHY_FIRST = 1400; + + public static final int HIERARCHY_CHANGED = 1400; + + public static final int ANCESTOR_MOVED = 1401; + + public static final int ANCESTOR_RESIZED = 1402; + + public static final int HIERARCHY_LAST = 1402; + + public static final int PARENT_CHANGED = 1; + + public static final int DISPLAYABILITY_CHANGED = 2; + + public static final int SHOWING_CHANGED = 4; + + //???AWT: private Container changedParent; + private Component changed; + private long changeFlag; + + //???AWT + /* + public HierarchyEvent(Component source, int id, Component changed, + Container changedParent) { + this(source, id, changed, changedParent, 0l); + } + */ + + //???AWT + /* + public HierarchyEvent(Component source, int id, Component changed, + Container changedParent, long changeFlags) { + super(source, id); + + this.changed = changed; + this.changedParent = changedParent; + this.changeFlag = changeFlags; + } + */ + //???AWT: Fake constructor, should be as above. + public HierarchyEvent(Component source, int id, Component changed, + Object changedParent, long changeFlags) { + super(source, id); + +// this.changed = changed; +// this.changedParent = changedParent; +// this.changeFlag = changeFlags; + } + + public Component getComponent() { + return (Component) source; + } + + public long getChangeFlags() { + return changeFlag; + } + + public Component getChanged() { + return changed; + } + + //???AWT + /* + public Container getChangedParent() { + return changedParent; + + } + */ + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * HierarchyEvent e = new HierarchyEvent(new Button("Button"), + * HierarchyEvent.HIERARCHY_CHANGED, + * new Panel(), new Container()); + * System.out.println(e); + */ + String paramString = null; + + switch (id) { + case HIERARCHY_CHANGED: + paramString = "HIERARCHY_CHANGED"; //$NON-NLS-1$ + break; + case ANCESTOR_MOVED: + paramString = "ANCESTOR_MOVED"; //$NON-NLS-1$ + break; + case ANCESTOR_RESIZED: + paramString = "ANCESTOR_RESIZED"; //$NON-NLS-1$ + break; + default: + paramString = "unknown type"; //$NON-NLS-1$ + } + + paramString += " ("; //$NON-NLS-1$ + + if (id == HIERARCHY_CHANGED) { + if ((changeFlag & PARENT_CHANGED) > 0) { + paramString += "PARENT_CHANGED,"; //$NON-NLS-1$ + } + if ((changeFlag & DISPLAYABILITY_CHANGED) > 0) { + paramString += "DISPLAYABILITY_CHANGED,"; //$NON-NLS-1$ + } + if ((changeFlag & SHOWING_CHANGED) > 0) { + paramString += "SHOWING_CHANGED,"; //$NON-NLS-1$ + } + } + + //???AWT + /* + return paramString + "changed=" + changed + //$NON-NLS-1$ + ",changedParent=" + changedParent + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + */ + return paramString; + } + +} diff --git a/awt/java/awt/event/HierarchyListener.java b/awt/java/awt/event/HierarchyListener.java new file mode 100644 index 0000000..ff3d9bc --- /dev/null +++ b/awt/java/awt/event/HierarchyListener.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface HierarchyListener extends EventListener { + + public void hierarchyChanged(HierarchyEvent e); + +} diff --git a/awt/java/awt/event/InputEvent.java b/awt/java/awt/event/InputEvent.java new file mode 100644 index 0000000..343b7a3 --- /dev/null +++ b/awt/java/awt/event/InputEvent.java @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.Component; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public abstract class InputEvent extends ComponentEvent { + + private static final long serialVersionUID = -2482525981698309786L; + + public static final int SHIFT_MASK = 1; + + public static final int CTRL_MASK = 2; + + public static final int META_MASK = 4; + + public static final int ALT_MASK = 8; + + public static final int ALT_GRAPH_MASK = 32; + + public static final int BUTTON1_MASK = 16; + + public static final int BUTTON2_MASK = 8; + + public static final int BUTTON3_MASK = 4; + + public static final int SHIFT_DOWN_MASK = 64; + + public static final int CTRL_DOWN_MASK = 128; + + public static final int META_DOWN_MASK = 256; + + public static final int ALT_DOWN_MASK = 512; + + public static final int BUTTON1_DOWN_MASK = 1024; + + public static final int BUTTON2_DOWN_MASK = 2048; + + public static final int BUTTON3_DOWN_MASK = 4096; + + public static final int ALT_GRAPH_DOWN_MASK = 8192; + + private static final int DOWN_MASKS = SHIFT_DOWN_MASK | CTRL_DOWN_MASK | + META_DOWN_MASK | ALT_DOWN_MASK | BUTTON1_DOWN_MASK | + BUTTON2_DOWN_MASK | BUTTON3_DOWN_MASK | ALT_GRAPH_DOWN_MASK; + + private long when; + private int modifiersEx; + + public static String getModifiersExText(int modifiers/*Ex*/) { + return MouseEvent.addMouseModifiersExText( + KeyEvent.getKeyModifiersExText(modifiers), modifiers); + } + + static int extractExFlags(int modifiers) { + int exFlags = modifiers & DOWN_MASKS; + + if ((modifiers & SHIFT_MASK) != 0) { + exFlags |= SHIFT_DOWN_MASK; + } + if ((modifiers & CTRL_MASK) != 0) { + exFlags |= CTRL_DOWN_MASK; + } + if ((modifiers & META_MASK) != 0) { + exFlags |= META_DOWN_MASK; + } + if ((modifiers & ALT_MASK) != 0) { + exFlags |= ALT_DOWN_MASK; + } + if ((modifiers & ALT_GRAPH_MASK) != 0) { + exFlags |= ALT_GRAPH_DOWN_MASK; + } + if ((modifiers & BUTTON1_MASK) != 0) { + exFlags |= BUTTON1_DOWN_MASK; + } + if ((modifiers & BUTTON2_MASK) != 0) { + exFlags |= BUTTON2_DOWN_MASK; + } + if ((modifiers & BUTTON3_MASK) != 0) { + exFlags |= BUTTON3_DOWN_MASK; + } + + return exFlags; + } + + InputEvent(Component source, int id, long when, int modifiers) { + super(source, id); + + this.when = when; + modifiersEx = extractExFlags(modifiers); + } + + public int getModifiers() { + int modifiers = 0; + + if ((modifiersEx & SHIFT_DOWN_MASK) != 0) { + modifiers |= SHIFT_MASK; + } + if ((modifiersEx & CTRL_DOWN_MASK) != 0) { + modifiers |= CTRL_MASK; + } + if ((modifiersEx & META_DOWN_MASK) != 0) { + modifiers |= META_MASK; + } + if ((modifiersEx & ALT_DOWN_MASK) != 0) { + modifiers |= ALT_MASK; + } + if ((modifiersEx & ALT_GRAPH_DOWN_MASK) != 0) { + modifiers |= ALT_GRAPH_MASK; + } + if ((modifiersEx & BUTTON1_DOWN_MASK) != 0) { + modifiers |= BUTTON1_MASK; + } + if ((modifiersEx & BUTTON2_DOWN_MASK) != 0) { + modifiers |= BUTTON2_MASK; + } + if ((modifiersEx & BUTTON3_DOWN_MASK) != 0) { + modifiers |= BUTTON3_MASK; + } + + return modifiers; + } + + public int getModifiersEx() { + return modifiersEx; + } + + void setModifiers(int modifiers) { + modifiersEx = extractExFlags(modifiers); + } + + public boolean isAltDown() { + return ((modifiersEx & ALT_DOWN_MASK) != 0); + } + + public boolean isAltGraphDown() { + return ((modifiersEx & ALT_GRAPH_DOWN_MASK) != 0); + } + + public boolean isControlDown() { + return ((modifiersEx & CTRL_DOWN_MASK) != 0); + } + + public boolean isMetaDown() { + return ((modifiersEx & META_DOWN_MASK) != 0); + } + + public boolean isShiftDown() { + return ((modifiersEx & SHIFT_DOWN_MASK) != 0); + } + + public long getWhen() { + return when; + } + + @Override + public void consume() { + super.consume(); + } + + @Override + public boolean isConsumed() { + return super.isConsumed(); + } + +} diff --git a/awt/java/awt/event/InputMethodEvent.java b/awt/java/awt/event/InputMethodEvent.java new file mode 100644 index 0000000..be001a5 --- /dev/null +++ b/awt/java/awt/event/InputMethodEvent.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.font.TextHitInfo; +import java.text.AttributedCharacterIterator; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class InputMethodEvent extends AWTEvent { + + private static final long serialVersionUID = 4727190874778922661L; + + public static final int INPUT_METHOD_FIRST = 1100; + + public static final int INPUT_METHOD_TEXT_CHANGED = 1100; + + public static final int CARET_POSITION_CHANGED = 1101; + + public static final int INPUT_METHOD_LAST = 1101; + + private AttributedCharacterIterator text; + private TextHitInfo visiblePosition; + private TextHitInfo caret; + private int committedCharacterCount; + private long when; + + public InputMethodEvent(Component src, int id, + TextHitInfo caret, + TextHitInfo visiblePos) { + this(src, id, null, 0, caret, visiblePos); + } + + public InputMethodEvent(Component src, int id, + AttributedCharacterIterator text, + int commitedCharCount, + TextHitInfo caret, + TextHitInfo visiblePos) { + this(src, id, 0l, text, commitedCharCount, caret, visiblePos); + } + + public InputMethodEvent(Component src, int id, long when, + AttributedCharacterIterator text, + int committedCharacterCount, + TextHitInfo caret, + TextHitInfo visiblePos) { + super(src, id); + + if ((id < INPUT_METHOD_FIRST) || (id > INPUT_METHOD_LAST)) { + // awt.18E=Wrong event id + throw new IllegalArgumentException(Messages.getString("awt.18E")); //$NON-NLS-1$ + } + if ((id == CARET_POSITION_CHANGED) && (text != null)) { + // awt.18F=Text must be null for CARET_POSITION_CHANGED + throw new IllegalArgumentException(Messages.getString("awt.18F")); //$NON-NLS-1$ + } + if ((text != null) && + ((committedCharacterCount < 0) || + (committedCharacterCount > + (text.getEndIndex() - text.getBeginIndex())))) { + // awt.190=Wrong committedCharacterCount + throw new IllegalArgumentException(Messages.getString("awt.190")); //$NON-NLS-1$ + } + + this.when = when; + this.text = text; + this.caret = caret; + this.visiblePosition = visiblePos; + this.committedCharacterCount = committedCharacterCount; + } + + public TextHitInfo getCaret() { + return caret; + } + + public int getCommittedCharacterCount() { + return committedCharacterCount; + } + + public AttributedCharacterIterator getText() { + return text; + } + + public TextHitInfo getVisiblePosition() { + return visiblePosition; + } + + public long getWhen() { + return when; + } + + @Override + public void consume() { + super.consume(); + } + + @Override + public boolean isConsumed() { + return super.isConsumed(); + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * InputMethodEvent e = new InputMethodEvent(new Component(){}, + * InputMethodEvent.INPUT_METHOD_TEXT_CHANGED, + * TextHitInfo.leading(1), TextHitInfo.trailing(2)); + * System.out.println(e); + */ + String typeString = null; + + switch (id) { + case INPUT_METHOD_TEXT_CHANGED: + typeString = "INPUT_METHOD_TEXT_CHANGED"; //$NON-NLS-1$ + break; + case CARET_POSITION_CHANGED: + typeString = "CARET_POSITION_CHANGED"; //$NON-NLS-1$ + break; + default: + typeString = "unknown type"; //$NON-NLS-1$ + } + + return typeString + ",text=" + text + //$NON-NLS-1$ + ",commitedCharCount=" + committedCharacterCount + //$NON-NLS-1$ + ",caret=" + caret + ",visiblePosition=" + visiblePosition; //$NON-NLS-1$ //$NON-NLS-2$ + } + +} diff --git a/awt/java/awt/event/InputMethodListener.java b/awt/java/awt/event/InputMethodListener.java new file mode 100644 index 0000000..85eaa7e --- /dev/null +++ b/awt/java/awt/event/InputMethodListener.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface InputMethodListener extends EventListener { + + public void caretPositionChanged(InputMethodEvent e); + + public void inputMethodTextChanged(InputMethodEvent e); + +} diff --git a/awt/java/awt/event/InvocationEvent.java b/awt/java/awt/event/InvocationEvent.java new file mode 100644 index 0000000..58e3b72 --- /dev/null +++ b/awt/java/awt/event/InvocationEvent.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.AWTEvent; +import java.awt.ActiveEvent; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class InvocationEvent extends AWTEvent implements ActiveEvent { + + private static final long serialVersionUID = 436056344909459450L; + + public static final int INVOCATION_FIRST = 1200; + + public static final int INVOCATION_DEFAULT = 1200; + + public static final int INVOCATION_LAST = 1200; + + protected Runnable runnable; + + protected Object notifier; + + protected boolean catchExceptions; + + private long when; + private Throwable throwable; + + public InvocationEvent(Object source, Runnable runnable) { + this(source, runnable, null, false); + } + + public InvocationEvent(Object source, Runnable runnable, + Object notifier, boolean catchExceptions) { + this(source, INVOCATION_DEFAULT, runnable, notifier, catchExceptions); + } + + protected InvocationEvent(Object source, int id, Runnable runnable, + Object notifier, boolean catchExceptions) + { + super(source, id); + + // awt.18C=Cannot invoke null runnable + assert runnable != null : Messages.getString("awt.18C"); //$NON-NLS-1$ + + if (source == null) { + // awt.18D=Source is null + throw new IllegalArgumentException(Messages.getString("awt.18D")); //$NON-NLS-1$ + } + this.runnable = runnable; + this.notifier = notifier; + this.catchExceptions = catchExceptions; + + throwable = null; + when = System.currentTimeMillis(); + } + + public void dispatch() { + if (!catchExceptions) { + runAndNotify(); + } else { + try { + runAndNotify(); + } catch (Throwable t) { + throwable = t; + } + } + } + + private void runAndNotify() { + if (notifier != null) { + synchronized(notifier) { + try { + runnable.run(); + } finally { + notifier.notifyAll(); + } + } + } else { + runnable.run(); + } + } + + public Exception getException() { + return (throwable != null && throwable instanceof Exception) ? + (Exception)throwable : null; + } + + public Throwable getThrowable() { + return throwable; + } + + public long getWhen() { + return when; + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * InvocationEvent e = new InvocationEvent(new Component(){}, + * new Runnable() { public void run(){} }); + * System.out.println(e); + */ + + return ((id == INVOCATION_DEFAULT ? "INVOCATION_DEFAULT" : "unknown type") + //$NON-NLS-1$ //$NON-NLS-2$ + ",runnable=" + runnable + //$NON-NLS-1$ + ",notifier=" + notifier + //$NON-NLS-1$ + ",catchExceptions=" + catchExceptions + //$NON-NLS-1$ + ",when=" + when); //$NON-NLS-1$ + } + +} diff --git a/awt/java/awt/event/ItemEvent.java b/awt/java/awt/event/ItemEvent.java new file mode 100644 index 0000000..09908f2 --- /dev/null +++ b/awt/java/awt/event/ItemEvent.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.AWTEvent; +import java.awt.ItemSelectable; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class ItemEvent extends AWTEvent { + + private static final long serialVersionUID = -608708132447206933L; + + public static final int ITEM_FIRST = 701; + + public static final int ITEM_LAST = 701; + + public static final int ITEM_STATE_CHANGED = 701; + + public static final int SELECTED = 1; + + public static final int DESELECTED = 2; + + private Object item; + private int stateChange; + + public ItemEvent(ItemSelectable source, int id, Object item, int stateChange) { + super(source, id); + + this.item = item; + this.stateChange = stateChange; + } + + public Object getItem() { + return item; + } + + public int getStateChange() { + return stateChange; + } + + public ItemSelectable getItemSelectable() { + return (ItemSelectable) source; + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * Checkbox c = new Checkbox("Checkbox", true); + * ItemEvent e = new ItemEvent(c, ItemEvent.ITEM_STATE_CHANGED, + * c, ItemEvent.SELECTED); + * System.out.println(e); + */ + + String stateString = null; + + switch (stateChange) { + case SELECTED: + stateString = "SELECTED"; //$NON-NLS-1$ + break; + case DESELECTED: + stateString = "DESELECTED"; //$NON-NLS-1$ + break; + default: + stateString = "unknown type"; //$NON-NLS-1$ + } + + return ((id == ITEM_STATE_CHANGED ? "ITEM_STATE_CHANGED" : "unknown type") + //$NON-NLS-1$ //$NON-NLS-2$ + ",item=" + item + ",stateChange=" + stateString); //$NON-NLS-1$ //$NON-NLS-2$ + } + +} diff --git a/awt/java/awt/event/ItemListener.java b/awt/java/awt/event/ItemListener.java new file mode 100644 index 0000000..8dec673 --- /dev/null +++ b/awt/java/awt/event/ItemListener.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface ItemListener extends EventListener { + + public void itemStateChanged(ItemEvent e); + +} diff --git a/awt/java/awt/event/KeyAdapter.java b/awt/java/awt/event/KeyAdapter.java new file mode 100644 index 0000000..a96cca8 --- /dev/null +++ b/awt/java/awt/event/KeyAdapter.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public abstract class KeyAdapter implements KeyListener { + + public KeyAdapter() { + } + + public void keyPressed(KeyEvent e) { + } + + public void keyReleased(KeyEvent e) { + } + + public void keyTyped(KeyEvent e) { + } + +} diff --git a/awt/java/awt/event/KeyEvent.java b/awt/java/awt/event/KeyEvent.java new file mode 100644 index 0000000..8627f70 --- /dev/null +++ b/awt/java/awt/event/KeyEvent.java @@ -0,0 +1,687 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.Component; +import java.awt.Toolkit; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class KeyEvent extends InputEvent { + + private static final long serialVersionUID = -2352130953028126954L; + + public static final int KEY_FIRST = 400; + + public static final int KEY_LAST = 402; + + public static final int KEY_TYPED = 400; + + public static final int KEY_PRESSED = 401; + + public static final int KEY_RELEASED = 402; + + public static final int VK_ENTER = 10; + + public static final int VK_BACK_SPACE = 8; + + public static final int VK_TAB = 9; + + public static final int VK_CANCEL = 3; + + public static final int VK_CLEAR = 12; + + public static final int VK_SHIFT = 16; + + public static final int VK_CONTROL = 17; + + public static final int VK_ALT = 18; + + public static final int VK_PAUSE = 19; + + public static final int VK_CAPS_LOCK = 20; + + public static final int VK_ESCAPE = 27; + + public static final int VK_SPACE = 32; + + public static final int VK_PAGE_UP = 33; + + public static final int VK_PAGE_DOWN = 34; + + public static final int VK_END = 35; + + public static final int VK_HOME = 36; + + public static final int VK_LEFT = 37; + + public static final int VK_UP = 38; + + public static final int VK_RIGHT = 39; + + public static final int VK_DOWN = 40; + + public static final int VK_COMMA = 44; + + public static final int VK_MINUS = 45; + + public static final int VK_PERIOD = 46; + + public static final int VK_SLASH = 47; + + public static final int VK_0 = 48; + + public static final int VK_1 = 49; + + public static final int VK_2 = 50; + + public static final int VK_3 = 51; + + public static final int VK_4 = 52; + + public static final int VK_5 = 53; + + public static final int VK_6 = 54; + + public static final int VK_7 = 55; + + public static final int VK_8 = 56; + + public static final int VK_9 = 57; + + public static final int VK_SEMICOLON = 59; + + public static final int VK_EQUALS = 61; + + public static final int VK_A = 65; + + public static final int VK_B = 66; + + public static final int VK_C = 67; + + public static final int VK_D = 68; + + public static final int VK_E = 69; + + public static final int VK_F = 70; + + public static final int VK_G = 71; + + public static final int VK_H = 72; + + public static final int VK_I = 73; + + public static final int VK_J = 74; + + public static final int VK_K = 75; + + public static final int VK_L = 76; + + public static final int VK_M = 77; + + public static final int VK_N = 78; + + public static final int VK_O = 79; + + public static final int VK_P = 80; + + public static final int VK_Q = 81; + + public static final int VK_R = 82; + + public static final int VK_S = 83; + + public static final int VK_T = 84; + + public static final int VK_U = 85; + + public static final int VK_V = 86; + + public static final int VK_W = 87; + + public static final int VK_X = 88; + + public static final int VK_Y = 89; + + public static final int VK_Z = 90; + + public static final int VK_OPEN_BRACKET = 91; + + public static final int VK_BACK_SLASH = 92; + + public static final int VK_CLOSE_BRACKET = 93; + + public static final int VK_NUMPAD0 = 96; + + public static final int VK_NUMPAD1 = 97; + + public static final int VK_NUMPAD2 = 98; + + public static final int VK_NUMPAD3 = 99; + + public static final int VK_NUMPAD4 = 100; + + public static final int VK_NUMPAD5 = 101; + + public static final int VK_NUMPAD6 = 102; + + public static final int VK_NUMPAD7 = 103; + + public static final int VK_NUMPAD8 = 104; + + public static final int VK_NUMPAD9 = 105; + + public static final int VK_MULTIPLY = 106; + + public static final int VK_ADD = 107; + + public static final int VK_SEPARATER = 108; + + public static final int VK_SEPARATOR = 108; + + public static final int VK_SUBTRACT = 109; + + public static final int VK_DECIMAL = 110; + + public static final int VK_DIVIDE = 111; + + public static final int VK_DELETE = 127; + + public static final int VK_NUM_LOCK = 144; + + public static final int VK_SCROLL_LOCK = 145; + + public static final int VK_F1 = 112; + + public static final int VK_F2 = 113; + + public static final int VK_F3 = 114; + + public static final int VK_F4 = 115; + + public static final int VK_F5 = 116; + + public static final int VK_F6 = 117; + + public static final int VK_F7 = 118; + + public static final int VK_F8 = 119; + + public static final int VK_F9 = 120; + + public static final int VK_F10 = 121; + + public static final int VK_F11 = 122; + + public static final int VK_F12 = 123; + + public static final int VK_F13 = 61440; + + public static final int VK_F14 = 61441; + + public static final int VK_F15 = 61442; + + public static final int VK_F16 = 61443; + + public static final int VK_F17 = 61444; + + public static final int VK_F18 = 61445; + + public static final int VK_F19 = 61446; + + public static final int VK_F20 = 61447; + + public static final int VK_F21 = 61448; + + public static final int VK_F22 = 61449; + + public static final int VK_F23 = 61450; + + public static final int VK_F24 = 61451; + + public static final int VK_PRINTSCREEN = 154; + + public static final int VK_INSERT = 155; + + public static final int VK_HELP = 156; + + public static final int VK_META = 157; + + public static final int VK_BACK_QUOTE = 192; + + public static final int VK_QUOTE = 222; + + public static final int VK_KP_UP = 224; + + public static final int VK_KP_DOWN = 225; + + public static final int VK_KP_LEFT = 226; + + public static final int VK_KP_RIGHT = 227; + + public static final int VK_DEAD_GRAVE = 128; + + public static final int VK_DEAD_ACUTE = 129; + + public static final int VK_DEAD_CIRCUMFLEX = 130; + + public static final int VK_DEAD_TILDE = 131; + + public static final int VK_DEAD_MACRON = 132; + + public static final int VK_DEAD_BREVE = 133; + + public static final int VK_DEAD_ABOVEDOT = 134; + + public static final int VK_DEAD_DIAERESIS = 135; + + public static final int VK_DEAD_ABOVERING = 136; + + public static final int VK_DEAD_DOUBLEACUTE = 137; + + public static final int VK_DEAD_CARON = 138; + + public static final int VK_DEAD_CEDILLA = 139; + + public static final int VK_DEAD_OGONEK = 140; + + public static final int VK_DEAD_IOTA = 141; + + public static final int VK_DEAD_VOICED_SOUND = 142; + + public static final int VK_DEAD_SEMIVOICED_SOUND = 143; + + public static final int VK_AMPERSAND = 150; + + public static final int VK_ASTERISK = 151; + + public static final int VK_QUOTEDBL = 152; + + public static final int VK_LESS = 153; + + public static final int VK_GREATER = 160; + + public static final int VK_BRACELEFT = 161; + + public static final int VK_BRACERIGHT = 162; + + public static final int VK_AT = 512; + + public static final int VK_COLON = 513; + + public static final int VK_CIRCUMFLEX = 514; + + public static final int VK_DOLLAR = 515; + + public static final int VK_EURO_SIGN = 516; + + public static final int VK_EXCLAMATION_MARK = 517; + + public static final int VK_INVERTED_EXCLAMATION_MARK = 518; + + public static final int VK_LEFT_PARENTHESIS = 519; + + public static final int VK_NUMBER_SIGN = 520; + + public static final int VK_PLUS = 521; + + public static final int VK_RIGHT_PARENTHESIS = 522; + + public static final int VK_UNDERSCORE = 523; + + public static final int VK_FINAL = 24; + + public static final int VK_WINDOWS = 524; + + public static final int VK_CONTEXT_MENU = 525; + + public static final int VK_CONVERT = 28; + + public static final int VK_NONCONVERT = 29; + + public static final int VK_ACCEPT = 30; + + public static final int VK_MODECHANGE = 31; + + public static final int VK_KANA = 21; + + public static final int VK_KANJI = 25; + + public static final int VK_ALPHANUMERIC = 240; + + public static final int VK_KATAKANA = 241; + + public static final int VK_HIRAGANA = 242; + + public static final int VK_FULL_WIDTH = 243; + + public static final int VK_HALF_WIDTH = 244; + + public static final int VK_ROMAN_CHARACTERS = 245; + + public static final int VK_ALL_CANDIDATES = 256; + + public static final int VK_PREVIOUS_CANDIDATE = 257; + + public static final int VK_CODE_INPUT = 258; + + public static final int VK_JAPANESE_KATAKANA = 259; + + public static final int VK_JAPANESE_HIRAGANA = 260; + + public static final int VK_JAPANESE_ROMAN = 261; + + public static final int VK_KANA_LOCK = 262; + + public static final int VK_INPUT_METHOD_ON_OFF = 263; + + public static final int VK_CUT = 65489; + + public static final int VK_COPY = 65485; + + public static final int VK_PASTE = 65487; + + public static final int VK_UNDO = 65483; + + public static final int VK_AGAIN = 65481; + + public static final int VK_FIND = 65488; + + public static final int VK_PROPS = 65482; + + public static final int VK_STOP = 65480; + + public static final int VK_COMPOSE = 65312; + + public static final int VK_ALT_GRAPH = 65406; + + public static final int VK_BEGIN = 65368; + + public static final int VK_UNDEFINED = 0; + + public static final char CHAR_UNDEFINED = (char)(-1); + + public static final int KEY_LOCATION_UNKNOWN = 0; + + public static final int KEY_LOCATION_STANDARD = 1; + + public static final int KEY_LOCATION_LEFT = 2; + + public static final int KEY_LOCATION_RIGHT = 3; + + public static final int KEY_LOCATION_NUMPAD = 4; + + private int keyCode; + private char keyChar; + private int keyLocation; + + public static String getKeyModifiersText(int modifiers) { + return getKeyModifiersExText(extractExFlags(modifiers)); + } + + static String getKeyModifiersExText(int modifiersEx) { + String text = ""; //$NON-NLS-1$ + + if ((modifiersEx & InputEvent.META_DOWN_MASK) != 0) { + text += Toolkit.getProperty("AWT.meta", "Meta"); //$NON-NLS-1$ //$NON-NLS-2$ + } + if ((modifiersEx & InputEvent.CTRL_DOWN_MASK) != 0) { + text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$ + Toolkit.getProperty("AWT.control", "Ctrl"); //$NON-NLS-1$ //$NON-NLS-2$ + } + if ((modifiersEx & InputEvent.ALT_DOWN_MASK) != 0) { + text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$ + Toolkit.getProperty("AWT.alt", "Alt"); //$NON-NLS-1$ //$NON-NLS-2$ + } + if ((modifiersEx & InputEvent.SHIFT_DOWN_MASK) != 0) { + text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$ + Toolkit.getProperty("AWT.shift", "Shift"); //$NON-NLS-1$ //$NON-NLS-2$ + } + if ((modifiersEx & InputEvent.ALT_GRAPH_DOWN_MASK) != 0) { + text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$ + Toolkit.getProperty("AWT.altGraph", "Alt Graph"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + return text; + } + + public static String getKeyText(int keyCode) { + String[] rawName = getPublicStaticFinalIntFieldName(keyCode); //$NON-NLS-1$ + + if ((rawName == null) || (rawName.length == 0)) { + return ("Unknown keyCode: " + (keyCode >= 0 ? "0x" : "-0x") + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + Integer.toHexString(Math.abs(keyCode))); + } + + String propertyName = getPropertyName(rawName); + String defaultName = getDefaultName(rawName); + + return Toolkit.getProperty(propertyName, defaultName); + } + + private static String getDefaultName(String[] rawName) { + String name = ""; //$NON-NLS-1$ + + for (int i = 0; true; i++) { + String part = rawName[i]; + + name += new String(new char[] {part.charAt(0)}).toUpperCase() + + part.substring(1).toLowerCase(); + + if (i == (rawName.length - 1)) { + break; + } + name += " "; //$NON-NLS-1$ + } + + return name; + } + + private static String getPropertyName(String[] rawName) { + String name = rawName[0].toLowerCase(); + + for (int i = 1; i < rawName.length; i++) { + String part = rawName[i]; + + name += new String(new char[] {part.charAt(0)}).toUpperCase() + + part.substring(1).toLowerCase(); + } + + return ("AWT." + name); //$NON-NLS-1$ + } + + private static String[] getPublicStaticFinalIntFieldName(int value) { + Field[] allFields = KeyEvent.class.getDeclaredFields(); + + try { + for (Field field : allFields) { + Class<?> ssalc = field.getType(); + int modifiers = field.getModifiers(); + + if (ssalc.isPrimitive() && ssalc.getName().equals("int") && //$NON-NLS-1$ + Modifier.isFinal(modifiers) && Modifier.isPublic(modifiers) && + Modifier.isStatic(modifiers)) + { + if (field.getInt(null) == value){ + final String name = field.getName(); + final int prefixLength = name.indexOf("_") + 1; + return name.substring(prefixLength).split("_"); //$NON-NLS-1$ + } + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } + + return null; + } + + @Deprecated + public KeyEvent(Component src, int id, + long when, int modifiers, + int keyCode) { + this(src, id, when, modifiers, keyCode, + (keyCode > (2 << 7) - 1) ? CHAR_UNDEFINED : (char) keyCode); + } + + public KeyEvent(Component src, int id, + long when, int modifiers, + int keyCode, char keyChar) { + this(src, id, when, modifiers, keyCode, keyChar, KEY_LOCATION_UNKNOWN); + } + + public KeyEvent(Component src, int id, + long when, int modifiers, + int keyCode, char keyChar, + int keyLocation) { + super(src, id, when, modifiers); + + if (id == KEY_TYPED) { + if (keyCode != VK_UNDEFINED) { + // awt.191=Invalid keyCode for KEY_TYPED event, must be VK_UNDEFINED + throw new IllegalArgumentException(Messages.getString("awt.191")); //$NON-NLS-1$ + } + if (keyChar == CHAR_UNDEFINED) { + // awt.192=Invalid keyChar for KEY_TYPED event, can't be CHAR_UNDEFINED + throw new IllegalArgumentException(Messages.getString("awt.192")); //$NON-NLS-1$ + } + } + + if ((keyLocation < KEY_LOCATION_UNKNOWN) + || (keyLocation > KEY_LOCATION_NUMPAD)) { + // awt.297=Invalid keyLocation + throw new IllegalArgumentException(Messages.getString("awt.297")); //$NON-NLS-1$ + } + + this.keyChar = keyChar; + this.keyLocation = keyLocation; + this.keyCode = keyCode; + } + + public int getKeyCode() { + return keyCode; + } + + public void setKeyCode(int keyCode) { + this.keyCode = keyCode; + } + + public char getKeyChar() { + return keyChar; + } + + public void setKeyChar(char keyChar) { + this.keyChar = keyChar; + } + + public int getKeyLocation() { + return keyLocation; + } + + @Override + @Deprecated + public void setModifiers(int modifiers) { + super.setModifiers(modifiers); + } + + public boolean isActionKey() { + return ((keyChar == CHAR_UNDEFINED) && (keyCode != VK_UNDEFINED) && + !((keyCode == VK_ALT) || (keyCode == VK_ALT_GRAPH) || + (keyCode == VK_CONTROL) || (keyCode == VK_META) || (keyCode == VK_SHIFT))); + } + + @Override + public String paramString() { + /* + * The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * KeyEvent e = new KeyEvent(new Component() {}, + * KeyEvent.KEY_PRESSED, 0, + * KeyEvent.CTRL_DOWN_MASK|KeyEvent.SHIFT_DOWN_MASK, + * KeyEvent.VK_A, 'A', KeyEvent.KEY_LOCATION_STANDARD); + * System.out.println(e); + */ + + String idString = null; + String locString = null; + String paramString = null; + String keyCharString = (keyChar == '\n') ? + keyCharString = getKeyText(VK_ENTER) : "'" + keyChar + "'"; //$NON-NLS-1$ //$NON-NLS-2$ + + switch (id) { + case KEY_PRESSED: + idString = "KEY_PRESSED"; //$NON-NLS-1$ + break; + case KEY_RELEASED: + idString = "KEY_RELEASED"; //$NON-NLS-1$ + break; + case KEY_TYPED: + idString = "KEY_TYPED"; //$NON-NLS-1$ + break; + default: + idString = "unknown type"; //$NON-NLS-1$ + } + + switch(keyLocation){ + case KEY_LOCATION_STANDARD: + locString = "KEY_LOCATION_STANDARD"; //$NON-NLS-1$ + break; + case KEY_LOCATION_LEFT: + locString = "KEY_LOCATION_LEFT"; //$NON-NLS-1$ + break; + case KEY_LOCATION_RIGHT: + locString = "KEY_LOCATION_RIGHT"; //$NON-NLS-1$ + break; + case KEY_LOCATION_NUMPAD: + locString = "KEY_LOCATION_NUMPAD"; //$NON-NLS-1$ + break; + case KEY_LOCATION_UNKNOWN: + locString = "KEY_LOCATION_UNKNOWN"; //$NON-NLS-1$ + break; + default: + locString = "unknown type"; //$NON-NLS-1$ + } + + paramString = idString + ",keyCode=" + keyCode; //$NON-NLS-1$ + if (isActionKey()) { + paramString += "," + getKeyText(keyCode); //$NON-NLS-1$ + } else { + paramString += ",keyChar=" + keyCharString; //$NON-NLS-1$ + } + if (getModifiersEx() > 0) { + paramString += ",modifiers=" + getModifiersExText(getModifiersEx()) + //$NON-NLS-1$ + ",extModifiers=" + getModifiersExText(getModifiersEx()); //$NON-NLS-1$ + } + paramString += ",keyLocation=" + locString; //$NON-NLS-1$ + + return paramString; + } + +} diff --git a/awt/java/awt/event/KeyListener.java b/awt/java/awt/event/KeyListener.java new file mode 100644 index 0000000..ec144df --- /dev/null +++ b/awt/java/awt/event/KeyListener.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface KeyListener extends EventListener { + + public void keyPressed(KeyEvent e); + + public void keyReleased(KeyEvent e); + + public void keyTyped(KeyEvent e); + +} diff --git a/awt/java/awt/event/MouseAdapter.java b/awt/java/awt/event/MouseAdapter.java new file mode 100644 index 0000000..dc19173 --- /dev/null +++ b/awt/java/awt/event/MouseAdapter.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public abstract class MouseAdapter implements MouseListener { + + public MouseAdapter() { + } + + public void mouseClicked(MouseEvent e) { + } + + public void mouseEntered(MouseEvent e) { + } + + public void mouseExited(MouseEvent e) { + } + + public void mousePressed(MouseEvent e) { + } + + public void mouseReleased(MouseEvent e) { + } + +} diff --git a/awt/java/awt/event/MouseEvent.java b/awt/java/awt/event/MouseEvent.java new file mode 100644 index 0000000..2b1fa8b --- /dev/null +++ b/awt/java/awt/event/MouseEvent.java @@ -0,0 +1,232 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.Component; +import java.awt.Point; +import java.awt.Toolkit; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class MouseEvent extends InputEvent { + + private static final long serialVersionUID = -991214153494842848L; + + public static final int MOUSE_FIRST = 500; + + public static final int MOUSE_LAST = 507; + + public static final int MOUSE_CLICKED = 500; + + public static final int MOUSE_PRESSED = 501; + + public static final int MOUSE_RELEASED = 502; + + public static final int MOUSE_MOVED = 503; + + public static final int MOUSE_ENTERED = 504; + + public static final int MOUSE_EXITED = 505; + + public static final int MOUSE_DRAGGED = 506; + + public static final int MOUSE_WHEEL = 507; + + public static final int NOBUTTON = 0; + + public static final int BUTTON1 = 1; + + public static final int BUTTON2 = 2; + + public static final int BUTTON3 = 3; + + private boolean popupTrigger; + private int clickCount; + private int button; + private int x; + private int y; + + public static String getMouseModifiersText(int modifiers) { + final StringBuffer text = new StringBuffer(); + + if ((modifiers & META_MASK) != 0) { + text.append(Toolkit.getProperty("AWT.meta", "Meta")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + if ((modifiers & SHIFT_MASK) != 0) { + text.append(Toolkit.getProperty("AWT.shift", "Shift")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + if ((modifiers & CTRL_MASK) != 0) { + text.append(Toolkit.getProperty("AWT.control", "Ctrl")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + if ((modifiers & ALT_MASK) != 0) { + text.append(Toolkit.getProperty("AWT.alt", "Alt")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + if ((modifiers & ALT_GRAPH_MASK) != 0) { + text.append(Toolkit.getProperty("AWT.altGraph", "Alt Graph")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + if ((modifiers & BUTTON1_MASK) != 0) { + text.append(Toolkit.getProperty("AWT.button1", "Button1")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + if ((modifiers & BUTTON2_MASK) != 0) { + text.append(Toolkit.getProperty("AWT.button2", "Button2")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + if ((modifiers & BUTTON3_MASK) != 0) { + text.append(Toolkit.getProperty("AWT.button3", "Button3")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + return text.length() == 0 ? text.toString() : text.substring(0, text + .length() - 1); + } + + static String addMouseModifiersExText(String text, int modifiersEx) { + if ((modifiersEx & InputEvent.BUTTON1_DOWN_MASK) != 0) { + text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$ + Toolkit.getProperty("AWT.button1", "Button1"); //$NON-NLS-1$ //$NON-NLS-2$ + } + if ((modifiersEx & InputEvent.BUTTON2_DOWN_MASK) != 0) { + text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$ + Toolkit.getProperty("AWT.button2", "Button2"); //$NON-NLS-1$ //$NON-NLS-2$ + } + if ((modifiersEx & InputEvent.BUTTON3_DOWN_MASK) != 0) { + text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$ + Toolkit.getProperty("AWT.button3", "Button3"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + return text; + } + + public MouseEvent(Component source, int id, long when, + int modifiers, int x, int y, + int clickCount, boolean popupTrigger) { + this(source, id, when, modifiers, x, y, + clickCount, popupTrigger, NOBUTTON); + } + + public MouseEvent(Component source, int id, long when, + int modifiers, int x, int y, + int clickCount, boolean popupTrigger, int button) { + super(source, id, when, modifiers); + + if ((button != NOBUTTON) && (button != BUTTON1) && + (button != BUTTON2) && (button != BUTTON3)) { + // awt.18B=Invalid button value + throw new IllegalArgumentException(Messages.getString("awt.18B")); //$NON-NLS-1$ + } + + this.popupTrigger = popupTrigger; + this.clickCount = clickCount; + this.button = button; + this.x = x; + this.y = y; + } + + public int getButton() { + return button; + } + + public int getClickCount() { + return clickCount; + } + + public Point getPoint() { + return new Point(x, y); + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public boolean isPopupTrigger() { + return popupTrigger; + } + + public void translatePoint(int x, int y) { + this.x += x; + this.y += y; + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * MouseEvent e = new MouseEvent(new Component(){}, + * MouseEvent.MOUSE_PRESSED, 0, + * MouseEvent.BUTTON1_DOWN_MASK|MouseEvent.CTRL_DOWN_MASK, + * 10, 20, 1, false, MouseEvent.BUTTON1); + * System.out.println(e); + */ + + String idString = null; + String paramString = null; + + switch (id) { + case MOUSE_MOVED: + idString = "MOUSE_MOVED"; //$NON-NLS-1$ + break; + case MOUSE_CLICKED: + idString = "MOUSE_CLICKED"; //$NON-NLS-1$ + break; + case MOUSE_PRESSED: + idString = "MOUSE_PRESSED"; //$NON-NLS-1$ + break; + case MOUSE_RELEASED: + idString = "MOUSE_RELEASED"; //$NON-NLS-1$ + break; + case MOUSE_DRAGGED: + idString = "MOUSE_DRAGGED"; //$NON-NLS-1$ + break; + case MOUSE_ENTERED: + idString = "MOUSE_ENTERED"; //$NON-NLS-1$ + break; + case MOUSE_EXITED: + idString = "MOUSE_EXITED"; //$NON-NLS-1$ + break; + case MOUSE_WHEEL: + idString = "MOUSE_WHEEL"; //$NON-NLS-1$ + break; + default: + idString = "unknown type"; //$NON-NLS-1$ + } + + paramString = idString + ",(" + getX() + "," + getY() + ")" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + ",button=" + button; //$NON-NLS-1$ + if (getModifiersEx() > 0) { + paramString += + ",modifiers=" + getModifiersExText(getModifiersEx()) + //$NON-NLS-1$ + ",extModifiers=" + getModifiersExText(getModifiersEx()); //$NON-NLS-1$ + } + paramString += ",clickCount=" + getClickCount(); //$NON-NLS-1$ + + return paramString; + } + +} diff --git a/awt/java/awt/event/MouseListener.java b/awt/java/awt/event/MouseListener.java new file mode 100644 index 0000000..95879b9 --- /dev/null +++ b/awt/java/awt/event/MouseListener.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface MouseListener extends EventListener { + + public void mouseClicked(MouseEvent e); + + public void mouseEntered(MouseEvent e); + + public void mouseExited(MouseEvent e); + + public void mousePressed(MouseEvent e); + + public void mouseReleased(MouseEvent e); + +} diff --git a/awt/java/awt/event/MouseMotionAdapter.java b/awt/java/awt/event/MouseMotionAdapter.java new file mode 100644 index 0000000..1ecd0d5 --- /dev/null +++ b/awt/java/awt/event/MouseMotionAdapter.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public abstract class MouseMotionAdapter implements MouseMotionListener { + + public MouseMotionAdapter() { + } + + public void mouseDragged(MouseEvent e) { + } + + public void mouseMoved(MouseEvent e) { + } + +} diff --git a/awt/java/awt/event/MouseMotionListener.java b/awt/java/awt/event/MouseMotionListener.java new file mode 100644 index 0000000..e1313c3 --- /dev/null +++ b/awt/java/awt/event/MouseMotionListener.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface MouseMotionListener extends EventListener { + + public void mouseDragged(MouseEvent e); + + public void mouseMoved(MouseEvent e); + +} diff --git a/awt/java/awt/event/MouseWheelEvent.java b/awt/java/awt/event/MouseWheelEvent.java new file mode 100644 index 0000000..a3ed424 --- /dev/null +++ b/awt/java/awt/event/MouseWheelEvent.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.Component; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class MouseWheelEvent extends MouseEvent { + + private static final long serialVersionUID = -9187413581993563929L; + + public static final int WHEEL_UNIT_SCROLL = 0; + + public static final int WHEEL_BLOCK_SCROLL = 1; + + private int wheelRotation; + private int scrollAmount; + private int scrollType; + + public MouseWheelEvent(Component source, int id, long when, int modifiers, + int x, int y, int clickCount, boolean popupTrigger, int scrollType, + int scrollAmount, int wheelRotation) { + super(source, id, when, modifiers, x, y, clickCount, popupTrigger); + + this.scrollType = scrollType; + this.scrollAmount = scrollAmount; + this.wheelRotation = wheelRotation; + } + + public int getScrollAmount() { + return scrollAmount; + } + + public int getScrollType() { + return scrollType; + } + + public int getWheelRotation() { + return wheelRotation; + } + + public int getUnitsToScroll() { + return (scrollAmount * wheelRotation); + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * MouseWheelEvent e = new MouseWheelEvent(new Component(){}, + * MouseWheelEvent.MOUSE_WHEEL, 0, + * MouseEvent.BUTTON1_DOWN_MASK|MouseEvent.CTRL_DOWN_MASK, + * 10, 20, 1, false, MouseWheelEvent.WHEEL_UNIT_SCROLL, + * 1, 3); + * System.out.println(e); + */ + + String paramString = super.paramString(); + String typeString = null; + + switch (scrollType) { + case WHEEL_UNIT_SCROLL: + typeString = "WHEEL_UNIT_SCROLL"; //$NON-NLS-1$ + break; + case WHEEL_BLOCK_SCROLL: + typeString = "WHEEL_BLOCK_SCROLL"; //$NON-NLS-1$ + break; + default: + typeString = "unknown type"; //$NON-NLS-1$ + } + + paramString += ",scrollType=" + typeString + //$NON-NLS-1$ + ",scrollAmount=" + scrollAmount + //$NON-NLS-1$ + ",wheelRotation=" + wheelRotation; //$NON-NLS-1$ + + return paramString; + } + +} diff --git a/awt/java/awt/event/MouseWheelListener.java b/awt/java/awt/event/MouseWheelListener.java new file mode 100644 index 0000000..2d6a982 --- /dev/null +++ b/awt/java/awt/event/MouseWheelListener.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface MouseWheelListener extends EventListener { + + public void mouseWheelMoved(MouseWheelEvent e); + +} diff --git a/awt/java/awt/event/PaintEvent.java b/awt/java/awt/event/PaintEvent.java new file mode 100644 index 0000000..22ac090 --- /dev/null +++ b/awt/java/awt/event/PaintEvent.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.Component; +import java.awt.Rectangle; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class PaintEvent extends ComponentEvent { + + private static final long serialVersionUID = 1267492026433337593L; + + public static final int PAINT_FIRST = 800; + + public static final int PAINT_LAST = 801; + + public static final int PAINT = 800; + + public static final int UPDATE = 801; + + private Rectangle updateRect; + + public PaintEvent(Component source, int id, Rectangle updateRect) { + super(source, id); + + this.updateRect = updateRect; + } + + public Rectangle getUpdateRect() { + return updateRect; + } + + public void setUpdateRect(Rectangle updateRect) { + this.updateRect = updateRect; + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * PaintEvent e = new PaintEvent(new Component(){}, + * PaintEvent.PAINT, new Rectangle(0, 0, 10, 20)); + * System.out.println(e); + */ + + String typeString = null; + + switch (id) { + case PAINT: + typeString = "PAINT"; //$NON-NLS-1$ + break; + case UPDATE: + typeString = "UPDATE"; //$NON-NLS-1$ + break; + default: + typeString = "unknown type"; //$NON-NLS-1$ + } + + return typeString + ",updateRect=" + updateRect; //$NON-NLS-1$ + } + +} diff --git a/awt/java/awt/event/TextEvent.java b/awt/java/awt/event/TextEvent.java new file mode 100644 index 0000000..2a690ad --- /dev/null +++ b/awt/java/awt/event/TextEvent.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.AWTEvent; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class TextEvent extends AWTEvent { + + private static final long serialVersionUID = 6269902291250941179L; + + public static final int TEXT_FIRST = 900; + + public static final int TEXT_LAST = 900; + + public static final int TEXT_VALUE_CHANGED = 900; + + public TextEvent(Object src, int id) { + super(src, id); + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * TextEvent e = new TextEvent(new Component(){}, + * TextEvent.TEXT_VALUE_CHANGED); + * System.out.println(e); + */ + + return (id == TEXT_VALUE_CHANGED) ? + "TEXT_VALUE_CHANGED" : "unknown type"; //$NON-NLS-1$ //$NON-NLS-2$ + } + +} diff --git a/awt/java/awt/event/TextListener.java b/awt/java/awt/event/TextListener.java new file mode 100644 index 0000000..05757c4 --- /dev/null +++ b/awt/java/awt/event/TextListener.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface TextListener extends EventListener { + + public void textValueChanged(TextEvent e); + +} + diff --git a/awt/java/awt/event/WindowAdapter.java b/awt/java/awt/event/WindowAdapter.java new file mode 100644 index 0000000..970aa8d --- /dev/null +++ b/awt/java/awt/event/WindowAdapter.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public abstract class WindowAdapter implements WindowListener, WindowStateListener, WindowFocusListener { + + public WindowAdapter() { + } + + public void windowActivated(WindowEvent e) { + } + + public void windowClosed(WindowEvent e) { + } + + public void windowClosing(WindowEvent e) { + } + + public void windowDeactivated(WindowEvent e) { + } + + public void windowDeiconified(WindowEvent e) { + } + + public void windowGainedFocus(WindowEvent e) { + } + + public void windowIconified(WindowEvent e) { + } + + public void windowLostFocus(WindowEvent e) { + } + + public void windowOpened(WindowEvent e) { + } + + public void windowStateChanged(WindowEvent e) { + } + +} diff --git a/awt/java/awt/event/WindowEvent.java b/awt/java/awt/event/WindowEvent.java new file mode 100644 index 0000000..474d2ac --- /dev/null +++ b/awt/java/awt/event/WindowEvent.java @@ -0,0 +1,168 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + + +//???AWT +//import java.awt.Window; +//import java.awt.Frame; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class WindowEvent extends ComponentEvent { + + private static final long serialVersionUID = -1567959133147912127L; + + public static final int WINDOW_FIRST = 200; + + public static final int WINDOW_OPENED = 200; + + public static final int WINDOW_CLOSING = 201; + + public static final int WINDOW_CLOSED = 202; + + public static final int WINDOW_ICONIFIED = 203; + + public static final int WINDOW_DEICONIFIED = 204; + + public static final int WINDOW_ACTIVATED = 205; + + public static final int WINDOW_DEACTIVATED = 206; + + public static final int WINDOW_GAINED_FOCUS = 207; + + public static final int WINDOW_LOST_FOCUS = 208; + + public static final int WINDOW_STATE_CHANGED = 209; + + public static final int WINDOW_LAST = 209; + + //???AWT: private Window oppositeWindow; + private int oldState; + private int newState; + + //???AWT + /* + public WindowEvent(Window source, int id) { + this(source, id, null); + } + + public WindowEvent(Window source, int id, Window opposite) { + this(source, id, opposite, Frame.NORMAL, Frame.NORMAL); + } + + public WindowEvent(Window source, int id, int oldState, int newState) { + this(source, id, null, oldState, newState); + } + + public WindowEvent(Window source, int id, Window opposite, + int oldState, int newState) { + super(source, id); + + oppositeWindow = opposite; + this.oldState = oldState; + this.newState = newState; + } + */ + //???AWT: Fake constructor + public WindowEvent() { + super(null, 0); + } + + public int getNewState() { + return newState; + } + + public int getOldState() { + return oldState; + } + + //???AWT + /* + public Window getOppositeWindow() { + return oppositeWindow; + } + + public Window getWindow() { + return (Window) source; + } + */ + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * WindowEvent e = new WindowEvent(new Frame(), + * WindowEvent.WINDOW_OPENED); + * System.out.println(e); + */ + + String typeString = null; + + switch (id) { + case WINDOW_OPENED: + typeString = "WINDOW_OPENED"; //$NON-NLS-1$ + break; + case WINDOW_CLOSING: + typeString = "WINDOW_CLOSING"; //$NON-NLS-1$ + break; + case WINDOW_CLOSED: + typeString = "WINDOW_CLOSED"; //$NON-NLS-1$ + break; + case WINDOW_ICONIFIED: + typeString = "WINDOW_ICONIFIED"; //$NON-NLS-1$ + break; + case WINDOW_DEICONIFIED: + typeString = "WINDOW_DEICONIFIED"; //$NON-NLS-1$ + break; + case WINDOW_ACTIVATED: + typeString = "WINDOW_ACTIVATED"; //$NON-NLS-1$ + break; + case WINDOW_DEACTIVATED: + typeString = "WINDOW_DEACTIVATED"; //$NON-NLS-1$ + break; + case WINDOW_GAINED_FOCUS: + typeString = "WINDOW_GAINED_FOCUS"; //$NON-NLS-1$ + break; + case WINDOW_LOST_FOCUS: + typeString = "WINDOW_LOST_FOCUS"; //$NON-NLS-1$ + break; + case WINDOW_STATE_CHANGED: + typeString = "WINDOW_STATE_CHANGED"; //$NON-NLS-1$ + break; + default: + typeString = "unknown type"; //$NON-NLS-1$ + } + + //???AWT + /* + return typeString + ",opposite=" + oppositeWindow + //$NON-NLS-1$ + ",oldState=" + oldState + ",newState=" + newState; //$NON-NLS-1$ //$NON-NLS-2$ + */ + return typeString; + } + +} diff --git a/awt/java/awt/event/WindowFocusListener.java b/awt/java/awt/event/WindowFocusListener.java new file mode 100644 index 0000000..528459f --- /dev/null +++ b/awt/java/awt/event/WindowFocusListener.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface WindowFocusListener extends EventListener { + + public void windowGainedFocus(WindowEvent e); + + public void windowLostFocus(WindowEvent e); + +} diff --git a/awt/java/awt/event/WindowListener.java b/awt/java/awt/event/WindowListener.java new file mode 100644 index 0000000..31bd547 --- /dev/null +++ b/awt/java/awt/event/WindowListener.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface WindowListener extends EventListener { + + public void windowActivated(WindowEvent e); + + public void windowClosed(WindowEvent e); + + public void windowClosing(WindowEvent e); + + public void windowDeactivated(WindowEvent e); + + public void windowDeiconified(WindowEvent e); + + public void windowIconified(WindowEvent e); + + public void windowOpened(WindowEvent e); + +} diff --git a/awt/java/awt/event/WindowStateListener.java b/awt/java/awt/event/WindowStateListener.java new file mode 100644 index 0000000..ba14d9e --- /dev/null +++ b/awt/java/awt/event/WindowStateListener.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface WindowStateListener extends EventListener { + + public void windowStateChanged(WindowEvent e); + +} + diff --git a/awt/java/awt/font/FontRenderContext.java b/awt/java/awt/font/FontRenderContext.java new file mode 100644 index 0000000..d7de00f --- /dev/null +++ b/awt/java/awt/font/FontRenderContext.java @@ -0,0 +1,178 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ +package java.awt.font; + +import java.awt.geom.AffineTransform; + +/** + * The FontRenderContext class contains the information about text measurement. + * Anti-aliasing and fractional-metrics modes are defined by an application and + * affect the size of a character. + * + * @since Android 1.0 + */ +public class FontRenderContext { + + // Affine transform of this mode + /** + * The transform. + */ + private AffineTransform transform; + + // Is the anti-aliased mode used + /** + * The anti aliased. + */ + private boolean fAntiAliased; + + // Is the fractional metrics used + /** + * The fractional metrics. + */ + private boolean fFractionalMetrics; + + + /** + * Instantiates a new FontRenderContext object with the specified + * AffineTransform, anti-aliasing and fractional metrics flags. + * + * @param trans + * the AffineTransform. + * @param antiAliased + * the anti-aliasing flag. + * @param usesFractionalMetrics + * the fractional metrics flag. + */ + public FontRenderContext(AffineTransform trans, boolean antiAliased, + boolean usesFractionalMetrics) { + if (trans != null){ + transform = new AffineTransform(trans); + } + fAntiAliased = antiAliased; + fFractionalMetrics = usesFractionalMetrics; + } + + /** + * Instantiates a new FontRenderContext object. + */ + protected FontRenderContext() { + } + + /** + * Compares the specified Object with current FontRenderContext object. + * + * @param obj + * the Object to be compared. + * @return true, if the specified Object is equal to current + * FontRenderContext object. + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + + if (obj != null) { + try { + return equals((FontRenderContext) obj); + } catch (ClassCastException e) { + return false; + } + } + return false; + + } + + /** + * Gets the transform which is used for scaling typographical points to + * pixels in this FontRenderContext. + * + * @return the AffineTransform which is used for scaling typographical + * points to pixels in this FontRenderContext. + */ + public AffineTransform getTransform() { + if (transform != null){ + return new AffineTransform(transform); + } + return new AffineTransform(); + } + + /** + * Compares the specified FontRenderContext object with current + * FontRenderContext. + * + * @param frc + * the FontRenderContext object to be compared. + * @return true, if the specified FontRenderContext object is equal to + * current FontRenderContext. + */ + public boolean equals(FontRenderContext frc) { + if (this == frc){ + return true; + } + + if (frc == null){ + return false; + } + + if (!frc.getTransform().equals(this.getTransform()) && + !frc.isAntiAliased() == this.fAntiAliased && + !frc.usesFractionalMetrics() == this.fFractionalMetrics){ + return false; + } + return true; + } + + /** + * Returns true if the text fractional metrics are used in this + * FontRenderContext. + * + * @return true, if the text fractional metrics are used in this + * FontRenderContext, false otherwise. + */ + public boolean usesFractionalMetrics() { + return this.fFractionalMetrics; + } + + /** + * Returns true if anti-aliasing is used in this FontRenderContext. + * + * @return true, if is anti-aliasing is used in this FontRenderContext, + * false otherwise. + */ + public boolean isAntiAliased() { + return this.fAntiAliased; + } + + /** + * Returns hash code of the FontRenderContext object. + * + * @return the hash code of the FontRenderContext object. + */ + @Override + public int hashCode() { + return this.getTransform().hashCode() ^ + new Boolean(this.fFractionalMetrics).hashCode() ^ + new Boolean(this.fAntiAliased).hashCode(); + } + +} + diff --git a/awt/java/awt/font/GlyphJustificationInfo.java b/awt/java/awt/font/GlyphJustificationInfo.java new file mode 100644 index 0000000..b03de0a --- /dev/null +++ b/awt/java/awt/font/GlyphJustificationInfo.java @@ -0,0 +1,197 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The GlyphJustificationInfo class provides information about the glyph's + * justification properties. There are four justification properties: weight, + * priority, absorb, and limit. + * <p> + * There are two sets of metrics: growing and shrinking. Growing metrics are + * used when the glyphs are to be spread apart to fit a larger width. Shrinking + * metrics are used when the glyphs are to be moved together to fit a smaller + * width. + * </p> + * + * @since Android 1.0 + */ +public final class GlyphJustificationInfo { + + /** + * The Constant PRIORITY_KASHIDA indicates the highest justification + * priority. + */ + public static final int PRIORITY_KASHIDA = 0; + + /** + * The Constant PRIORITY_WHITESPACE indicates the second highest + * justification priority. + */ + public static final int PRIORITY_WHITESPACE = 1; + + /** + * The Constant PRIORITY_INTERCHAR indicates the second lowest justification + * priority. + */ + public static final int PRIORITY_INTERCHAR = 2; + + /** + * The Constant PRIORITY_NONE indicates the lowest justification priority. + */ + public static final int PRIORITY_NONE = 3; + + /** + * The grow absorb flag indicates if this glyph absorbs all extra space at + * this and lower priority levels when it grows. + */ + public final boolean growAbsorb; + + /** + * The grow left limit value represents the maximum value by which the left + * side of this glyph grows. + */ + public final float growLeftLimit; + + /** + * The grow right limit value repesents the maximum value by which the right + * side of this glyph grows. + */ + public final float growRightLimit; + + /** + * The grow priority value represents the priority level of this glyph as it + * is growing. + */ + public final int growPriority; + + /** + * The shrink absorb fleg indicates this glyph absorbs all remaining + * shrinkage at this and lower priority levels as it shrinks. + */ + public final boolean shrinkAbsorb; + + /** + * The shrink left limit value represents the maximum value by which the + * left side of this glyph shrinks. + */ + public final float shrinkLeftLimit; + + /** + * The shrink right limit value represents the maximum value by which the + * right side of this glyph shrinks. + */ + public final float shrinkRightLimit; + + /** + * The shrink priority represents the glyth's priority level as it is + * shrinking. + */ + public final int shrinkPriority; + + /** + * The weight of the glyph. + */ + public final float weight; + + /** + * Instantiates a new GlyphJustificationInfo object which contains glyph's + * justification properties. + * + * @param weight + * the weight of glyph. + * @param growAbsorb + * indicates if this glyph contais all space at this priority and + * lower priority levels when it grows. + * @param growPriority + * indicates the priority level of this glyph when it grows. + * @param growLeftLimit + * indicates the maximum value of which the left side of this + * glyph can grow. + * @param growRightLimit + * the maximum value of which the right side of this glyph can + * grow. + * @param shrinkAbsorb + * indicates if this glyph contains all remaining shrinkage at + * this and lower priority levels when it shrinks. + * @param shrinkPriority + * indicates the glyph's priority level when it shrinks. + * @param shrinkLeftLimit + * indicates the maximum value of which the left side of this + * glyph can shrink. + * @param shrinkRightLimit + * indicates the maximum amount by which the right side of this + * glyph can shrink. + */ + public GlyphJustificationInfo(float weight, boolean growAbsorb, int growPriority, + float growLeftLimit, float growRightLimit, boolean shrinkAbsorb, int shrinkPriority, + float shrinkLeftLimit, float shrinkRightLimit) { + + if (weight < 0) { + // awt.19C=weight must be a positive number + throw new IllegalArgumentException(Messages.getString("awt.19C")); //$NON-NLS-1$ + } + this.weight = weight; + + if (growLeftLimit < 0) { + // awt.19D=growLeftLimit must be a positive number + throw new IllegalArgumentException(Messages.getString("awt.19D")); //$NON-NLS-1$ + } + this.growLeftLimit = growLeftLimit; + + if (growRightLimit < 0) { + // awt.19E=growRightLimit must be a positive number + throw new IllegalArgumentException(Messages.getString("awt.19E")); //$NON-NLS-1$ + } + this.growRightLimit = growRightLimit; + + if ((shrinkPriority < 0) || (shrinkPriority > PRIORITY_NONE)) { + // awt.19F=incorrect value for shrinkPriority, more than + // PRIORITY_NONE or less than PRIORITY_KASHIDA value + throw new IllegalArgumentException(Messages.getString("awt.19F")); //$NON-NLS-1$ + } + this.shrinkPriority = shrinkPriority; + + if ((growPriority < 0) || (growPriority > PRIORITY_NONE)) { + // awt.200=incorrect value for growPriority, more than PRIORITY_NONE + // or less than PRIORITY_KASHIDA value + throw new IllegalArgumentException(Messages.getString("awt.200")); //$NON-NLS-1$ + } + this.growPriority = growPriority; + + if (shrinkLeftLimit < 0) { + // awt.201=shrinkLeftLimit must be a positive number + throw new IllegalArgumentException(Messages.getString("awt.201")); //$NON-NLS-1$ + } + this.shrinkLeftLimit = shrinkLeftLimit; + + if (shrinkRightLimit < 0) { + // awt.202=shrinkRightLimit must be a positive number + throw new IllegalArgumentException(Messages.getString("awt.202")); //$NON-NLS-1$ + } + this.shrinkRightLimit = shrinkRightLimit; + + this.shrinkAbsorb = shrinkAbsorb; + this.growAbsorb = growAbsorb; + } +} diff --git a/awt/java/awt/font/GlyphMetrics.java b/awt/java/awt/font/GlyphMetrics.java new file mode 100644 index 0000000..2871722 --- /dev/null +++ b/awt/java/awt/font/GlyphMetrics.java @@ -0,0 +1,266 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.geom.Rectangle2D; + +/** + * The GlyphMetrics class provides information about the size and shape of a + * single glyph. Each glyph has information to specify whether its baseline is + * horizontal or vertical as well as information on how it interacts with other + * characters in a text, given as one of the following types: STANDARD, + * LIGATURE, COMBINING, or COMPONENT. + * + * @since Android 1.0 + */ +public final class GlyphMetrics { + + // advance width of the glyph character cell + /** + * The advance x. + */ + private float advanceX; + + // advance height of the glyph character cell + /** + * The advance y. + */ + private float advanceY; + + // flag if the glyph horizontal + /** + * The horizontal. + */ + private boolean horizontal; + + // glyph type code + /** + * The glyph type. + */ + private byte glyphType; + + // bounding box for outline of the glyph + /** + * The bounds. + */ + private Rectangle2D.Float bounds; + + /** + * The Constant STANDARD indicates a glyph that represents a single + * character. + */ + public static final byte STANDARD = 0; + + /** + * The Constant LIGATURE indicates a glyph that represents multiple + * characters as a ligature. + */ + public static final byte LIGATURE = 1; + + /** + * The Constant COMBINING indicates a glyph which has no caret position + * between glyphs (for example umlaut). + */ + public static final byte COMBINING = 2; + + /** + * The Constant COMPONENT indicates a glyph with no corresponding character + * in the backing store. + */ + public static final byte COMPONENT = 3; + + /** + * The Constant WHITESPACE indicates a glyph without visual representation. + */ + public static final byte WHITESPACE = 4; + + /** + * Instantiates a new GlyphMetrics object with the specified parameters. + * + * @param horizontal + * specifies if metrics are for a horizontal baseline (true + * value), or a vertical baseline (false value). + * @param advanceX + * the X component of the glyph's advance. + * @param advanceY + * the Y component of the glyph's advance. + * @param bounds + * the glyph's bounds. + * @param glyphType + * the glyph's type. + */ + public GlyphMetrics(boolean horizontal, float advanceX, float advanceY, Rectangle2D bounds, + byte glyphType) { + this.horizontal = horizontal; + this.advanceX = advanceX; + this.advanceY = advanceY; + + this.bounds = new Rectangle2D.Float(); + this.bounds.setRect(bounds); + + this.glyphType = glyphType; + } + + /** + * Instantiates a new horizontal GlyphMetrics with the specified parameters. + * + * @param advanceX + * the X component of the glyph's advance. + * @param bounds + * the glyph's bounds. + * @param glyphType + * the glyph's type. + */ + public GlyphMetrics(float advanceX, Rectangle2D bounds, byte glyphType) { + this.advanceX = advanceX; + this.advanceY = 0; + + this.horizontal = true; + + this.bounds = new Rectangle2D.Float(); + this.bounds.setRect(bounds); + + this.glyphType = glyphType; + } + + /** + * Gets the glyph's bounds. + * + * @return glyph's bounds. + */ + public Rectangle2D getBounds2D() { + return (Rectangle2D.Float)this.bounds.clone(); + } + + /** + * Checks if this glyph is whitespace or not. + * + * @return true, if this glyph is whitespace, false otherwise. + */ + public boolean isWhitespace() { + return ((this.glyphType & 4) == WHITESPACE); + } + + /** + * Checks if this glyph is standard or not. + * + * @return true, if this glyph is standard, false otherwise. + */ + public boolean isStandard() { + return ((this.glyphType & 3) == STANDARD); + } + + /** + * Checks if this glyph is ligature or not. + * + * @return true, if this glyph is ligature, false otherwise. + */ + public boolean isLigature() { + return ((this.glyphType & 3) == LIGATURE); + } + + /** + * Checks if this glyph is component or not. + * + * @return true, if this glyph is component, false otherwise. + */ + public boolean isComponent() { + return ((this.glyphType & 3) == COMPONENT); + } + + /** + * Checks if this glyph is combining or not. + * + * @return true, if this glyph is combining, false otherwise. + */ + public boolean isCombining() { + return ((this.glyphType & 3) == COMBINING); + } + + /** + * Gets the glyph's type. + * + * @return the glyph's type. + */ + public int getType() { + return this.glyphType; + } + + /** + * Gets the distance from the right (for horizontal) or bottom (for + * vertical) of the glyph bounds to the advance. + * + * @return the distance from the right (for horizontal) or bottom (for + * vertical) of the glyph bounds to the advance. + */ + public float getRSB() { + if (this.horizontal) { + return this.advanceX - this.bounds.x - (float)this.bounds.getWidth(); + } + return this.advanceY - this.bounds.y - (float)this.bounds.getHeight(); + } + + /** + * Gets the distance from 0, 0 to the left (for horizontal) or top (for + * vertical) of the glyph bounds. + * + * @return the distance from 0, 0 to the left (for horizontal) or top (for + * vertical) of the glyph bounds. + */ + public float getLSB() { + if (this.horizontal) { + return this.bounds.x; + } + return this.bounds.y; + } + + /** + * Gets the Y component of the glyph's advance. + * + * @return the Y component of the glyph's advance. + */ + public float getAdvanceY() { + return this.advanceY; + } + + /** + * Gets the X component of the glyph's advance. + * + * @return the X component of the glyph's advance. + */ + public float getAdvanceX() { + return this.advanceX; + } + + /** + * Gets the glyph's advance along the baseline. + * + * @return the glyph's advance. + */ + public float getAdvance() { + if (this.horizontal) { + return this.advanceX; + } + return this.advanceY; + } + +} diff --git a/awt/java/awt/font/GlyphVector.java b/awt/java/awt/font/GlyphVector.java new file mode 100644 index 0000000..a72b774 --- /dev/null +++ b/awt/java/awt/font/GlyphVector.java @@ -0,0 +1,403 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.Font; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphJustificationInfo; +import java.awt.font.GlyphMetrics; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * The GlyphVector class contains a collection of glyphs with geometric + * information and each glyph's location. Each GlyphVector can be associated + * with only one Font. GlyphVector contains the following properties for each + * glyph: + * <ul> + * <li>the glyph position;</li> + * <li>the transform of the glyph;</li> + * <li>the metrics of the glyph in the context of the GlyphVector.</li> + * </ul> + * + * @since Android 1.0 + */ +public abstract class GlyphVector implements Cloneable { + + /** + * The Constant FLAG_HAS_TRANSFORMS indicates that this GlyphVector has + * per-glyph transforms. + */ + public static final int FLAG_HAS_TRANSFORMS = 1; + + /** + * The Constant FLAG_HAS_POSITION_ADJUSTMENTS indicates that the GlyphVector + * has per-glyph position adjustments. + */ + public static final int FLAG_HAS_POSITION_ADJUSTMENTS = 2; + + /** + * The Constant FLAG_RUN_RTL indicates that this GlyphVector has a right to + * left run direction. + */ + public static final int FLAG_RUN_RTL = 4; + + /** + * The Constant FLAG_COMPLEX_GLYPHS indicates that this GlyphVector has a + * complex glyph to char mapping. + */ + public static final int FLAG_COMPLEX_GLYPHS = 8; + + /** + * The Constant FLAG_MASK indicates a mask for supported flags from + * getLayoutFlags. + */ + public static final int FLAG_MASK = 15; // (|) mask of other flags + + /** + * Instantiates a new GlyphVector. + */ + public GlyphVector() { + } + + /** + * Gets the pixel bounds of the GlyphVector when rendered at the specified + * location with the specified FontRenderContext. + * + * @param frc + * the FontRenderContext. + * @param x + * the X coordinate of the GlyphVector's location. + * @param y + * the Y coordinate of the GlyphVector's location. + * @return the pixel bounds + */ + public Rectangle getPixelBounds(FontRenderContext frc, float x, float y) { + // default implementation - integer Rectangle, that encloses visual + // bounds rectangle + Rectangle2D visualRect = getVisualBounds(); + + int minX = (int)Math.floor(visualRect.getMinX() + x); + int minY = (int)Math.floor(visualRect.getMinY() + y); + int width = (int)Math.ceil(visualRect.getMaxX() + x) - minX; + int height = (int)Math.ceil(visualRect.getMaxY() + y) - minY; + + return new Rectangle(minX, minY, width, height); + } + + /** + * Gets the pixel bounds of the glyph with the specified index in this + * GlyphVector which is rendered with the specified FontRenderContext at the + * specified location. + * + * @param index + * the glyph index in this GlyphVector. + * @param frc + * the FontRenderContext. + * @param x + * the X coordinate of the GlyphVector's location. + * @param y + * the Y coordinate of the GlyphVector's location. + * @return a Rectangle bounds. + */ + public Rectangle getGlyphPixelBounds(int index, FontRenderContext frc, float x, float y) { + Rectangle2D visualRect = getGlyphVisualBounds(index).getBounds2D(); + + int minX = (int)Math.floor(visualRect.getMinX() + x); + int minY = (int)Math.floor(visualRect.getMinY() + y); + int width = (int)Math.ceil(visualRect.getMaxX() + x) - minX; + int height = (int)Math.ceil(visualRect.getMaxY() + y) - minY; + + return new Rectangle(minX, minY, width, height); + } + + /** + * Gets the visual bounds of the GlyphVector. + * + * @return the visual bounds of the GlyphVector. + */ + public abstract Rectangle2D getVisualBounds(); + + /** + * Gets the logical bounds of the GlyphVector. + * + * @return the logical bounds of the GlyphVector. + */ + public abstract Rectangle2D getLogicalBounds(); + + /** + * Sets the position of the specified glyph in this GlyphVector. + * + * @param glyphIndex + * the glyph index in this GlyphVector. + * @param newPos + * the new position of the glyph at the specified glyphIndex. + */ + public abstract void setGlyphPosition(int glyphIndex, Point2D newPos); + + /** + * Gets the position of the specified glyph in this GlyphVector. + * + * @param glyphIndex + * the glyph index in this GlyphVector. + * @return the position of the specified glyph in this GlyphVector. + */ + public abstract Point2D getGlyphPosition(int glyphIndex); + + /** + * Sets the affine transform to a glyph with the specified index in this + * GlyphVector. + * + * @param glyphIndex + * the glyth index in this GlyphVector. + * @param trans + * the AffineTransform to be assigned to the specified glyph. + */ + public abstract void setGlyphTransform(int glyphIndex, AffineTransform trans); + + /** + * Gets the transform of the specified glyph in this GlyphVector. + * + * @param glyphIndex + * the glyph index in this GlyphVector. + * @return the new transform of the glyph. + */ + public abstract AffineTransform getGlyphTransform(int glyphIndex); + + /** + * Compares this GlyphVector with the specified GlyphVector objects. + * + * @param glyphVector + * the GlyphVector object to be compared. + * @return true, if this GlyphVector is equal to the specified GlyphVector + * object, false otherwise. + */ + public abstract boolean equals(GlyphVector glyphVector); + + /** + * Gets the metrics of the glyph with the specified index in this + * GlyphVector. + * + * @param glyphIndex + * index in this GlyphVector. + * @return the metrics of the glyph with the specified index in this + * GlyphVector. + */ + public abstract GlyphMetrics getGlyphMetrics(int glyphIndex); + + /** + * Gets the justification information of the glyph whose index is specified. + * + * @param glyphIndex + * the glyph index. + * @return the GlyphJustificationInfo for the specified glyph. + */ + public abstract GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex); + + /** + * Gets the FontRenderContext of this GlyphVector. + * + * @return the FontRenderContext of this GlyphVector. + */ + public abstract FontRenderContext getFontRenderContext(); + + /** + * Gets a Shape object which defines the visual representation of the + * specified glyph in this GlyphVector, translated a distance of x in the X + * direction and y in the Y direction. + * + * @param glyphIndex + * the glyth index in this GlyphVector. + * @param x + * the distance in the X direction to translate the shape object + * before returning it. + * @param y + * the distance in the Y direction to translate the shape object + * before returning it. + * @return a Shape object which represents the visual representation of the + * specified glyph in this GlyphVector - glyph outline. + */ + public Shape getGlyphOutline(int glyphIndex, float x, float y) { + Shape initialShape = getGlyphOutline(glyphIndex); + AffineTransform trans = AffineTransform.getTranslateInstance(x, y); + return trans.createTransformedShape(initialShape); + } + + /** + * Gets the visual bounds of the specified glyph in the GlyphVector. + * + * @param glyphIndex + * the glyph index in this GlyphVector. + * @return the glyph visual bounds of the glyph with the specified index in + * the GlyphVector. + */ + public abstract Shape getGlyphVisualBounds(int glyphIndex); + + /** + * Gets a Shape object which defines the visual representation of the + * specified glyph in this GlyphVector. + * + * @param glyphIndex + * the glyth index in this GlyphVector. + * @return a Shape object which represents the visual representation of the + * specified glyph in this GlyphVector - glyph outline. + */ + public abstract Shape getGlyphOutline(int glyphIndex); + + /** + * Gets the logical bounds of the specified glyph in the GlyphVector. + * + * @param glyphIndex + * the index in this GlyphVector of the glyph from which to + * retrieve its logical bounds + * @return the logical bounds of the specified glyph in the GlyphVector. + */ + public abstract Shape getGlyphLogicalBounds(int glyphIndex); + + /** + * Gets the visual representation of this GlyphVector rendered in x, y + * location as a Shape object. + * + * @param x + * the x coordinate of the GlyphVector. + * @param y + * the y coordinate of the GlyphVector. + * @return the visual representation of this GlyphVector as a Shape object. + */ + public abstract Shape getOutline(float x, float y); + + /** + * Gets the visual representation of this GlyphVector as a Shape object. + * + * @return the visual representation of this GlyphVector as a Shape object. + */ + public abstract Shape getOutline(); + + /** + * Gets the font of this GlyphVector. + * + * @return the font of this GlyphVector. + */ + public abstract Font getFont(); + + /** + * Gets an array of the glyph codes of the specified glyphs. + * + * @param beginGlyphIndex + * the index into this GlyphVector at which to start retrieving + * glyph codes. + * @param numEntries + * the number of glyph codes. + * @param codeReturn + * the array into which the resulting glyphcodes will be written. + * @return the array of the glyph codes. + */ + public abstract int[] getGlyphCodes(int beginGlyphIndex, int numEntries, int[] codeReturn); + + /** + * Gets an array of the character indices of the specified glyphs. + * + * @param beginGlyphIndex + * the index of the first glyph to return information for. + * @param numEntries + * the number of glyph indices to return. + * @param codeReturn + * the array into which the resulting character indices will be + * written. + * @return an array of character indices for the specifies glyphs. + */ + public int[] getGlyphCharIndices(int beginGlyphIndex, int numEntries, int[] codeReturn) { + if (codeReturn == null) { + codeReturn = new int[numEntries]; + } + + for (int i = 0; i < numEntries; i++) { + codeReturn[i] = getGlyphCharIndex(i + beginGlyphIndex); + } + return codeReturn; + } + + /** + * Gets an array of the positions of the specified glyphs in this + * GlyphVector. + * + * @param beginGlyphIndex + * the index of the first glyph to return information for. + * @param numEntries + * the number of glyphs to return information for. + * @param positionReturn + * the array where the result will be stored. + * @return an array of glyph positions. + */ + public abstract float[] getGlyphPositions(int beginGlyphIndex, int numEntries, + float[] positionReturn); + + /** + * Gets the glyph code of the specified glyph. + * + * @param glyphIndex + * the index in this GlyphVector which corresponds to the glyph + * from which to retrieve the glyphcode. + * @return the glyphcode of the specified glyph. + */ + public abstract int getGlyphCode(int glyphIndex); + + /** + * Gets the first logical character's index of the specified glyph. + * + * @param glyphIndex + * the glyph index. + * @return the the first logical character's index. + */ + public int getGlyphCharIndex(int glyphIndex) { + // default implemetation one-to-one + return glyphIndex; + } + + /** + * Sets default layout to this GlyphVector. + */ + public abstract void performDefaultLayout(); + + /** + * Gets the number of glyphs in the GlyphVector. + * + * @return the number of glyphs in the GlyphVector. + */ + public abstract int getNumGlyphs(); + + /** + * Gets flags which describe the global state of the GlyphVector. The + * default implementation returns 0. + * + * @return the layout flags + */ + public int getLayoutFlags() { + // default implementation - returned value is 0 + return 0; + } + +} diff --git a/awt/java/awt/font/GraphicAttribute.java b/awt/java/awt/font/GraphicAttribute.java new file mode 100644 index 0000000..8480e0f --- /dev/null +++ b/awt/java/awt/font/GraphicAttribute.java @@ -0,0 +1,179 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The GraphicAttribute abstract class provides an opportunity to insert + * graphical elements in printed text. + * + * @since Android 1.0 + */ +public abstract class GraphicAttribute { + + /** + * The Constant TOP_ALIGNMENT indicates using the top line to calculate + * placement of graphics. + */ + public static final int TOP_ALIGNMENT = -1; + + /** + * The Constant BOTTOM_ALIGNMENT indicates using the bottom line to + * calculate placement of graphics. + */ + public static final int BOTTOM_ALIGNMENT = -2; + + /** + * The Constant ROMAN_BASELINE indicates the placement of the roman baseline + * with respect to the graphics origin. + */ + public static final int ROMAN_BASELINE = 0; + + /** + * The Constant CENTER_BASELINE indicates the placement of the center + * baseline with respect to the graphics origin. + */ + public static final int CENTER_BASELINE = 1; + + /** + * The Constant HANGING_BASELINE indicates the placement of the hanging + * baseline with respect to the graphics origin. + */ + public static final int HANGING_BASELINE = 2; + + // the alignment of this GraphicAttribute + /** + * The alignment. + */ + private int alignment; + + /** + * Instantiates a new graphic attribute with the specified alignment. + * + * @param align + * the specified alignment. + */ + protected GraphicAttribute(int align) { + if ((align < BOTTOM_ALIGNMENT) || (align > HANGING_BASELINE)) { + // awt.198=Illegal alignment argument + throw new IllegalArgumentException(Messages.getString("awt.198")); //$NON-NLS-1$ + } + this.alignment = align; + } + + /** + * Draws the GraphicAttribute at the specified location. + * + * @param graphics + * the Graphics. + * @param x + * the X coordinate of GraphicAttribute location. + * @param y + * the Y coordinate of GraphicAttribute location. + */ + public abstract void draw(Graphics2D graphics, float x, float y); + + /** + * Gets the GraphicAttribute's advance. It's the distance from the point at + * which the graphic is rendered and the point where the next character or + * graphic is rendered. + * + * @return the GraphicAttribute's advance. + */ + public abstract float getAdvance(); + + /** + * Gets the alignment of this GraphicAttribute. + * + * @return the alignment of this GraphicAttribute. + */ + public final int getAlignment() { + return this.alignment; + } + + /** + * Gets the ascent of this GraphicAttribute. + * + * @return the ascent of this GraphicAttribute. + */ + public abstract float getAscent(); + + /** + * Gets the bounds of this GraphicAttribute. + * + * @return the bounds of this GraphicAttribute. + */ + public Rectangle2D getBounds() { + float ascent = getAscent(); + float advance = getAdvance(); + float descent = getDescent(); + + // Default implementation - see API documentation. + return new Rectangle2D.Float(0, -ascent, advance, ascent + descent); + } + + /** + * Gets the descent of this GraphicAttribute. + * + * @return the descent of this GraphicAttribute. + */ + public abstract float getDescent(); + + /** + * Gets the GlyphJustificationInfo of this GraphicAttribute. + * + * @return the GlyphJustificationInfo of this GraphicAttribute. + */ + public GlyphJustificationInfo getJustificationInfo() { + + /* + * Default implementation. Since documentation doesn't describe default + * values, they were calculated based on 1.5 release behavior and can be + * obtained using next test sample: // Create GraphicAttribute class + * implementation public class MyGraphicAttribute extends + * GraphicAttribute { protected MyGraphicAttribute(int align) { + * super(align); } public float getDescent() { return 0; } public float + * getAdvance() { return 1; } public void draw(Graphics2D g2, float x, + * float y) { } public float getAscent() { return 0; } } + * MyGraphicAttribute myGA = gat.new MyGraphicAttribute(0); // print + * justification parameters + * System.out.println(myGA.getJustificationInfo().growAbsorb); + * System.out.println(myGA.getJustificationInfo().shrinkAbsorb); + * System.out.println(myGA.getJustificationInfo().growLeftLimit); + * System.out.println(myGA.getJustificationInfo().growPriority); + * System.out.println(myGA.getJustificationInfo().growRightLimit); + * System.out.println(myGA.getJustificationInfo().shrinkLeftLimit); + * System.out.println(myGA.getJustificationInfo().shrinkPriority); + * System.out.println(myGA.getJustificationInfo().shrinkRightLimit); + * System.out.println(myGA.getJustificationInfo().weight); + */ + float advance = getAdvance(); + return new GlyphJustificationInfo(advance, false, + GlyphJustificationInfo.PRIORITY_INTERCHAR, advance / 3, advance / 3, false, + GlyphJustificationInfo.PRIORITY_WHITESPACE, 0, 0); + } + +} diff --git a/awt/java/awt/font/ImageGraphicAttribute.java b/awt/java/awt/font/ImageGraphicAttribute.java new file mode 100644 index 0000000..d6d4758 --- /dev/null +++ b/awt/java/awt/font/ImageGraphicAttribute.java @@ -0,0 +1,185 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.geom.Rectangle2D; + +import org.apache.harmony.misc.HashCode; + +/** + * The ImageGraphicAttribute class provides an opportunity to insert images to a + * text. + * + * @since Android 1.0 + */ +public final class ImageGraphicAttribute extends GraphicAttribute { + + // Image object rendered by this ImageGraphicAttribute + /** + * The image. + */ + private Image fImage; + + // X coordinate of the origin point + /** + * The origin x. + */ + private float fOriginX; + + // Y coordinate of the origin point + /** + * The origin y. + */ + private float fOriginY; + + // the width of the image object + /** + * The img width. + */ + private float fImgWidth; + + // the height of the image object + /** + * The img height. + */ + private float fImgHeight; + + /** + * Instantiates a new ImageGraphicAttribute with the specified image, + * alignment and origins. + * + * @param image + * the Image to be rendered by ImageGraphicAttribute. + * @param alignment + * the alignment of the ImageGraphicAttribute. + * @param originX + * the origin X coordinate in the image of ImageGraphicAttribute. + * @param originY + * the origin Y coordinate in the image of ImageGraphicAttribute. + */ + public ImageGraphicAttribute(Image image, int alignment, float originX, float originY) { + super(alignment); + + this.fImage = image; + this.fOriginX = originX; + this.fOriginY = originY; + + this.fImgWidth = fImage.getWidth(null); + this.fImgHeight = fImage.getHeight(null); + + } + + /** + * Instantiates a new ImageGraphicAttribute with the specified image and + * alignment. + * + * @param image + * the Image to be rendered by ImageGraphicAttribute. + * @param alignment + * the alignment of the ImageGraphicAttribute. + */ + public ImageGraphicAttribute(Image image, int alignment) { + this(image, alignment, 0, 0); + } + + /** + * Returns a hash code of this ImageGraphicAttribute object. + * + * @return the hash code of this ImageGraphicAttribute object. + */ + @Override + public int hashCode() { + HashCode hash = new HashCode(); + + hash.append(fImage.hashCode()); + hash.append(getAlignment()); + return hash.hashCode(); + } + + /** + * Compares the specified ImageGraphicAttribute object with this + * ImageGraphicAttribute object. + * + * @param iga + * the ImageGraphicAttribute object to be compared. + * @return true, if the specified ImageGraphicAttribute object is equal to + * this ImageGraphicAttribute object, false otherwise. + */ + public boolean equals(ImageGraphicAttribute iga) { + if (iga == null) { + return false; + } + + if (iga == this) { + return true; + } + + return (fOriginX == iga.fOriginX && fOriginY == iga.fOriginY + && getAlignment() == iga.getAlignment() && fImage.equals(iga.fImage)); + } + + /** + * Compares the specified Object with this ImageGraphicAttribute object. + * + * @param obj + * the Object to be compared. + * @return true, if the specified Object is equal to this + * ImageGraphicAttribute object, false otherwise. + */ + @Override + public boolean equals(Object obj) { + try { + return equals((ImageGraphicAttribute)obj); + } catch (ClassCastException e) { + return false; + } + + } + + @Override + public void draw(Graphics2D g2, float x, float y) { + g2.drawImage(fImage, (int)(x - fOriginX), (int)(y - fOriginY), null); + } + + @Override + public float getAdvance() { + return Math.max(0, fImgWidth - fOriginX); + } + + @Override + public float getAscent() { + return Math.max(0, fOriginY); + } + + @Override + public Rectangle2D getBounds() { + return new Rectangle2D.Float(-fOriginX, -fOriginY, fImgWidth, fImgHeight); + } + + @Override + public float getDescent() { + return Math.max(0, fImgHeight - fOriginY); + } + +} diff --git a/awt/java/awt/font/LineBreakMeasurer.java b/awt/java/awt/font/LineBreakMeasurer.java new file mode 100644 index 0000000..4800093 --- /dev/null +++ b/awt/java/awt/font/LineBreakMeasurer.java @@ -0,0 +1,238 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt.font; + +import java.text.AttributedCharacterIterator; //???AWT: import java.text.BreakIterator; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The class LineBreakMeasurer provides methods to measure the graphical + * representation of a text in order to determine where to add line breaks so + * the resulting line of text fits its wrapping width. The wrapping width + * defines the visual width of the paragraph. + * + * @since Android 1.0 + */ +public final class LineBreakMeasurer { + + /** + * The tm. + */ + private TextMeasurer tm = null; + + // ???AWT private BreakIterator bi = null; + /** + * The position. + */ + private int position = 0; + + /** + * The maxpos. + */ + int maxpos = 0; + + /** + * Instantiates a new LineBreakMeasurer object for the specified text. + * + * @param text + * the AttributedCharacterIterator object which contains text + * with at least one character. + * @param frc + * the FontRenderContext represented information about graphic + * device. + */ + public LineBreakMeasurer(AttributedCharacterIterator text, FontRenderContext frc) { + // ???AWT: this(text, BreakIterator.getLineInstance(), frc); + } + + /* + * ???AWT public LineBreakMeasurer( AttributedCharacterIterator text, + * BreakIterator bi, FontRenderContext frc ) { tm = new TextMeasurer(text, + * frc); this.bi = bi; this.bi.setText(text); position = + * text.getBeginIndex(); maxpos = tm.aci.getEndIndex(); } + */ + + /** + * Deletes a character from the specified position of the text, updates this + * LineBreakMeasurer object. + * + * @param newText + * the new text. + * @param pos + * the position of the character which is deleted. + */ + public void deleteChar(AttributedCharacterIterator newText, int pos) { + tm.deleteChar(newText, pos); + // ???AWT: bi.setText(newText); + + position = newText.getBeginIndex(); + + maxpos--; + } + + /** + * Gets current position of this LineBreakMeasurer. + * + * @return the current position of this LineBreakMeasurer + */ + public int getPosition() { + return position; + } + + /** + * Inserts a character at the specified position in the text, updates this + * LineBreakMeasurer object. + * + * @param newText + * the new text. + * @param pos + * the position of the character which is inserted. + */ + public void insertChar(AttributedCharacterIterator newText, int pos) { + tm.insertChar(newText, pos); + // ???AWT: bi.setText(newText); + + position = newText.getBeginIndex(); + + maxpos++; + } + + /** + * Returns the next line of text, updates current position in this + * LineBreakMeasurer. + * + * @param wrappingWidth + * the maximum visible line width. + * @param offsetLimit + * the limit point within the text indicating that no further + * text should be included on the line; the paragraph break. + * @param requireNextWord + * if true, null is returned (the entire word at the current + * position does not fit within the wrapping width); if false, a + * valid layout is returned that includes at least the character + * at the current position. + * @return the next TextLayout which begins at the current position and + * represents the next line of text with width wrappingWidth, null + * is returned if the entire word at the current position does not + * fit within the wrapping width. + */ + public TextLayout nextLayout(float wrappingWidth, int offsetLimit, boolean requireNextWord) { + if (position == maxpos) { + return null; + } + + int nextPosition = nextOffset(wrappingWidth, offsetLimit, requireNextWord); + + if (nextPosition == position) { + return null; + } + TextLayout layout = tm.getLayout(position, nextPosition); + position = nextPosition; + return layout; + } + + /** + * Returns the next line of text. + * + * @param wrappingWidth + * the maximum visible line width. + * @return the next line of text. + */ + public TextLayout nextLayout(float wrappingWidth) { + return nextLayout(wrappingWidth, maxpos, false); + } + + /** + * Returns the end position of the next line of text. + * + * @param wrappingWidth + * the maximum visible line width. + * @return the end position of the next line of text. + */ + public int nextOffset(float wrappingWidth) { + return nextOffset(wrappingWidth, maxpos, false); + } + + /** + * Returns the end position of the next line of text. + * + * @param wrappingWidth + * the maximum visible line width. + * @param offsetLimit + * the limit point withing the text indicating that no further + * text should be included on the line; the paragraph break. + * @param requireNextWord + * if true, the current position is returned if the entire next + * word does not fit within wrappingWidth; if false, the offset + * returned is at least one greater than the current position. + * @return the end position of the next line of text. + * @throws IllegalArgumentException + * if the offsetLimit is less than the current position. + */ + public int nextOffset(float wrappingWidth, int offsetLimit, boolean requireNextWord) { + if (offsetLimit <= position) { + // awt.203=Offset limit should be greater than current position. + throw new IllegalArgumentException(Messages.getString("awt.203")); //$NON-NLS-1$ + } + + if (position == maxpos) { + return position; + } + + int breakPos = tm.getLineBreakIndex(position, wrappingWidth); + int correctedPos = breakPos; + + // This check is required because bi.preceding(maxpos) throws an + // exception + /* + * ???AWT if (breakPos == maxpos) { correctedPos = maxpos; } else if + * (Character.isWhitespace(bi.getText().setIndex(breakPos))) { + * correctedPos = bi.following(breakPos); } else { correctedPos = + * bi.preceding(breakPos); } + */ + + if (position >= correctedPos) { + if (requireNextWord) { + correctedPos = position; + } else { + correctedPos = Math.max(position + 1, breakPos); + } + } + + return Math.min(correctedPos, offsetLimit); + } + + /** + * Sets the new position of this LineBreakMeasurer. + * + * @param pos + * the new position of this LineBreakMeasurer. + */ + public void setPosition(int pos) { + if (tm.aci.getBeginIndex() > pos || maxpos < pos) { + // awt.33=index is out of range + throw new IllegalArgumentException(Messages.getString("awt.33")); //$NON-NLS-1$ + } + position = pos; + } +} diff --git a/awt/java/awt/font/LineMetrics.java b/awt/java/awt/font/LineMetrics.java new file mode 100644 index 0000000..4b03e5d --- /dev/null +++ b/awt/java/awt/font/LineMetrics.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +/** + * The LineMetrics class provides information such as concerning how the text is + * positioned with respect to the base line, such as ascent, descent, and + * leading. + * + * @since Android 1.0 + */ +public abstract class LineMetrics { + + /** + * Gets the baseline offsets of the text according to the the baseline of + * this text. + * + * @return the baseline offsets of the text according to the the baseline of + * this text. + */ + public abstract float[] getBaselineOffsets(); + + /** + * Gets the number of characters of the text. + * + * @return the number of characters of the text. + */ + public abstract int getNumChars(); + + /** + * Gets the baseline index, returns one of the following index: + * ROMAN_BASELINE, CENTER_BASELINE, HANGING_BASELINE. + * + * @return the baseline index: ROMAN_BASELINE, CENTER_BASELINE or + * HANGING_BASELINE. + */ + public abstract int getBaselineIndex(); + + /** + * Gets the thickness of the underline. + * + * @return the thickness of the underline. + */ + public abstract float getUnderlineThickness(); + + /** + * Gets the offset of the underline. + * + * @return the offset of the underline. + */ + public abstract float getUnderlineOffset(); + + /** + * Gets the thickness of strike through line. + * + * @return the thickness of strike through line. + */ + public abstract float getStrikethroughThickness(); + + /** + * Gets the offset of the strike through line. + * + * @return the offset of the strike through line. + */ + public abstract float getStrikethroughOffset(); + + /** + * Gets the leading of the text. + * + * @return the leading of the text. + */ + public abstract float getLeading(); + + /** + * Gets the height of the text as a sum of the ascent, the descent and the + * leading. + * + * @return the height of the text as a sum of the ascent, the descent and + * the leading. + */ + public abstract float getHeight(); + + /** + * Gets the descent of the text. + * + * @return the descent of the text. + */ + public abstract float getDescent(); + + /** + * Gets the ascent of the text. + * + * @return the ascent of the text. + */ + public abstract float getAscent(); + +} diff --git a/awt/java/awt/font/MultipleMaster.java b/awt/java/awt/font/MultipleMaster.java new file mode 100644 index 0000000..d264f24 --- /dev/null +++ b/awt/java/awt/font/MultipleMaster.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.Font; + +/** + * The MultipleMaster interface provides methods to manipulate MultipleMaster + * type fonts and retrieve graphical and design data from them. + * + * @since Android 1.0 + */ +public interface MultipleMaster { + + /** + * Derives a new multiple master font based on the specified parameters. + * + * @param glyphWidths + * float array which represents width of each glyph in font + * space. + * @param avgStemWidth + * the average stem width in font space. + * @param typicalCapHeight + * the typical upper case char height. + * @param typicalXHeight + * the typical lower case char height. + * @param italicAngle + * the slope angle for italics. + * @return a MultipleMaster font. + */ + public Font deriveMMFont(float[] glyphWidths, float avgStemWidth, float typicalCapHeight, + float typicalXHeight, float italicAngle); + + /** + * Derives a new multiple master font based on the design axis values + * contained in the specified array. + * + * @param axes + * an float array which contains axis values. + * @return a MultipleMaster font. + */ + public Font deriveMMFont(float[] axes); + + /** + * Gets default design values for the axes. + * + * @return the default design values for the axes. + */ + public float[] getDesignAxisDefaults(); + + /** + * Gets the array of design axis names. + * + * @return the array of design axis names. + */ + public String[] getDesignAxisNames(); + + /** + * Gets the array of design axis ranges. + * + * @return the array of design axis ranges. + */ + public float[] getDesignAxisRanges(); + + /** + * Gets the number of multiple master design controls. + * + * @return the number of multiple master design controls. + */ + public int getNumDesignAxes(); + +} diff --git a/awt/java/awt/font/OpenType.java b/awt/java/awt/font/OpenType.java new file mode 100644 index 0000000..db66911 --- /dev/null +++ b/awt/java/awt/font/OpenType.java @@ -0,0 +1,418 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +/** + * The OpenType interface provides constants and methods for getting instance + * data for fonts of type OpenType and TrueType. For more information, see the + * <a + * href="http://partners.adobe.com/public/developer/opentype/index_spec.html"> + * OpenType specification</a>. + * + * @since Android 1.0 + */ +public interface OpenType { + + /** + * The Constant TAG_ACNT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_ACNT = 1633906292; + + /** + * The Constant TAG_AVAR indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_AVAR = 1635148146; + + /** + * The Constant TAG_BASE indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_BASE = 1111577413; + + /** + * The Constant TAG_BDAT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_BDAT = 1650745716; + + /** + * The Constant TAG_BLOC indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_BLOC = 1651273571; + + /** + * The Constant TAG_BSLN indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_BSLN = 1651731566; + + /** + * The Constant TAG_CFF indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_CFF = 1128678944; + + /** + * The Constant TAG_CMAP indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_CMAP = 1668112752; + + /** + * The Constant TAG_CVAR indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_CVAR = 1668702578; + + /** + * The Constant TAG_CVT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_CVT = 1668707360; + + /** + * The Constant TAG_DSIG indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_DSIG = 1146308935; + + /** + * The Constant TAG_EBDT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_EBDT = 1161970772; + + /** + * The Constant TAG_EBLC indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_EBLC = 1161972803; + + /** + * The Constant TAG_EBSC indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_EBSC = 1161974595; + + /** + * The Constant TAG_FDSC indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_FDSC = 1717859171; + + /** + * The Constant TAG_FEAT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_FEAT = 1717920116; + + /** + * The Constant TAG_FMTX indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_FMTX = 1718449272; + + /** + * The Constant TAG_FPGM indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_FPGM = 1718642541; + + /** + * The Constant TAG_FVAR indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_FVAR = 1719034226; + + /** + * The Constant TAG_GASP indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_GASP = 1734439792; + + /** + * The Constant TAG_GDEF indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_GDEF = 1195656518; + + /** + * The Constant TAG_GLYF indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_GLYF = 1735162214; + + /** + * The Constant TAG_GPOS indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_GPOS = 1196445523; + + /** + * The Constant TAG_GSUB indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_GSUB = 1196643650; + + /** + * The Constant TAG_GVAR indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_GVAR = 1735811442; + + /** + * The Constant TAG_HDMX indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_HDMX = 1751412088; + + /** + * The Constant TAG_HEAD indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_HEAD = 1751474532; + + /** + * The Constant TAG_HHEA indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_HHEA = 1751672161; + + /** + * The Constant TAG_HMTX indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_HMTX = 1752003704; + + /** + * The Constant TAG_JSTF indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_JSTF = 1246975046; + + /** + * The Constant TAG_JUST indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_JUST = 1786082164; + + /** + * The Constant TAG_KERN indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_KERN = 1801810542; + + /** + * The Constant TAG_LCAR indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_LCAR = 1818452338; + + /** + * The Constant TAG_LOCA indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_LOCA = 1819239265; + + /** + * The Constant TAG_LTSH indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_LTSH = 1280594760; + + /** + * The Constant TAG_MAXP indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_MAXP = 1835104368; + + /** + * The Constant TAG_MMFX indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_MMFX = 1296909912; + + /** + * The Constant TAG_MMSD indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_MMSD = 1296913220; + + /** + * The Constant TAG_MORT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_MORT = 1836020340; + + /** + * The Constant TAG_NAME indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_NAME = 1851878757; + + /** + * The Constant TAG_OPBD indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_OPBD = 1836020340; + + /** + * The Constant TAG_OS2 indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_OS2 = 1330851634; + + /** + * The Constant TAG_PCLT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_PCLT = 1346587732; + + /** + * The Constant TAG_POST indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_POST = 1886352244; + + /** + * The Constant TAG_PREP indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_PREP = 1886545264; + + /** + * The Constant TAG_PROP indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_PROP = 1886547824; + + /** + * The Constant TAG_TRAK indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_TRAK = 1953653099; + + /** + * The Constant TAG_TYP1 indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_TYP1 = 1954115633; + + /** + * The Constant TAG_VDMX indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_VDMX = 1447316824; + + /** + * The Constant TAG_VHEA indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_VHEA = 1986553185; + + /** + * The Constant TAG_VMTX indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_VMTX = 1986884728; + + /** + * Returns the OpenType font version. + * + * @return the the OpenType font version. + */ + public int getVersion(); + + /** + * Gets the table for a specified tag. Sfnt tables include cmap, name and + * head items. + * + * @param sfntTag + * the sfnt tag. + * @return a byte array contains the font data corresponding to the + * specified tag. + */ + public byte[] getFontTable(int sfntTag); + + /** + * Gets the table for a specified tag. Sfnt tables include cmap, name and + * head items. + * + * @param sfntTag + * the sfnt tag. + * @param offset + * the offset of the returned table. + * @param count + * the number of returned table. + * @return the table corresponding to sfntTag and containing the bytes + * starting at offset byte and including count bytes. + */ + public byte[] getFontTable(int sfntTag, int offset, int count); + + /** + * Gets the table for a specified tag. Sfnt tables include cmap, name and + * head items. + * + * @param strSfntTag + * the str sfnt tag as a String. + * @return a byte array contains the font data corresponding to the + * specified tag. + */ + public byte[] getFontTable(String strSfntTag); + + /** + * Gets the table for a specified tag. Sfnt tables include cmap, name and + * head items. + * + * @param strSfntTag + * the sfnt tag as a String. + * @param offset + * the offset of the returned table. + * @param count + * the number of returned table. + * @return the table corresponding to sfntTag and containing the bytes + * starting at offset byte and including count bytes. + */ + public byte[] getFontTable(String strSfntTag, int offset, int count); + + /** + * Gets the table size for a specified tag. + * + * @param strSfntTag + * the sfnt tag as a String. + * @return the table size for a specified tag. + */ + public int getFontTableSize(String strSfntTag); + + /** + * Gets the table size for a specified tag. + * + * @param sfntTag + * the sfnt tag. + * @return the table size for a specified tag. + */ + public int getFontTableSize(int sfntTag); + +} diff --git a/awt/java/awt/font/ShapeGraphicAttribute.java b/awt/java/awt/font/ShapeGraphicAttribute.java new file mode 100644 index 0000000..182bffd --- /dev/null +++ b/awt/java/awt/font/ShapeGraphicAttribute.java @@ -0,0 +1,206 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.BasicStroke; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; + +import org.apache.harmony.misc.HashCode; + +/** + * The ShapeGraphicAttribute class provides an opportunity to insert shapes to a + * text. + * + * @since Android 1.0 + */ +public final class ShapeGraphicAttribute extends GraphicAttribute { + + // shape to render + /** + * The shape. + */ + private Shape fShape; + + // flag, if the shape should be stroked (true) or filled (false) + /** + * The stroke. + */ + private boolean fStroke; + + // bounds of the shape + /** + * The bounds. + */ + private Rectangle2D fBounds; + + // X coordinate of the origin point + /** + * The origin x. + */ + private float fOriginX; + + // Y coordinate of the origin point + /** + * The origin y. + */ + private float fOriginY; + + // width of the shape + /** + * The shape width. + */ + private float fShapeWidth; + + // height of the shape + /** + * The shape height. + */ + private float fShapeHeight; + + /** + * The Constant STROKE indicates whether the Shape is stroked or not. + */ + public static final boolean STROKE = true; + + /** + * The Constant FILL indicates whether the Shape is filled or not. + */ + public static final boolean FILL = false; + + /** + * Instantiates a new ShapeGraphicAttribute object for the specified Shape. + * + * @param shape + * the shape to be rendered by this ShapeGraphicAttribute. + * @param alignment + * the alignment of this ShapeGraphicAttribute. + * @param stroke + * true if the Shape is stroked, false if the Shape is filled. + */ + public ShapeGraphicAttribute(Shape shape, int alignment, boolean stroke) { + super(alignment); + + this.fShape = shape; + this.fStroke = stroke; + + this.fBounds = fShape.getBounds2D(); + + this.fOriginX = (float)fBounds.getMinX(); + this.fOriginY = (float)fBounds.getMinY(); + + this.fShapeWidth = (float)fBounds.getWidth(); + this.fShapeHeight = (float)fBounds.getHeight(); + } + + /** + * Returns a hash code of this ShapeGraphicAttribute object. + * + * @return a hash code of this ShapeGraphicAttribute object. + */ + @Override + public int hashCode() { + HashCode hash = new HashCode(); + + hash.append(fShape.hashCode()); + hash.append(getAlignment()); + return hash.hashCode(); + } + + /** + * Compares this ShapeGraphicAttribute object to the specified + * ShapeGraphicAttribute object. + * + * @param sga + * the ShapeGraphicAttribute object to be compared. + * @return true, if this ShapeGraphicAttribute object is equal to the + * specified ShapeGraphicAttribute object, false otherwise. + */ + public boolean equals(ShapeGraphicAttribute sga) { + if (sga == null) { + return false; + } + + if (sga == this) { + return true; + } + + return (fStroke == sga.fStroke && getAlignment() == sga.getAlignment() && fShape + .equals(sga.fShape)); + + } + + /** + * Compares this ShapeGraphicAttribute object to the specified Object. + * + * @param obj + * the Object to be compared. + * @return true, if this ShapeGraphicAttribute object is equal to the + * specified Object, false otherwise. + */ + @Override + public boolean equals(Object obj) { + try { + return equals((ShapeGraphicAttribute)obj); + } catch (ClassCastException e) { + return false; + } + } + + @Override + public void draw(Graphics2D g2, float x, float y) { + AffineTransform at = AffineTransform.getTranslateInstance(x, y); + if (fStroke == STROKE) { + Stroke oldStroke = g2.getStroke(); + g2.setStroke(new BasicStroke()); + g2.draw(at.createTransformedShape(fShape)); + g2.setStroke(oldStroke); + } else { + g2.fill(at.createTransformedShape(fShape)); + } + + } + + @Override + public float getAdvance() { + return Math.max(0, fShapeWidth + fOriginX); + } + + @Override + public float getAscent() { + return Math.max(0, -fOriginY); + } + + @Override + public Rectangle2D getBounds() { + return (Rectangle2D)fBounds.clone(); + } + + @Override + public float getDescent() { + return Math.max(0, fShapeHeight + fOriginY); + } + +} diff --git a/awt/java/awt/font/TextHitInfo.java b/awt/java/awt/font/TextHitInfo.java new file mode 100644 index 0000000..6460eba --- /dev/null +++ b/awt/java/awt/font/TextHitInfo.java @@ -0,0 +1,215 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt.font; + +import org.apache.harmony.misc.HashCode; + +/** + * The TextHitInfo class provides information about a caret position in a text + * model for insertion or deletion of a character in a text. The TextHitInfo + * defines two biases of the character: leading or trailing. Leading position + * means the left edge of the specified character (TextHitInfo.leading(2) method + * for "text" returns the left side of "x"). Trailing position means the right + * edge of the specified character (TextHitInfo.trailing(2) method for "text" + * returns the right side of "x"). + * + * @since Android 1.0 + */ +public final class TextHitInfo { + + /** + * The char idx. + */ + private int charIdx; // Represents character index in the line + + /** + * The is trailing. + */ + private boolean isTrailing; + + /** + * Instantiates a new text hit info. + * + * @param idx + * the idx. + * @param isTrailing + * the is trailing. + */ + private TextHitInfo(int idx, boolean isTrailing) { + charIdx = idx; + this.isTrailing = isTrailing; + } + + /** + * Returns the textual string representation of this TextHitInfo instance. + * + * @return the string representation. + */ + @Override + public String toString() { + return new String("TextHitInfo[" + charIdx + ", " + //$NON-NLS-1$ //$NON-NLS-2$ + (isTrailing ? "Trailing" : "Leading") + "]" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + ); + } + + /** + * Compares this TextHitInfo object with the specified object. + * + * @param obj + * the Object to be compared. + * @return true, if the specified object is a TextHitInfo object with the + * same data values as this TextHitInfo, false otherwise. + */ + @Override + public boolean equals(Object obj) { + if (obj instanceof TextHitInfo) { + return equals((TextHitInfo)obj); + } + return false; + } + + /** + * Compares this TextHitInfo object with the specified TextHitInfo object. + * + * @param thi + * the TextHitInfo object to be compared. + * @return true, if this TextHitInfo object has the same data values as the + * specified TextHitInfo object, false otherwise. + */ + public boolean equals(TextHitInfo thi) { + return thi != null && thi.charIdx == charIdx && thi.isTrailing == isTrailing; + } + + /** + * Gets a TextHitInfo object with its character index at the specified + * offset from the character index of this TextHitInfo. + * + * @param offset + * the offset. + * @return the TextHitInfo. + */ + public TextHitInfo getOffsetHit(int offset) { + return new TextHitInfo(charIdx + offset, isTrailing); + } + + /** + * Gets a TextHitInfo associated with the other side of the insertion point. + * + * @return the other hit. + */ + public TextHitInfo getOtherHit() { + return isTrailing ? new TextHitInfo(charIdx + 1, false) + : new TextHitInfo(charIdx - 1, true); + } + + /** + * Returns true if the leading edge of the character is hit, false if the + * trailing edge of the character is hit. + * + * @return true if the leading edge of the character is hit, false if the + * trailing edge of the character is hit. + */ + public boolean isLeadingEdge() { + return !isTrailing; + } + + /** + * Returns the hash code value of this TextHitInfo instance. + * + * @return the hash code value. + */ + @Override + public int hashCode() { + return HashCode.combine(charIdx, isTrailing); + } + + /** + * Gets the insertion index. + * + * @return the insertion index: character index if the leading edge is hit, + * or character index + 1 if the trailing edge is hit. + */ + public int getInsertionIndex() { + return isTrailing ? charIdx + 1 : charIdx; + } + + /** + * Gets the index of the character hit. + * + * @return the character hit's index. + */ + public int getCharIndex() { + return charIdx; + } + + /** + * Returns a TextHitInfo associated with the trailing edge of the character + * at the specified char index. + * + * @param charIndex + * the char index. + * @return the TextHitInfo associated with the trailing edge of the + * character at the specified char index. + */ + public static TextHitInfo trailing(int charIndex) { + return new TextHitInfo(charIndex, true); + } + + /** + * Returns a TextHitInfo object associated with the leading edge of the + * character at the specified char index. + * + * @param charIndex + * the char index. + * @return the TextHitInfo object associated with the leading edge of the + * character at the specified char index. + */ + public static TextHitInfo leading(int charIndex) { + return new TextHitInfo(charIndex, false); + } + + /** + * Returns a (trailing) TextHitInfo object associated with the character + * before the specified offset. + * + * @param offset + * the offset. + * @return the TextHitInfo object associated with the character before the + * specified offset. + */ + public static TextHitInfo beforeOffset(int offset) { + return new TextHitInfo(offset - 1, true); + } + + /** + * Returns a (leading) TextHitInfo object associated with the character + * after the specified offset. + * + * @param offset + * the offset. + * @return the TextHitInfo object associated with the character after the + * specified offset. + */ + public static TextHitInfo afterOffset(int offset) { + return new TextHitInfo(offset, false); + } +} diff --git a/awt/java/awt/font/TextLayout.java b/awt/java/awt/font/TextLayout.java new file mode 100644 index 0000000..cc6f0ba --- /dev/null +++ b/awt/java/awt/font/TextLayout.java @@ -0,0 +1,927 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.geom.GeneralPath; +import java.text.AttributedCharacterIterator; +import java.text.AttributedString; +import java.util.Map; + +import org.apache.harmony.awt.gl.font.BasicMetrics; +import org.apache.harmony.awt.gl.font.CaretManager; +import org.apache.harmony.awt.gl.font.TextMetricsCalculator; +import org.apache.harmony.awt.gl.font.TextRunBreaker; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The TextLayout class defines the graphical representation of character data. + * This class provides method for obtaining information about cursor positioning + * and movement, split cursors for text with different directions, logical and + * visual highlighting, multiple baselines, hits, justification, ascent, + * descent, and advance, and rendering. A TextLayout object can be rendered + * using Graphics context. + * + * @since Android 1.0 + */ +public final class TextLayout implements Cloneable { + + /** + * The CaretPolicy class provides a policy for obtaining the caret location. + * The single getStrongCaret method specifies the policy. + */ + public static class CaretPolicy { + + /** + * Instantiates a new CaretPolicy. + */ + public CaretPolicy() { + // Nothing to do + } + + /** + * Returns whichever of the two specified TextHitInfo objects has the + * stronger caret (higher character level) in the specified TextLayout. + * + * @param hit1 + * the first TextHitInfo of the specified TextLayout. + * @param hit2 + * the second TextHitInfo of the specified TextLayout. + * @param layout + * the TextLayout. + * @return the TextHitInfo with the stronger caret. + */ + public TextHitInfo getStrongCaret(TextHitInfo hit1, TextHitInfo hit2, TextLayout layout) { + // Stronger hit is the one with greater level. + // If the level is same, leading edge is stronger. + + int level1 = layout.getCharacterLevel(hit1.getCharIndex()); + int level2 = layout.getCharacterLevel(hit2.getCharIndex()); + + if (level1 == level2) { + return (hit2.isLeadingEdge() && (!hit1.isLeadingEdge())) ? hit2 : hit1; + } + return level1 > level2 ? hit1 : hit2; + } + + } + + /** + * The Constant DEFAULT_CARET_POLICY indicates the default caret policy. + */ + public static final TextLayout.CaretPolicy DEFAULT_CARET_POLICY = new CaretPolicy(); + + /** + * The breaker. + */ + private TextRunBreaker breaker; + + /** + * The metrics valid. + */ + private boolean metricsValid = false; + + /** + * The tmc. + */ + private TextMetricsCalculator tmc; + + /** + * The metrics. + */ + private BasicMetrics metrics; + + /** + * The caret manager. + */ + private CaretManager caretManager; + + /** + * The justification width. + */ + float justificationWidth = -1; + + /** + * Instantiates a new TextLayout object from the specified string and Font. + * + * @param string + * the string to be displayed. + * @param font + * the font of the text. + * @param frc + * the FontRenderContext object for obtaining information about a + * graphics device. + */ + public TextLayout(String string, Font font, FontRenderContext frc) { + if (string == null) { + // awt.01='{0}' parameter is null + throw new IllegalArgumentException(Messages.getString("awt.01", "string")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + if (font == null) { + // awt.01='{0}' parameter is null + throw new IllegalArgumentException(Messages.getString("awt.01", "font")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + if (string.length() == 0) { + // awt.02='{0}' parameter has zero length + throw new IllegalArgumentException(Messages.getString("awt.02", "string")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + AttributedString as = new AttributedString(string); + as.addAttribute(TextAttribute.FONT, font); + this.breaker = new TextRunBreaker(as.getIterator(), frc); + caretManager = new CaretManager(breaker); + } + + /** + * Instantiates a new TextLayout from the specified text and a map of + * attributes. + * + * @param string + * the string to be displayed. + * @param attributes + * the attributes to be used for obtaining the text style. + * @param frc + * the FontRenderContext object for obtaining information about a + * graphics device. + */ + public TextLayout(String string, + Map<? extends java.text.AttributedCharacterIterator.Attribute, ?> attributes, + FontRenderContext frc) { + if (string == null) { + // awt.01='{0}' parameter is null + throw new IllegalArgumentException(Messages.getString("awt.01", "string")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + if (attributes == null) { + // awt.01='{0}' parameter is null + throw new IllegalArgumentException(Messages.getString("awt.01", "attributes")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + if (string.length() == 0) { + // awt.02='{0}' parameter has zero length + throw new IllegalArgumentException(Messages.getString("awt.02", "string")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + AttributedString as = new AttributedString(string); + as.addAttributes(attributes, 0, string.length()); + this.breaker = new TextRunBreaker(as.getIterator(), frc); + caretManager = new CaretManager(breaker); + } + + /** + * Instantiates a new TextLayout from the AttributedCharacterIterator. + * + * @param text + * the AttributedCharacterIterator. + * @param frc + * the FontRenderContext object for obtaining information about a + * graphics device. + */ + public TextLayout(AttributedCharacterIterator text, FontRenderContext frc) { + if (text == null) { + // awt.03='{0}' iterator parameter is null + throw new IllegalArgumentException(Messages.getString("awt.03", "text")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + if (text.getBeginIndex() == text.getEndIndex()) { + // awt.04='{0}' iterator parameter has zero length + throw new IllegalArgumentException(Messages.getString("awt.04", "text")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + this.breaker = new TextRunBreaker(text, frc); + caretManager = new CaretManager(breaker); + } + + /** + * Instantiates a new text layout. + * + * @param breaker + * the breaker. + */ + TextLayout(TextRunBreaker breaker) { + this.breaker = breaker; + caretManager = new CaretManager(this.breaker); + } + + /** + * Returns a hash code of this TextLayout object. + * + * @return a hash code of this TextLayout object. + */ + @Override + public int hashCode() { + return breaker.hashCode(); + } + + /** + * Returns a copy of this object. + * + * @return a copy of this object. + */ + @Override + protected Object clone() { + TextLayout res = new TextLayout((TextRunBreaker)breaker.clone()); + + if (justificationWidth >= 0) { + res.handleJustify(justificationWidth); + } + + return res; + } + + /** + * Compares this TextLayout object to the specified TextLayout object. + * + * @param layout + * the TextLayout object to be compared. + * @return true, if this TextLayout object is equal to the specified + * TextLayout object, false otherwise. + */ + public boolean equals(TextLayout layout) { + if (layout == null) { + return false; + } + return this.breaker.equals(layout.breaker); + } + + /** + * Compares this TextLayout object to the specified Object. + * + * @param obj + * the Object to be compared. + * @return true, if this TextLayout object is equal to the specified Object, + * false otherwise. + */ + @Override + public boolean equals(Object obj) { + return obj instanceof TextLayout ? equals((TextLayout)obj) : false; + } + + /** + * Gets the string representation for this TextLayout. + * + * @return the string representation for this TextLayout. + */ + @Override + public String toString() { // what for? + return super.toString(); + } + + /** + * Draws this TextLayout at the specified location with the specified + * Graphics2D context. + * + * @param g2d + * the Graphics2D object which renders this TextLayout. + * @param x + * the X coordinate of the TextLayout origin. + * @param y + * the Y coordinate of the TextLayout origin. + */ + public void draw(Graphics2D g2d, float x, float y) { + updateMetrics(); + breaker.drawSegments(g2d, x, y); + } + + /** + * Update metrics. + */ + private void updateMetrics() { + if (!metricsValid) { + breaker.createAllSegments(); + tmc = new TextMetricsCalculator(breaker); + metrics = tmc.createMetrics(); + metricsValid = true; + } + } + + /** + * Gets the advance of this TextLayout object. + * + * @return the advance of this TextLayout object. + */ + public float getAdvance() { + updateMetrics(); + return metrics.getAdvance(); + } + + /** + * Gets the ascent of this TextLayout object. + * + * @return the ascent of this TextLayout object. + */ + public float getAscent() { + updateMetrics(); + return metrics.getAscent(); + } + + /** + * Gets the baseline of this TextLayout object. + * + * @return the baseline of this TextLayout object. + */ + public byte getBaseline() { + updateMetrics(); + return (byte)metrics.getBaseLineIndex(); + } + + /** + * Gets the float array of offsets for the baselines which are used in this + * TextLayout. + * + * @return the float array of offsets for the baselines which are used in + * this TextLayout. + */ + public float[] getBaselineOffsets() { + updateMetrics(); + return tmc.getBaselineOffsets(); + } + + /** + * Gets the black box bounds of the characters in the specified area. The + * black box bounds is an Shape which contains all bounding boxes of all the + * glyphs of the characters between firstEndpoint and secondEndpoint + * parameters values. + * + * @param firstEndpoint + * the first point of the area. + * @param secondEndpoint + * the second point of the area. + * @return the Shape which contains black box bounds. + */ + public Shape getBlackBoxBounds(int firstEndpoint, int secondEndpoint) { + updateMetrics(); + if (firstEndpoint < secondEndpoint) { + return breaker.getBlackBoxBounds(firstEndpoint, secondEndpoint); + } + return breaker.getBlackBoxBounds(secondEndpoint, firstEndpoint); + } + + /** + * Gets the bounds of this TextLayout. + * + * @return the bounds of this TextLayout. + */ + public Rectangle2D getBounds() { + updateMetrics(); + return breaker.getVisualBounds(); + } + + /** + * Gets information about the caret of the specified TextHitInfo. + * + * @param hitInfo + * the TextHitInfo. + * @return the information about the caret of the specified TextHitInfo. + */ + public float[] getCaretInfo(TextHitInfo hitInfo) { + updateMetrics(); + return caretManager.getCaretInfo(hitInfo); + } + + /** + * Gets information about the caret of the specified TextHitInfo of a + * character in this TextLayout. + * + * @param hitInfo + * the TextHitInfo of a character in this TextLayout. + * @param bounds + * the bounds to which the caret info is constructed. + * @return the caret of the specified TextHitInfo. + */ + public float[] getCaretInfo(TextHitInfo hitInfo, Rectangle2D bounds) { + updateMetrics(); + return caretManager.getCaretInfo(hitInfo); + } + + /** + * Gets a Shape which represents the caret of the specified TextHitInfo in + * the bounds of this TextLayout. + * + * @param hitInfo + * the TextHitInfo. + * @param bounds + * the bounds to which the caret info is constructed. + * @return the Shape which represents the caret. + */ + public Shape getCaretShape(TextHitInfo hitInfo, Rectangle2D bounds) { + updateMetrics(); + return caretManager.getCaretShape(hitInfo, this); + } + + /** + * Gets a Shape which represents the caret of the specified TextHitInfo in + * the bounds of this TextLayout. + * + * @param hitInfo + * the TextHitInfo. + * @return the Shape which represents the caret. + */ + public Shape getCaretShape(TextHitInfo hitInfo) { + updateMetrics(); + return caretManager.getCaretShape(hitInfo, this); + } + + /** + * Gets two Shapes for the strong and weak carets with default caret policy + * and null bounds: the first element is the strong caret, the second is the + * weak caret or null. + * + * @param offset + * an offset in the TextLayout. + * @return an array of two Shapes corresponded to the strong and weak + * carets. + */ + public Shape[] getCaretShapes(int offset) { + return getCaretShapes(offset, null, TextLayout.DEFAULT_CARET_POLICY); + } + + /** + * Gets two Shapes for the strong and weak carets with the default caret + * policy: the first element is the strong caret, the second is the weak + * caret or null. + * + * @param offset + * an offset in the TextLayout. + * @param bounds + * the bounds to which to extend the carets. + * @return an array of two Shapes corresponded to the strong and weak + * carets. + */ + public Shape[] getCaretShapes(int offset, Rectangle2D bounds) { + return getCaretShapes(offset, bounds, TextLayout.DEFAULT_CARET_POLICY); + } + + /** + * Gets two Shapes for the strong and weak carets: the first element is the + * strong caret, the second is the weak caret or null. + * + * @param offset + * an offset in the TextLayout. + * @param bounds + * the bounds to which to extend the carets. + * @param policy + * the specified CaretPolicy. + * @return an array of two Shapes corresponded to the strong and weak + * carets. + */ + public Shape[] getCaretShapes(int offset, Rectangle2D bounds, TextLayout.CaretPolicy policy) { + if (offset < 0 || offset > breaker.getCharCount()) { + // awt.195=Offset is out of bounds + throw new IllegalArgumentException(Messages.getString("awt.195")); //$NON-NLS-1$ + } + + updateMetrics(); + return caretManager.getCaretShapes(offset, bounds, policy, this); + } + + /** + * Gets the number of characters in this TextLayout. + * + * @return the number of characters in this TextLayout. + */ + public int getCharacterCount() { + return breaker.getCharCount(); + } + + /** + * Gets the level of the character with the specified index. + * + * @param index + * the specified index of the character. + * @return the level of the character. + */ + public byte getCharacterLevel(int index) { + if (index == -1 || index == getCharacterCount()) { + return (byte)breaker.getBaseLevel(); + } + return breaker.getLevel(index); + } + + /** + * Gets the descent of this TextLayout. + * + * @return the descent of this TextLayout. + */ + public float getDescent() { + updateMetrics(); + return metrics.getDescent(); + } + + /** + * Gets the TextLayout wich is justified with the specified width related to + * this TextLayout. + * + * @param justificationWidth + * the width which is used for justification. + * @return a TextLayout justified to the specified width. + * @throws Error + * the error occures if this TextLayout has been already + * justified. + */ + public TextLayout getJustifiedLayout(float justificationWidth) throws Error { + float justification = breaker.getJustification(); + + if (justification < 0) { + // awt.196=Justification impossible, layout already justified + throw new Error(Messages.getString("awt.196")); //$NON-NLS-1$ + } else if (justification == 0) { + return this; + } + + TextLayout justifiedLayout = new TextLayout((TextRunBreaker)breaker.clone()); + justifiedLayout.handleJustify(justificationWidth); + return justifiedLayout; + } + + /** + * Gets the leading of this TextLayout. + * + * @return the leading of this TextLayout. + */ + public float getLeading() { + updateMetrics(); + return metrics.getLeading(); + } + + /** + * Gets a Shape representing the logical selection betweeen the specified + * endpoints and extended to the natural bounds of this TextLayout. + * + * @param firstEndpoint + * the first selected endpoint within the area of characters + * @param secondEndpoint + * the second selected endpoint within the area of characters + * @return a Shape represented the logical selection betweeen the specified + * endpoints. + */ + public Shape getLogicalHighlightShape(int firstEndpoint, int secondEndpoint) { + updateMetrics(); + return getLogicalHighlightShape(firstEndpoint, secondEndpoint, breaker.getLogicalBounds()); + } + + /** + * Gets a Shape representing the logical selection betweeen the specified + * endpoints and extended to the specified bounds of this TextLayout. + * + * @param firstEndpoint + * the first selected endpoint within the area of characters + * @param secondEndpoint + * the second selected endpoint within the area of characters + * @param bounds + * the specified bounds of this TextLayout. + * @return a Shape represented the logical selection betweeen the specified + * endpoints. + */ + public Shape getLogicalHighlightShape(int firstEndpoint, int secondEndpoint, Rectangle2D bounds) { + updateMetrics(); + + if (firstEndpoint > secondEndpoint) { + if (secondEndpoint < 0 || firstEndpoint > breaker.getCharCount()) { + // awt.197=Endpoints are out of range + throw new IllegalArgumentException(Messages.getString("awt.197")); //$NON-NLS-1$ + } + return caretManager.getLogicalHighlightShape(secondEndpoint, firstEndpoint, bounds, + this); + } + if (firstEndpoint < 0 || secondEndpoint > breaker.getCharCount()) { + // awt.197=Endpoints are out of range + throw new IllegalArgumentException(Messages.getString("awt.197")); //$NON-NLS-1$ + } + return caretManager.getLogicalHighlightShape(firstEndpoint, secondEndpoint, bounds, this); + } + + /** + * Gets the logical ranges of text which corresponds to a visual selection. + * + * @param hit1 + * the first endpoint of the visual range. + * @param hit2 + * the second endpoint of the visual range. + * @return the logical ranges of text which corresponds to a visual + * selection. + */ + public int[] getLogicalRangesForVisualSelection(TextHitInfo hit1, TextHitInfo hit2) { + return caretManager.getLogicalRangesForVisualSelection(hit1, hit2); + } + + /** + * Gets the TextHitInfo for the next caret to the left (or up at the end of + * the line) of the specified offset. + * + * @param offset + * the offset in this TextLayout. + * @return the TextHitInfo for the next caret to the left (or up at the end + * of the line) of the specified hit, or null if there is no hit. + */ + public TextHitInfo getNextLeftHit(int offset) { + return getNextLeftHit(offset, DEFAULT_CARET_POLICY); + } + + /** + * Gets the TextHitInfo for the next caret to the left (or up at the end of + * the line) of the specified hit. + * + * @param hitInfo + * the initial hit. + * @return the TextHitInfo for the next caret to the left (or up at the end + * of the line) of the specified hit, or null if there is no hit. + */ + public TextHitInfo getNextLeftHit(TextHitInfo hitInfo) { + breaker.createAllSegments(); + return caretManager.getNextLeftHit(hitInfo); + } + + /** + * Gets the TextHitInfo for the next caret to the left (or up at the end of + * the line) of the specified offset, given the specified caret policy. + * + * @param offset + * the offset in this TextLayout. + * @param policy + * the policy to be used for obtaining the strong caret. + * @return the TextHitInfo for the next caret to the left of the specified + * offset, or null if there is no hit. + */ + public TextHitInfo getNextLeftHit(int offset, TextLayout.CaretPolicy policy) { + if (offset < 0 || offset > breaker.getCharCount()) { + // awt.195=Offset is out of bounds + throw new IllegalArgumentException(Messages.getString("awt.195")); //$NON-NLS-1$ + } + + TextHitInfo hit = TextHitInfo.afterOffset(offset); + TextHitInfo strongHit = policy.getStrongCaret(hit, hit.getOtherHit(), this); + TextHitInfo nextLeftHit = getNextLeftHit(strongHit); + + if (nextLeftHit != null) { + return policy.getStrongCaret(getVisualOtherHit(nextLeftHit), nextLeftHit, this); + } + return null; + } + + /** + * Gets the TextHitInfo for the next caret to the right (or down at the end + * of the line) of the specified hit. + * + * @param hitInfo + * the initial hit. + * @return the TextHitInfo for the next caret to the right (or down at the + * end of the line) of the specified hit, or null if there is no + * hit. + */ + public TextHitInfo getNextRightHit(TextHitInfo hitInfo) { + breaker.createAllSegments(); + return caretManager.getNextRightHit(hitInfo); + } + + /** + * Gets the TextHitInfo for the next caret to the right (or down at the end + * of the line) of the specified offset. + * + * @param offset + * the offset in this TextLayout. + * @return the TextHitInfo for the next caret to the right of the specified + * offset, or null if there is no hit. + */ + public TextHitInfo getNextRightHit(int offset) { + return getNextRightHit(offset, DEFAULT_CARET_POLICY); + } + + /** + * Gets the TextHitInfo for the next caret to the right (or down at the end + * of the line) of the specified offset, given the specified caret policy. + * + * @param offset + * the offset in this TextLayout. + * @param policy + * the policy to be used for obtaining the strong caret. + * @return the TextHitInfo for the next caret to the right of the specified + * offset, or null if there is no hit. + */ + public TextHitInfo getNextRightHit(int offset, TextLayout.CaretPolicy policy) { + if (offset < 0 || offset > breaker.getCharCount()) { + // awt.195=Offset is out of bounds + throw new IllegalArgumentException(Messages.getString("awt.195")); //$NON-NLS-1$ + } + + TextHitInfo hit = TextHitInfo.afterOffset(offset); + TextHitInfo strongHit = policy.getStrongCaret(hit, hit.getOtherHit(), this); + TextHitInfo nextRightHit = getNextRightHit(strongHit); + + if (nextRightHit != null) { + return policy.getStrongCaret(getVisualOtherHit(nextRightHit), nextRightHit, this); + } + return null; + } + + /** + * Gets the outline of this TextLayout as a Shape. + * + * @param xform + * the AffineTransform to be used to transform the outline before + * returning it, or null if no transformation is desired. + * @return the outline of this TextLayout as a Shape. + */ + public Shape getOutline(AffineTransform xform) { + breaker.createAllSegments(); + + GeneralPath outline = breaker.getOutline(); + + if (outline != null && xform != null) { + outline.transform(xform); + } + + return outline; + } + + /** + * Gets the visible advance of this TextLayout which is defined as diffence + * between leading (advance) and trailing whitespace. + * + * @return the visible advance of this TextLayout. + */ + public float getVisibleAdvance() { + updateMetrics(); + + // Trailing whitespace _SHOULD_ be reordered (Unicode spec) to + // base direction, so it is also trailing + // in logical representation. We use this fact. + int lastNonWhitespace = breaker.getLastNonWhitespace(); + + if (lastNonWhitespace < 0) { + return 0; + } else if (lastNonWhitespace == getCharacterCount() - 1) { + return getAdvance(); + } else if (justificationWidth >= 0) { // Layout is justified + return justificationWidth; + } else { + breaker.pushSegments(breaker.getACI().getBeginIndex(), lastNonWhitespace + + breaker.getACI().getBeginIndex() + 1); + + breaker.createAllSegments(); + + float visAdvance = tmc.createMetrics().getAdvance(); + + breaker.popSegments(); + return visAdvance; + } + } + + /** + * Gets a Shape which corresponds to the highlighted (selected) area based + * on two hit locations within the text and extends to the bounds. + * + * @param hit1 + * the first text hit location. + * @param hit2 + * the second text hit location. + * @param bounds + * the rectangle that the highlighted area should be extended or + * restricted to. + * @return a Shape which corresponds to the highlighted (selected) area. + */ + public Shape getVisualHighlightShape(TextHitInfo hit1, TextHitInfo hit2, Rectangle2D bounds) { + return caretManager.getVisualHighlightShape(hit1, hit2, bounds, this); + } + + /** + * Gets a Shape which corresponds to the highlighted (selected) area based + * on two hit locations within the text. + * + * @param hit1 + * the first text hit location. + * @param hit2 + * the second text hit location. + * @return a Shape which corresponds to the highlighted (selected) area. + */ + public Shape getVisualHighlightShape(TextHitInfo hit1, TextHitInfo hit2) { + breaker.createAllSegments(); + return caretManager.getVisualHighlightShape(hit1, hit2, breaker.getLogicalBounds(), this); + } + + /** + * Gets the TextHitInfo for a hit on the opposite side of the specified + * hit's caret. + * + * @param hitInfo + * the specified TextHitInfo. + * @return the TextHitInfo for a hit on the opposite side of the specified + * hit's caret. + */ + public TextHitInfo getVisualOtherHit(TextHitInfo hitInfo) { + return caretManager.getVisualOtherHit(hitInfo); + } + + /** + * Justifies the text; this method should be overridden by subclasses. + * + * @param justificationWidth + * the width for justification. + */ + protected void handleJustify(float justificationWidth) { + float justification = breaker.getJustification(); + + if (justification < 0) { + // awt.196=Justification impossible, layout already justified + throw new IllegalStateException(Messages.getString("awt.196")); //$NON-NLS-1$ + } else if (justification == 0) { + return; + } + + float gap = (justificationWidth - getVisibleAdvance()) * justification; + breaker.justify(gap); + this.justificationWidth = justificationWidth; + + // Correct metrics + tmc = new TextMetricsCalculator(breaker); + tmc.correctAdvance(metrics); + } + + /** + * Returns a TextHitInfo object that gives information on which division + * point (between two characters) is corresponds to a hit (such as a mouse + * click) at the specified coordinates. + * + * @param x + * the X coordinate in this TextLayout. + * @param y + * the Y coordinate in this TextLayout. TextHitInfo object + * corresponding to the given coordinates within the text. + * @return the information about the character at the specified position. + */ + public TextHitInfo hitTestChar(float x, float y) { + return hitTestChar(x, y, getBounds()); + } + + /** + * Returns a TextHitInfo object that gives information on which division + * point (between two characters) is corresponds to a hit (such as a mouse + * click) at the specified coordinates within the specified text rectangle. + * + * @param x + * the X coordinate in this TextLayout. + * @param y + * the Y coordinate in this TextLayout. + * @param bounds + * the bounds of the text area. TextHitInfo object corresponding + * to the given coordinates within the text. + * @return the information about the character at the specified position. + */ + public TextHitInfo hitTestChar(float x, float y, Rectangle2D bounds) { + if (x > bounds.getMaxX()) { + return breaker.isLTR() ? TextHitInfo.trailing(breaker.getCharCount() - 1) : TextHitInfo + .leading(0); + } + + if (x < bounds.getMinX()) { + return breaker.isLTR() ? TextHitInfo.leading(0) : TextHitInfo.trailing(breaker + .getCharCount() - 1); + } + + return breaker.hitTest(x, y); + } + + /** + * Returns true if this TextLayout has a "left to right" direction. + * + * @return true if this TextLayout has a "left to right" direction, false if + * this TextLayout has a "right to left" direction. + */ + public boolean isLeftToRight() { + return breaker.isLTR(); + } + + /** + * Returns true if this TextLayout is vertical, false otherwise. + * + * @return true if this TextLayout is vertical, false if horizontal. + */ + public boolean isVertical() { + return false; + } +} diff --git a/awt/java/awt/font/TextMeasurer.java b/awt/java/awt/font/TextMeasurer.java new file mode 100644 index 0000000..9741f59 --- /dev/null +++ b/awt/java/awt/font/TextMeasurer.java @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt.font; + +import java.text.AttributedCharacterIterator; + +import org.apache.harmony.awt.gl.font.TextMetricsCalculator; +import org.apache.harmony.awt.gl.font.TextRunBreaker; + +/** + * The TextMeasurer class provides utilities for line break operations. + * + * @since Android 1.0 + */ +public final class TextMeasurer implements Cloneable { + + /** + * The aci. + */ + AttributedCharacterIterator aci; + + /** + * The frc. + */ + FontRenderContext frc; + + /** + * The breaker. + */ + TextRunBreaker breaker = null; + + /** + * The tmc. + */ + TextMetricsCalculator tmc = null; + + /** + * Instantiates a new text measurer from the specified text. + * + * @param text + * the source text. + * @param frc + * the FontRenderContext. + */ + public TextMeasurer(AttributedCharacterIterator text, FontRenderContext frc) { + this.aci = text; + this.frc = frc; + breaker = new TextRunBreaker(aci, this.frc); + tmc = new TextMetricsCalculator(breaker); + } + + /** + * Replaces the current text with the new text, inserting a break character + * at the specified insert position. + * + * @param newParagraph + * the new paragraph text. + * @param insertPos + * the position in the text where the character is inserted. + */ + public void insertChar(AttributedCharacterIterator newParagraph, int insertPos) { + AttributedCharacterIterator oldAci = aci; + aci = newParagraph; + if ((oldAci.getEndIndex() - oldAci.getBeginIndex()) + - (aci.getEndIndex() - aci.getBeginIndex()) != -1) { + breaker = new TextRunBreaker(aci, this.frc); + tmc = new TextMetricsCalculator(breaker); + } else { + breaker.insertChar(newParagraph, insertPos); + } + } + + /** + * Replaces the current text with the new text and deletes a character at + * the specified position. + * + * @param newParagraph + * the paragraph text after deletion. + * @param deletePos + * the position in the text where the character is removed. + */ + public void deleteChar(AttributedCharacterIterator newParagraph, int deletePos) { + AttributedCharacterIterator oldAci = aci; + aci = newParagraph; + if ((oldAci.getEndIndex() - oldAci.getBeginIndex()) + - (aci.getEndIndex() - aci.getBeginIndex()) != 1) { + breaker = new TextRunBreaker(aci, this.frc); + tmc = new TextMetricsCalculator(breaker); + } else { + breaker.deleteChar(newParagraph, deletePos); + } + } + + /** + * Returns a copy of this object. + * + * @return a copy of this object. + */ + @Override + protected Object clone() { + return new TextMeasurer((AttributedCharacterIterator)aci.clone(), frc); + } + + /** + * Returns a TextLayout of the specified character range. + * + * @param start + * the index of the first character. + * @param limit + * the index after the last character. + * @return a TextLayout for the characters beginning at "start" up to "end". + */ + public TextLayout getLayout(int start, int limit) { + breaker.pushSegments(start - aci.getBeginIndex(), limit - aci.getBeginIndex()); + + breaker.createAllSegments(); + TextLayout layout = new TextLayout((TextRunBreaker)breaker.clone()); + + breaker.popSegments(); + return layout; + } + + /** + * Returns the graphical width of a line beginning at "start" parameter and + * including characters up to "end" parameter. "start" and "end" are + * absolute indices, not relative to the "start" of the paragraph. + * + * @param start + * the character index at which to start measuring. + * @param end + * the character index at which to stop measuring. + * @return the graphical width of a line beginning at "start" and including + * characters up to "end". + */ + public float getAdvanceBetween(int start, int end) { + breaker.pushSegments(start - aci.getBeginIndex(), end - aci.getBeginIndex()); + + breaker.createAllSegments(); + float retval = tmc.createMetrics().getAdvance(); + + breaker.popSegments(); + return retval; + } + + /** + * Returns the index of the first character which is not fit on a line + * beginning at start and possible measuring up to maxAdvance in graphical + * width. + * + * @param start + * he character index at which to start measuring. + * @param maxAdvance + * the graphical width in which the line must fit. + * @return the index after the last character that is fit on a line + * beginning at start, which is not longer than maxAdvance in + * graphical width. + */ + public int getLineBreakIndex(int start, float maxAdvance) { + breaker.createAllSegments(); + return breaker.getLineBreakIndex(start - aci.getBeginIndex(), maxAdvance) + + aci.getBeginIndex(); + } +} diff --git a/awt/java/awt/font/TransformAttribute.java b/awt/java/awt/font/TransformAttribute.java new file mode 100644 index 0000000..ff2caa2 --- /dev/null +++ b/awt/java/awt/font/TransformAttribute.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.geom.AffineTransform; +import java.io.Serializable; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The TransformAttribute class is a wrapper for the AffineTransform class in + * order to use it as attribute. + * + * @since Android 1.0 + */ +public final class TransformAttribute implements Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 3356247357827709530L; + + // affine transform of this TransformAttribute instance + /** + * The transform. + */ + private AffineTransform fTransform; + + /** + * Instantiates a new TransformAttribute from the specified AffineTransform. + * + * @param transform + * the AffineTransform to be wrapped. + */ + public TransformAttribute(AffineTransform transform) { + if (transform == null) { + // awt.94=transform can not be null + throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$ + } + if (!transform.isIdentity()) { + this.fTransform = new AffineTransform(transform); + } + } + + /** + * Gets the initial AffineTransform which is wrapped. + * + * @return the initial AffineTransform which is wrapped. + */ + public AffineTransform getTransform() { + if (fTransform != null) { + return new AffineTransform(fTransform); + } + return new AffineTransform(); + } + + /** + * Checks if this transform is an identity transform. + * + * @return true, if this transform is an identity transform, false + * otherwise. + */ + public boolean isIdentity() { + return (fTransform == null); + } + +} diff --git a/awt/java/awt/font/package.html b/awt/java/awt/font/package.html new file mode 100644 index 0000000..788dcc0 --- /dev/null +++ b/awt/java/awt/font/package.html @@ -0,0 +1,8 @@ +<html> + <body> + <p> + This package contains classes to support the representation of different types of fonts for example TrueType fonts. + </p> + @since Android 1.0 + </body> +</html> diff --git a/awt/java/awt/geom/AffineTransform.java b/awt/java/awt/geom/AffineTransform.java new file mode 100644 index 0000000..8a6938c --- /dev/null +++ b/awt/java/awt/geom/AffineTransform.java @@ -0,0 +1,1267 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt.geom; + +import java.awt.Shape; +import java.io.IOException; +import java.io.Serializable; + +import org.apache.harmony.awt.internal.nls.Messages; +import org.apache.harmony.misc.HashCode; + +/** + * The Class AffineTransform represents a linear transformation (rotation, + * scaling, or shear) followed by a translation that acts on a coordinate space. + * It preserves collinearity of points and ratios of distances between collinear + * points: so if A, B, and C are on a line, then after the space has been + * transformed via the affine transform, the images of the three points will + * still be on a line, and the ratio of the distance from A to B with the + * distance from B to C will be the same as the corresponding ratio in the image + * space. + * + * @since Android 1.0 + */ +public class AffineTransform implements Cloneable, Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 1330973210523860834L; + + /** + * The Constant TYPE_IDENTITY. + */ + public static final int TYPE_IDENTITY = 0; + + /** + * The Constant TYPE_TRANSLATION. + */ + public static final int TYPE_TRANSLATION = 1; + + /** + * The Constant TYPE_UNIFORM_SCALE. + */ + public static final int TYPE_UNIFORM_SCALE = 2; + + /** + * The Constant TYPE_GENERAL_SCALE. + */ + public static final int TYPE_GENERAL_SCALE = 4; + + /** + * The Constant TYPE_QUADRANT_ROTATION. + */ + public static final int TYPE_QUADRANT_ROTATION = 8; + + /** + * The Constant TYPE_GENERAL_ROTATION. + */ + public static final int TYPE_GENERAL_ROTATION = 16; + + /** + * The Constant TYPE_GENERAL_TRANSFORM. + */ + public static final int TYPE_GENERAL_TRANSFORM = 32; + + /** + * The Constant TYPE_FLIP. + */ + public static final int TYPE_FLIP = 64; + + /** + * The Constant TYPE_MASK_SCALE. + */ + public static final int TYPE_MASK_SCALE = TYPE_UNIFORM_SCALE | TYPE_GENERAL_SCALE; + + /** + * The Constant TYPE_MASK_ROTATION. + */ + public static final int TYPE_MASK_ROTATION = TYPE_QUADRANT_ROTATION | TYPE_GENERAL_ROTATION; + + /** + * The <code>TYPE_UNKNOWN</code> is an initial type value. + */ + static final int TYPE_UNKNOWN = -1; + + /** + * The min value equivalent to zero. If absolute value less then ZERO it + * considered as zero. + */ + static final double ZERO = 1E-10; + + /** + * The values of transformation matrix. + */ + double m00; + + /** + * The m10. + */ + double m10; + + /** + * The m01. + */ + double m01; + + /** + * The m11. + */ + double m11; + + /** + * The m02. + */ + double m02; + + /** + * The m12. + */ + double m12; + + /** + * The transformation <code>type</code>. + */ + transient int type; + + /** + * Instantiates a new affine transform of type <code>TYPE_IDENTITY</code> + * (which leaves coordinates unchanged). + */ + public AffineTransform() { + type = TYPE_IDENTITY; + m00 = m11 = 1.0; + m10 = m01 = m02 = m12 = 0.0; + } + + /** + * Instantiates a new affine transform that has the same data as the given + * AffineTransform. + * + * @param t + * the transform to copy. + */ + public AffineTransform(AffineTransform t) { + this.type = t.type; + this.m00 = t.m00; + this.m10 = t.m10; + this.m01 = t.m01; + this.m11 = t.m11; + this.m02 = t.m02; + this.m12 = t.m12; + } + + /** + * Instantiates a new affine transform by specifying the values of the 2x3 + * transformation matrix as floats. The type is set to the default type: + * <code>TYPE_UNKNOWN</code> + * + * @param m00 + * the m00 entry in the transformation matrix. + * @param m10 + * the m10 entry in the transformation matrix. + * @param m01 + * the m01 entry in the transformation matrix. + * @param m11 + * the m11 entry in the transformation matrix. + * @param m02 + * the m02 entry in the transformation matrix. + * @param m12 + * the m12 entry in the transformation matrix. + */ + public AffineTransform(float m00, float m10, float m01, float m11, float m02, float m12) { + this.type = TYPE_UNKNOWN; + this.m00 = m00; + this.m10 = m10; + this.m01 = m01; + this.m11 = m11; + this.m02 = m02; + this.m12 = m12; + } + + /** + * Instantiates a new affine transform by specifying the values of the 2x3 + * transformation matrix as doubles. The type is set to the default type: + * <code>TYPE_UNKNOWN</code> + * + * @param m00 + * the m00 entry in the transformation matrix. + * @param m10 + * the m10 entry in the transformation matrix. + * @param m01 + * the m01 entry in the transformation matrix. + * @param m11 + * the m11 entry in the transformation matrix. + * @param m02 + * the m02 entry in the transformation matrix. + * @param m12 + * the m12 entry in the transformation matrix. + */ + public AffineTransform(double m00, double m10, double m01, double m11, double m02, double m12) { + this.type = TYPE_UNKNOWN; + this.m00 = m00; + this.m10 = m10; + this.m01 = m01; + this.m11 = m11; + this.m02 = m02; + this.m12 = m12; + } + + /** + * Instantiates a new affine transform by reading the values of the + * transformation matrix from an array of floats. The mapping from the array + * to the matrix starts with <code>matrix[0]</code> giving the top-left + * entry of the matrix and proceeds with the usual left-to-right and + * top-down ordering. + * <p> + * If the array has only four entries, then the two entries of the last row + * of the transformation matrix default to zero. + * + * @param matrix + * the array of four or six floats giving the values of the + * matrix. + * @throws ArrayIndexOutOfBoundsException + * if the size of the array is 0, 1, 2, 3, or 5. + */ + public AffineTransform(float[] matrix) { + this.type = TYPE_UNKNOWN; + m00 = matrix[0]; + m10 = matrix[1]; + m01 = matrix[2]; + m11 = matrix[3]; + if (matrix.length > 4) { + m02 = matrix[4]; + m12 = matrix[5]; + } + } + + /** + * Instantiates a new affine transform by reading the values of the + * transformation matrix from an array of doubles. The mapping from the + * array to the matrix starts with <code>matrix[0]</code> giving the + * top-left entry of the matrix and proceeds with the usual left-to-right + * and top-down ordering. + * <p> + * If the array has only four entries, then the two entries of the last row + * of the transformation matrix default to zero. + * + * @param matrix + * the array of four or six doubles giving the values of the + * matrix. + * @throws ArrayIndexOutOfBoundsException + * if the size of the array is 0, 1, 2, 3, or 5. + */ + public AffineTransform(double[] matrix) { + this.type = TYPE_UNKNOWN; + m00 = matrix[0]; + m10 = matrix[1]; + m01 = matrix[2]; + m11 = matrix[3]; + if (matrix.length > 4) { + m02 = matrix[4]; + m12 = matrix[5]; + } + } + + /** + * Returns type of the affine transformation. + * <p> + * The type is computed as follows: Label the entries of the transformation + * matrix as three rows (m00, m01), (m10, m11), and (m02, m12). Then if the + * original basis vectors are (1, 0) and (0, 1), the new basis vectors after + * transformation are given by (m00, m01) and (m10, m11), and the + * translation vector is (m02, m12). + * <p> + * The types are classified as follows: <br/> TYPE_IDENTITY - no change<br/> + * TYPE_TRANSLATION - The translation vector isn't zero<br/> + * TYPE_UNIFORM_SCALE - The new basis vectors have equal length<br/> + * TYPE_GENERAL_SCALE - The new basis vectors dont' have equal length<br/> + * TYPE_FLIP - The new basis vector orientation differs from the original + * one<br/> TYPE_QUADRANT_ROTATION - The new basis is a rotation of the + * original by 90, 180, 270, or 360 degrees<br/> TYPE_GENERAL_ROTATION - The + * new basis is a rotation of the original by an arbitrary angle<br/> + * TYPE_GENERAL_TRANSFORM - The transformation can't be inverted.<br/> + * <p> + * Note that multiple types are possible, thus the types can be combined + * using bitwise combinations. + * + * @return the type of the Affine Transform. + */ + public int getType() { + if (type != TYPE_UNKNOWN) { + return type; + } + + int type = 0; + + if (m00 * m01 + m10 * m11 != 0.0) { + type |= TYPE_GENERAL_TRANSFORM; + return type; + } + + if (m02 != 0.0 || m12 != 0.0) { + type |= TYPE_TRANSLATION; + } else if (m00 == 1.0 && m11 == 1.0 && m01 == 0.0 && m10 == 0.0) { + type = TYPE_IDENTITY; + return type; + } + + if (m00 * m11 - m01 * m10 < 0.0) { + type |= TYPE_FLIP; + } + + double dx = m00 * m00 + m10 * m10; + double dy = m01 * m01 + m11 * m11; + if (dx != dy) { + type |= TYPE_GENERAL_SCALE; + } else if (dx != 1.0) { + type |= TYPE_UNIFORM_SCALE; + } + + if ((m00 == 0.0 && m11 == 0.0) || (m10 == 0.0 && m01 == 0.0 && (m00 < 0.0 || m11 < 0.0))) { + type |= TYPE_QUADRANT_ROTATION; + } else if (m01 != 0.0 || m10 != 0.0) { + type |= TYPE_GENERAL_ROTATION; + } + + return type; + } + + /** + * Gets the scale x entry of the transformation matrix (the upper left + * matrix entry). + * + * @return the scale x value. + */ + public double getScaleX() { + return m00; + } + + /** + * Gets the scale y entry of the transformation matrix (the lower right + * entry of the linear transformation). + * + * @return the scale y value. + */ + public double getScaleY() { + return m11; + } + + /** + * Gets the shear x entry of the transformation matrix (the upper right + * entry of the linear transformation). + * + * @return the shear x value. + */ + public double getShearX() { + return m01; + } + + /** + * Gets the shear y entry of the transformation matrix (the lower left entry + * of the linear transformation). + * + * @return the shear y value. + */ + public double getShearY() { + return m10; + } + + /** + * Gets the x coordinate of the translation vector. + * + * @return the x coordinate of the translation vector. + */ + public double getTranslateX() { + return m02; + } + + /** + * Gets the y coordinate of the translation vector. + * + * @return the y coordinate of the translation vector. + */ + public double getTranslateY() { + return m12; + } + + /** + * Checks if the AffineTransformation is the identity. + * + * @return true, if the AffineTransformation is the identity. + */ + public boolean isIdentity() { + return getType() == TYPE_IDENTITY; + } + + /** + * Writes the values of the transformation matrix into the given array of + * doubles. If the array has length 4, only the linear transformation part + * will be written into it. If it has length greater than 4, the translation + * vector will be included as well. + * + * @param matrix + * the array to fill with the values of the matrix. + * @throws ArrayIndexOutOfBoundsException + * if the size of the array is 0, 1, 2, 3, or 5. + */ + public void getMatrix(double[] matrix) { + matrix[0] = m00; + matrix[1] = m10; + matrix[2] = m01; + matrix[3] = m11; + if (matrix.length > 4) { + matrix[4] = m02; + matrix[5] = m12; + } + } + + /** + * Gets the determinant of the linear transformation matrix. + * + * @return the determinant of the linear transformation matrix. + */ + public double getDeterminant() { + return m00 * m11 - m01 * m10; + } + + /** + * Sets the transform in terms of a list of double values. + * + * @param m00 + * the m00 coordinate of the transformation matrix. + * @param m10 + * the m10 coordinate of the transformation matrix. + * @param m01 + * the m01 coordinate of the transformation matrix. + * @param m11 + * the m11 coordinate of the transformation matrix. + * @param m02 + * the m02 coordinate of the transformation matrix. + * @param m12 + * the m12 coordinate of the transformation matrix. + */ + public void setTransform(double m00, double m10, double m01, double m11, double m02, double m12) { + this.type = TYPE_UNKNOWN; + this.m00 = m00; + this.m10 = m10; + this.m01 = m01; + this.m11 = m11; + this.m02 = m02; + this.m12 = m12; + } + + /** + * Sets the transform's data to match the data of the transform sent as a + * parameter. + * + * @param t + * the transform that gives the new values. + */ + public void setTransform(AffineTransform t) { + type = t.type; + setTransform(t.m00, t.m10, t.m01, t.m11, t.m02, t.m12); + } + + /** + * Sets the transform to the identity transform. + */ + public void setToIdentity() { + type = TYPE_IDENTITY; + m00 = m11 = 1.0; + m10 = m01 = m02 = m12 = 0.0; + } + + /** + * Sets the transformation to a translation alone. Sets the linear part of + * the transformation to identity and the translation vector to the values + * sent as parameters. Sets the type to <code>TYPE_IDENTITY</code> if the + * resulting AffineTransformation is the identity transformation, otherwise + * sets it to <code>TYPE_TRANSLATION</code>. + * + * @param mx + * the distance to translate in the x direction. + * @param my + * the distance to translate in the y direction. + */ + public void setToTranslation(double mx, double my) { + m00 = m11 = 1.0; + m01 = m10 = 0.0; + m02 = mx; + m12 = my; + if (mx == 0.0 && my == 0.0) { + type = TYPE_IDENTITY; + } else { + type = TYPE_TRANSLATION; + } + } + + /** + * Sets the transformation to being a scale alone, eliminating rotation, + * shear, and translation elements. Sets the type to + * <code>TYPE_IDENTITY</code> if the resulting AffineTransformation is the + * identity transformation, otherwise sets it to <code>TYPE_UNKNOWN</code>. + * + * @param scx + * the scaling factor in the x direction. + * @param scy + * the scaling factor in the y direction. + */ + public void setToScale(double scx, double scy) { + m00 = scx; + m11 = scy; + m10 = m01 = m02 = m12 = 0.0; + if (scx != 1.0 || scy != 1.0) { + type = TYPE_UNKNOWN; + } else { + type = TYPE_IDENTITY; + } + } + + /** + * Sets the transformation to being a shear alone, eliminating rotation, + * scaling, and translation elements. Sets the type to + * <code>TYPE_IDENTITY</code> if the resulting AffineTransformation is the + * identity transformation, otherwise sets it to <code>TYPE_UNKNOWN</code>. + * + * @param shx + * the shearing factor in the x direction. + * @param shy + * the shearing factor in the y direction. + */ + public void setToShear(double shx, double shy) { + m00 = m11 = 1.0; + m02 = m12 = 0.0; + m01 = shx; + m10 = shy; + if (shx != 0.0 || shy != 0.0) { + type = TYPE_UNKNOWN; + } else { + type = TYPE_IDENTITY; + } + } + + /** + * Sets the transformation to being a rotation alone, eliminating shearing, + * scaling, and translation elements. Sets the type to + * <code>TYPE_IDENTITY</code> if the resulting AffineTransformation is the + * identity transformation, otherwise sets it to <code>TYPE_UNKNOWN</code>. + * + * @param angle + * the angle of rotation in radians. + */ + public void setToRotation(double angle) { + double sin = Math.sin(angle); + double cos = Math.cos(angle); + if (Math.abs(cos) < ZERO) { + cos = 0.0; + sin = sin > 0.0 ? 1.0 : -1.0; + } else if (Math.abs(sin) < ZERO) { + sin = 0.0; + cos = cos > 0.0 ? 1.0 : -1.0; + } + m00 = m11 = cos; + m01 = -sin; + m10 = sin; + m02 = m12 = 0.0; + type = TYPE_UNKNOWN; + } + + /** + * Sets the transformation to being a rotation followed by a translation. + * Sets the type to <code>TYPE_UNKNOWN</code>. + * + * @param angle + * the angle of rotation in radians. + * @param px + * the distance to translate in the x direction. + * @param py + * the distance to translate in the y direction. + */ + public void setToRotation(double angle, double px, double py) { + setToRotation(angle); + m02 = px * (1.0 - m00) + py * m10; + m12 = py * (1.0 - m00) - px * m10; + type = TYPE_UNKNOWN; + } + + /** + * Creates a new AffineTransformation that is a translation alone with the + * translation vector given by the values sent as parameters. The new + * transformation's type is <code>TYPE_IDENTITY</code> if the + * AffineTransformation is the identity transformation, otherwise it's + * <code>TYPE_TRANSLATION</code>. + * + * @param mx + * the distance to translate in the x direction. + * @param my + * the distance to translate in the y direction. + * @return the new AffineTransformation. + */ + public static AffineTransform getTranslateInstance(double mx, double my) { + AffineTransform t = new AffineTransform(); + t.setToTranslation(mx, my); + return t; + } + + /** + * Creates a new AffineTransformation that is a scale alone. The new + * transformation's type is <code>TYPE_IDENTITY</code> if the + * AffineTransformation is the identity transformation, otherwise it's + * <code>TYPE_UNKNOWN</code>. + * + * @param scx + * the scaling factor in the x direction. + * @param scY + * the scaling factor in the y direction. + * @return the new AffineTransformation. + */ + public static AffineTransform getScaleInstance(double scx, double scY) { + AffineTransform t = new AffineTransform(); + t.setToScale(scx, scY); + return t; + } + + /** + * Creates a new AffineTransformation that is a shear alone. The new + * transformation's type is <code>TYPE_IDENTITY</code> if the + * AffineTransformation is the identity transformation, otherwise it's + * <code>TYPE_UNKNOWN</code>. + * + * @param shx + * the shearing factor in the x direction. + * @param shy + * the shearing factor in the y direction. + * @return the new AffineTransformation. + */ + public static AffineTransform getShearInstance(double shx, double shy) { + AffineTransform m = new AffineTransform(); + m.setToShear(shx, shy); + return m; + } + + /** + * Creates a new AffineTransformation that is a rotation alone. The new + * transformation's type is <code>TYPE_IDENTITY</code> if the + * AffineTransformation is the identity transformation, otherwise it's + * <code>TYPE_UNKNOWN</code>. + * + * @param angle + * the angle of rotation in radians. + * @return the new AffineTransformation. + */ + public static AffineTransform getRotateInstance(double angle) { + AffineTransform t = new AffineTransform(); + t.setToRotation(angle); + return t; + } + + /** + * Creates a new AffineTransformation that is a rotation followed by a + * translation. Sets the type to <code>TYPE_UNKNOWN</code>. + * + * @param angle + * the angle of rotation in radians. + * @param x + * the distance to translate in the x direction. + * @param y + * the distance to translate in the y direction. + * @return the new AffineTransformation. + */ + public static AffineTransform getRotateInstance(double angle, double x, double y) { + AffineTransform t = new AffineTransform(); + t.setToRotation(angle, x, y); + return t; + } + + /** + * Applies a translation to this AffineTransformation. + * + * @param mx + * the distance to translate in the x direction. + * @param my + * the distance to translate in the y direction. + */ + public void translate(double mx, double my) { + concatenate(AffineTransform.getTranslateInstance(mx, my)); + } + + /** + * Applies a scaling transformation to this AffineTransformation. + * + * @param scx + * the scaling factor in the x direction. + * @param scy + * the scaling factor in the y direction. + */ + public void scale(double scx, double scy) { + concatenate(AffineTransform.getScaleInstance(scx, scy)); + } + + /** + * Applies a shearing transformation to this AffineTransformation. + * + * @param shx + * the shearing factor in the x direction. + * @param shy + * the shearing factor in the y direction. + */ + public void shear(double shx, double shy) { + concatenate(AffineTransform.getShearInstance(shx, shy)); + } + + /** + * Applies a rotation transformation to this AffineTransformation. + * + * @param angle + * the angle of rotation in radians. + */ + public void rotate(double angle) { + concatenate(AffineTransform.getRotateInstance(angle)); + } + + /** + * Applies a rotation and translation transformation to this + * AffineTransformation. + * + * @param angle + * the angle of rotation in radians. + * @param px + * the distance to translate in the x direction. + * @param py + * the distance to translate in the y direction. + */ + public void rotate(double angle, double px, double py) { + concatenate(AffineTransform.getRotateInstance(angle, px, py)); + } + + /** + * Multiplies the matrix representations of two AffineTransform objects. + * + * @param t1 + * - the AffineTransform object is a multiplicand + * @param t2 + * - the AffineTransform object is a multiplier + * @return an AffineTransform object that is the result of t1 multiplied by + * the matrix t2. + */ + AffineTransform multiply(AffineTransform t1, AffineTransform t2) { + return new AffineTransform(t1.m00 * t2.m00 + t1.m10 * t2.m01, // m00 + t1.m00 * t2.m10 + t1.m10 * t2.m11, // m01 + t1.m01 * t2.m00 + t1.m11 * t2.m01, // m10 + t1.m01 * t2.m10 + t1.m11 * t2.m11, // m11 + t1.m02 * t2.m00 + t1.m12 * t2.m01 + t2.m02, // m02 + t1.m02 * t2.m10 + t1.m12 * t2.m11 + t2.m12);// m12 + } + + /** + * Applies the given AffineTransform to this AffineTransform via matrix + * multiplication. + * + * @param t + * the AffineTransform to apply to this AffineTransform. + */ + public void concatenate(AffineTransform t) { + setTransform(multiply(t, this)); + } + + /** + * Changes the current AffineTransform the one obtained by taking the + * transform t and applying this AffineTransform to it. + * + * @param t + * the AffineTransform that this AffineTransform is multiplied + * by. + */ + public void preConcatenate(AffineTransform t) { + setTransform(multiply(this, t)); + } + + /** + * Creates an AffineTransform that is the inverse of this transform. + * + * @return the affine transform that is the inverse of this AffineTransform. + * @throws NoninvertibleTransformException + * if this AffineTransform cannot be inverted (the determinant + * of the linear transformation part is zero). + */ + public AffineTransform createInverse() throws NoninvertibleTransformException { + double det = getDeterminant(); + if (Math.abs(det) < ZERO) { + // awt.204=Determinant is zero + throw new NoninvertibleTransformException(Messages.getString("awt.204")); //$NON-NLS-1$ + } + return new AffineTransform(m11 / det, // m00 + -m10 / det, // m10 + -m01 / det, // m01 + m00 / det, // m11 + (m01 * m12 - m11 * m02) / det, // m02 + (m10 * m02 - m00 * m12) / det // m12 + ); + } + + /** + * Apply the current AffineTransform to the point. + * + * @param src + * the original point. + * @param dst + * Point2D object to be filled with the destination coordinates + * (where the original point is sent by this AffineTransform). + * May be null. + * @return the point in the AffineTransform's image space where the original + * point is sent. + */ + public Point2D transform(Point2D src, Point2D dst) { + if (dst == null) { + if (src instanceof Point2D.Double) { + dst = new Point2D.Double(); + } else { + dst = new Point2D.Float(); + } + } + + double x = src.getX(); + double y = src.getY(); + + dst.setLocation(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12); + return dst; + } + + /** + * Applies this AffineTransform to an array of points. + * + * @param src + * the array of points to be transformed. + * @param srcOff + * the offset in the source point array of the first point to be + * transformed. + * @param dst + * the point array where the images of the points (after applying + * the AffineTransformation) should be placed. + * @param dstOff + * the offset in the destination array where the new values + * should be written. + * @param length + * the number of points to transform. + * @throws ArrayIndexOutOfBoundsException + * if <code>srcOff + length > src.length</code> or + * <code>dstOff + length > dst.length</code>. + */ + public void transform(Point2D[] src, int srcOff, Point2D[] dst, int dstOff, int length) { + while (--length >= 0) { + Point2D srcPoint = src[srcOff++]; + double x = srcPoint.getX(); + double y = srcPoint.getY(); + Point2D dstPoint = dst[dstOff]; + if (dstPoint == null) { + if (srcPoint instanceof Point2D.Double) { + dstPoint = new Point2D.Double(); + } else { + dstPoint = new Point2D.Float(); + } + } + dstPoint.setLocation(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12); + dst[dstOff++] = dstPoint; + } + } + + /** + * Applies this AffineTransform to a set of points given as an array of + * double values where every two values in the array give the coordinates of + * a point; the even-indexed values giving the x coordinates and the + * odd-indexed values giving the y coordinates. + * + * @param src + * the array of points to be transformed. + * @param srcOff + * the offset in the source point array of the first point to be + * transformed. + * @param dst + * the point array where the images of the points (after applying + * the AffineTransformation) should be placed. + * @param dstOff + * the offset in the destination array where the new values + * should be written. + * @param length + * the number of points to transform. + * @throws ArrayIndexOutOfBoundsException + * if <code>srcOff + length*2 > src.length</code> or + * <code>dstOff + length*2 > dst.length</code>. + */ + public void transform(double[] src, int srcOff, double[] dst, int dstOff, int length) { + int step = 2; + if (src == dst && srcOff < dstOff && dstOff < srcOff + length * 2) { + srcOff = srcOff + length * 2 - 2; + dstOff = dstOff + length * 2 - 2; + step = -2; + } + while (--length >= 0) { + double x = src[srcOff + 0]; + double y = src[srcOff + 1]; + dst[dstOff + 0] = x * m00 + y * m01 + m02; + dst[dstOff + 1] = x * m10 + y * m11 + m12; + srcOff += step; + dstOff += step; + } + } + + /** + * Applies this AffineTransform to a set of points given as an array of + * float values where every two values in the array give the coordinates of + * a point; the even-indexed values giving the x coordinates and the + * odd-indexed values giving the y coordinates. + * + * @param src + * the array of points to be transformed. + * @param srcOff + * the offset in the source point array of the first point to be + * transformed. + * @param dst + * the point array where the images of the points (after applying + * the AffineTransformation) should be placed. + * @param dstOff + * the offset in the destination array where the new values + * should be written. + * @param length + * the number of points to transform. + * @throws ArrayIndexOutOfBoundsException + * if <code>srcOff + length*2 > src.length</code> or + * <code>dstOff + length*2 > dst.length</code>. + */ + public void transform(float[] src, int srcOff, float[] dst, int dstOff, int length) { + int step = 2; + if (src == dst && srcOff < dstOff && dstOff < srcOff + length * 2) { + srcOff = srcOff + length * 2 - 2; + dstOff = dstOff + length * 2 - 2; + step = -2; + } + while (--length >= 0) { + float x = src[srcOff + 0]; + float y = src[srcOff + 1]; + dst[dstOff + 0] = (float)(x * m00 + y * m01 + m02); + dst[dstOff + 1] = (float)(x * m10 + y * m11 + m12); + srcOff += step; + dstOff += step; + } + } + + /** + * Applies this AffineTransform to a set of points given as an array of + * float values where every two values in the array give the coordinates of + * a point; the even-indexed values giving the x coordinates and the + * odd-indexed values giving the y coordinates. The destination coordinates + * are given as values of type <code>double</code>. + * + * @param src + * the array of points to be transformed. + * @param srcOff + * the offset in the source point array of the first point to be + * transformed. + * @param dst + * the point array where the images of the points (after applying + * the AffineTransformation) should be placed. + * @param dstOff + * the offset in the destination array where the new values + * should be written. + * @param length + * the number of points to transform. + * @throws ArrayIndexOutOfBoundsException + * if <code>srcOff + length*2 > src.length</code> or + * <code>dstOff + length*2 > dst.length</code>. + */ + public void transform(float[] src, int srcOff, double[] dst, int dstOff, int length) { + while (--length >= 0) { + float x = src[srcOff++]; + float y = src[srcOff++]; + dst[dstOff++] = x * m00 + y * m01 + m02; + dst[dstOff++] = x * m10 + y * m11 + m12; + } + } + + /** + * Applies this AffineTransform to a set of points given as an array of + * double values where every two values in the array give the coordinates of + * a point; the even-indexed values giving the x coordinates and the + * odd-indexed values giving the y coordinates. The destination coordinates + * are given as values of type <code>float</code>. + * + * @param src + * the array of points to be transformed. + * @param srcOff + * the offset in the source point array of the first point to be + * transformed. + * @param dst + * the point array where the images of the points (after applying + * the AffineTransformation) should be placed. + * @param dstOff + * the offset in the destination array where the new values + * should be written. + * @param length + * the number of points to transform. + * @throws ArrayIndexOutOfBoundsException + * if <code>srcOff + length*2 > src.length</code> or + * <code>dstOff + length*2 > dst.length</code>. + */ + public void transform(double[] src, int srcOff, float[] dst, int dstOff, int length) { + while (--length >= 0) { + double x = src[srcOff++]; + double y = src[srcOff++]; + dst[dstOff++] = (float)(x * m00 + y * m01 + m02); + dst[dstOff++] = (float)(x * m10 + y * m11 + m12); + } + } + + /** + * Transforms the point according to the linear transformation part of this + * AffineTransformation (without applying the translation). + * + * @param src + * the original point. + * @param dst + * the point object where the result of the delta transform is + * written. + * @return the result of applying the delta transform (linear part only) to + * the original point. + */ + // TODO: is this right? if dst is null, we check what it's an + // instance of? Shouldn't it be src instanceof Point2D.Double? + public Point2D deltaTransform(Point2D src, Point2D dst) { + if (dst == null) { + if (dst instanceof Point2D.Double) { + dst = new Point2D.Double(); + } else { + dst = new Point2D.Float(); + } + } + + double x = src.getX(); + double y = src.getY(); + + dst.setLocation(x * m00 + y * m01, x * m10 + y * m11); + return dst; + } + + /** + * Applies the linear transformation part of this AffineTransform (ignoring + * the translation part) to a set of points given as an array of double + * values where every two values in the array give the coordinates of a + * point; the even-indexed values giving the x coordinates and the + * odd-indexed values giving the y coordinates. + * + * @param src + * the array of points to be transformed. + * @param srcOff + * the offset in the source point array of the first point to be + * transformed. + * @param dst + * the point array where the images of the points (after applying + * the delta transformation) should be placed. + * @param dstOff + * the offset in the destination array where the new values + * should be written. + * @param length + * the number of points to transform. + * @throws ArrayIndexOutOfBoundsException + * if <code>srcOff + length*2 > src.length</code> or + * <code>dstOff + length*2 > dst.length</code>. + */ + public void deltaTransform(double[] src, int srcOff, double[] dst, int dstOff, int length) { + while (--length >= 0) { + double x = src[srcOff++]; + double y = src[srcOff++]; + dst[dstOff++] = x * m00 + y * m01; + dst[dstOff++] = x * m10 + y * m11; + } + } + + /** + * Transforms the point according to the inverse of this + * AffineTransformation. + * + * @param src + * the original point. + * @param dst + * the point object where the result of the inverse transform is + * written (may be null). + * @return the result of applying the inverse transform. Inverse transform. + * @throws NoninvertibleTransformException + * if this AffineTransform cannot be inverted (the determinant + * of the linear transformation part is zero). + */ + public Point2D inverseTransform(Point2D src, Point2D dst) + throws NoninvertibleTransformException { + double det = getDeterminant(); + if (Math.abs(det) < ZERO) { + // awt.204=Determinant is zero + throw new NoninvertibleTransformException(Messages.getString("awt.204")); //$NON-NLS-1$ + } + + if (dst == null) { + if (src instanceof Point2D.Double) { + dst = new Point2D.Double(); + } else { + dst = new Point2D.Float(); + } + } + + double x = src.getX() - m02; + double y = src.getY() - m12; + + dst.setLocation((x * m11 - y * m01) / det, (y * m00 - x * m10) / det); + return dst; + } + + /** + * Applies the inverse of this AffineTransform to a set of points given as + * an array of double values where every two values in the array give the + * coordinates of a point; the even-indexed values giving the x coordinates + * and the odd-indexed values giving the y coordinates. + * + * @param src + * the array of points to be transformed. + * @param srcOff + * the offset in the source point array of the first point to be + * transformed. + * @param dst + * the point array where the images of the points (after applying + * the inverse of the AffineTransformation) should be placed. + * @param dstOff + * the offset in the destination array where the new values + * should be written. + * @param length + * the number of points to transform. + * @throws ArrayIndexOutOfBoundsException + * if <code>srcOff + length*2 > src.length</code> or + * <code>dstOff + length*2 > dst.length</code>. + * @throws NoninvertibleTransformException + * if this AffineTransform cannot be inverted (the determinant + * of the linear transformation part is zero). + */ + public void inverseTransform(double[] src, int srcOff, double[] dst, int dstOff, int length) + throws NoninvertibleTransformException { + double det = getDeterminant(); + if (Math.abs(det) < ZERO) { + // awt.204=Determinant is zero + throw new NoninvertibleTransformException(Messages.getString("awt.204")); //$NON-NLS-1$ + } + + while (--length >= 0) { + double x = src[srcOff++] - m02; + double y = src[srcOff++] - m12; + dst[dstOff++] = (x * m11 - y * m01) / det; + dst[dstOff++] = (y * m00 - x * m10) / det; + } + } + + /** + * Creates a new shape whose data is given by applying this AffineTransform + * to the specified shape. + * + * @param src + * the original shape whose data is to be transformed. + * @return the new shape found by applying this AffineTransform to the + * original shape. + */ + public Shape createTransformedShape(Shape src) { + if (src == null) { + return null; + } + if (src instanceof GeneralPath) { + return ((GeneralPath)src).createTransformedShape(this); + } + PathIterator path = src.getPathIterator(this); + GeneralPath dst = new GeneralPath(path.getWindingRule()); + dst.append(path, false); + return dst; + } + + @Override + public String toString() { + return getClass().getName() + "[[" + m00 + ", " + m01 + ", " + m02 + "], [" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + + m10 + ", " + m11 + ", " + m12 + "]]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + } + + @Override + public int hashCode() { + HashCode hash = new HashCode(); + hash.append(m00); + hash.append(m01); + hash.append(m02); + hash.append(m10); + hash.append(m11); + hash.append(m12); + return hash.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof AffineTransform) { + AffineTransform t = (AffineTransform)obj; + return m00 == t.m00 && m01 == t.m01 && m02 == t.m02 && m10 == t.m10 && m11 == t.m11 + && m12 == t.m12; + } + return false; + } + + /** + * Writes the AffineTrassform object to the output steam. + * + * @param stream + * - the output stream. + * @throws IOException + * - if there are I/O errors while writing to the output stream. + */ + private void writeObject(java.io.ObjectOutputStream stream) throws IOException { + stream.defaultWriteObject(); + } + + /** + * Read the AffineTransform object from the input stream. + * + * @param stream + * - the input stream. + * @throws IOException + * - if there are I/O errors while reading from the input + * stream. + * @throws ClassNotFoundException + * - if class could not be found. + */ + private void readObject(java.io.ObjectInputStream stream) throws IOException, + ClassNotFoundException { + stream.defaultReadObject(); + type = TYPE_UNKNOWN; + } + +} diff --git a/awt/java/awt/geom/Arc2D.java b/awt/java/awt/geom/Arc2D.java new file mode 100644 index 0000000..56f5cd3 --- /dev/null +++ b/awt/java/awt/geom/Arc2D.java @@ -0,0 +1,1157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt.geom; + +import java.util.NoSuchElementException; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class Arc2D represents a segment of a curve inscribed in a rectangle. The + * curve is defined by a start angle and an extent angle (the end angle minus + * the start angle) as a pie wedge whose point is in the center of the + * rectangle. The Arc2D as a shape may be either OPEN (including nothing but the + * curved arc segment itself), CHORD (the curved arc segment closed by a + * connecting segment from the end to the beginning of the arc, or PIE (the + * segments from the end of the arc to the center of the rectangle and from the + * center of the rectangle back to the arc's start point are included). + * + * @since Android 1.0 + */ +public abstract class Arc2D extends RectangularShape { + + /** + * The arc type OPEN indicates that the shape includes only the curved arc + * segment. + */ + public final static int OPEN = 0; + + /** + * The arc type CHORD indicates that as a shape the connecting segment from + * the end point of the curved arc to the beginning point is included. + */ + public final static int CHORD = 1; + + /** + * The arc type PIE indicates that as a shape the two segments from the + * arc's endpoint to the center of the rectangle and from the center of the + * rectangle to the arc's endpoint are included. + */ + public final static int PIE = 2; + + /** + * The Class Float is a subclass of Arc2D in which all of the data values + * are given as floats. + * + * @see Arc2D.Double + * @since Android 1.0 + */ + public static class Float extends Arc2D { + + /** + * The x coordinate of the upper left corner of the rectangle that + * contains the arc. + */ + public float x; + + /** + * The y coordinate of the upper left corner of the rectangle that + * contains the arc. + */ + public float y; + + /** + * The width of the rectangle that contains the arc. + */ + public float width; + + /** + * The height of the rectangle that contains the arc. + */ + public float height; + + /** + * The start angle of the arc in degrees. + */ + public float start; + + /** + * The width angle of the arc in degrees. + */ + public float extent; + + /** + * Instantiates a new Arc2D of type OPEN with float values. + */ + public Float() { + super(OPEN); + } + + /** + * Instantiates a new Arc2D of the specified type with float values. + * + * @param type + * the type of the new Arc2D, either {@link Arc2D#OPEN}, + * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + */ + public Float(int type) { + super(type); + } + + /** + * Instantiates a Arc2D with the specified float-valued data. + * + * @param x + * the x coordinate of the upper left corner of the rectangle + * that contains the arc. + * @param y + * the y coordinate of the upper left corner of the rectangle + * that contains the arc. + * @param width + * the width of the rectangle that contains the arc. + * @param height + * the height of the rectangle that contains the arc. + * @param start + * the start angle of the arc in degrees. + * @param extent + * the width angle of the arc in degrees. + * @param type + * the type of the new Arc2D, either {@link Arc2D#OPEN}, + * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + */ + public Float(float x, float y, float width, float height, float start, float extent, + int type) { + super(type); + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.start = start; + this.extent = extent; + } + + /** + * Instantiates a new Angle2D with the specified float-valued data and + * the bounding rectangle given by the parameter bounds. + * + * @param bounds + * the bounding rectangle of the Angle2D. + * @param start + * the start angle of the arc in degrees. + * @param extent + * the width angle of the arc in degrees. + * @param type + * the type of the new Arc2D, either {@link Arc2D#OPEN}, + * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + */ + public Float(Rectangle2D bounds, float start, float extent, int type) { + super(type); + this.x = (float)bounds.getX(); + this.y = (float)bounds.getY(); + this.width = (float)bounds.getWidth(); + this.height = (float)bounds.getHeight(); + this.start = start; + this.extent = extent; + } + + @Override + public double getX() { + return x; + } + + @Override + public double getY() { + return y; + } + + @Override + public double getWidth() { + return width; + } + + @Override + public double getHeight() { + return height; + } + + @Override + public double getAngleStart() { + return start; + } + + @Override + public double getAngleExtent() { + return extent; + } + + @Override + public boolean isEmpty() { + return width <= 0.0f || height <= 0.0f; + } + + @Override + public void setArc(double x, double y, double width, double height, double start, + double extent, int type) { + this.setArcType(type); + this.x = (float)x; + this.y = (float)y; + this.width = (float)width; + this.height = (float)height; + this.start = (float)start; + this.extent = (float)extent; + } + + @Override + public void setAngleStart(double start) { + this.start = (float)start; + } + + @Override + public void setAngleExtent(double extent) { + this.extent = (float)extent; + } + + @Override + protected Rectangle2D makeBounds(double x, double y, double width, double height) { + return new Rectangle2D.Float((float)x, (float)y, (float)width, (float)height); + } + + } + + /** + * The Class Double is a subclass of Arc2D in which all of the data values + * are given as doubles. + * + * @see Arc2D.Float + * @since Android 1.0 + */ + public static class Double extends Arc2D { + + /** + * The x coordinate of the upper left corner of the rectangle that + * contains the arc. + */ + public double x; + + /** + * The y coordinate of the upper left corner of the rectangle that + * contains the arc. + */ + public double y; + + /** + * The width of the rectangle that contains the arc. + */ + public double width; + + /** + * The height of the rectangle that contains the arc. + */ + public double height; + + /** + * The start angle of the arc in degrees. + */ + public double start; + + /** + * The width angle of the arc in degrees. + */ + public double extent; + + /** + * Instantiates a new Arc2D of type OPEN with double values. + */ + public Double() { + super(OPEN); + } + + /** + * Instantiates a new Arc2D of the specified type with double values. + * + * @param type + * the type of the new Arc2D, either {@link Arc2D#OPEN}, + * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + */ + public Double(int type) { + super(type); + } + + /** + * Instantiates a Arc2D with the specified double-valued data. + * + * @param x + * the x coordinate of the upper left corner of the rectangle + * that contains the arc. + * @param y + * the y coordinate of the upper left corner of the rectangle + * that contains the arc. + * @param width + * the width of the rectangle that contains the arc. + * @param height + * the height of the rectangle that contains the arc. + * @param start + * the start angle of the arc in degrees. + * @param extent + * the width angle of the arc in degrees. + * @param type + * the type of the new Arc2D, either {@link Arc2D#OPEN}, + * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + */ + public Double(double x, double y, double width, double height, double start, double extent, + int type) { + super(type); + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.start = start; + this.extent = extent; + } + + /** + * Instantiates a new Angle2D with the specified float-valued data and + * the bounding rectangle given by the parameter bounds. + * + * @param bounds + * the bounding rectangle of the Angle2D. + * @param start + * the start angle of the arc in degrees. + * @param extent + * the width angle of the arc in degrees. + * @param type + * the type of the new Arc2D, either {@link Arc2D#OPEN}, + * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + */ + public Double(Rectangle2D bounds, double start, double extent, int type) { + super(type); + this.x = bounds.getX(); + this.y = bounds.getY(); + this.width = bounds.getWidth(); + this.height = bounds.getHeight(); + this.start = start; + this.extent = extent; + } + + @Override + public double getX() { + return x; + } + + @Override + public double getY() { + return y; + } + + @Override + public double getWidth() { + return width; + } + + @Override + public double getHeight() { + return height; + } + + @Override + public double getAngleStart() { + return start; + } + + @Override + public double getAngleExtent() { + return extent; + } + + @Override + public boolean isEmpty() { + return width <= 0.0 || height <= 0.0; + } + + @Override + public void setArc(double x, double y, double width, double height, double start, + double extent, int type) { + this.setArcType(type); + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.start = start; + this.extent = extent; + } + + @Override + public void setAngleStart(double start) { + this.start = start; + } + + @Override + public void setAngleExtent(double extent) { + this.extent = extent; + } + + @Override + protected Rectangle2D makeBounds(double x, double y, double width, double height) { + return new Rectangle2D.Double(x, y, width, height); + } + + } + + /** + * The Class Iterator is the subclass of PathIterator that is used to + * traverse the boundary of a shape of type Arc2D. + */ + class Iterator implements PathIterator { + + /** + * The x coordinate of the center of the arc's bounding rectangle. + */ + double x; + + /** + * The y coordinate of the center of the arc's bounding rectangle. + */ + double y; + + /** + * Half of the width of the arc's bounding rectangle (the radius in the + * case of a circular arc). + */ + double width; + + /** + * Half of the height of the arc's bounding rectangle (the radius in the + * case of a circular arc). + */ + double height; + + /** + * The start angle of the arc in degrees. + */ + double angle; + + /** + * The angle extent in degrees. + */ + double extent; + + /** + * The closure type of the arc. + */ + int type; + + /** + * The path iterator transformation. + */ + AffineTransform t; + + /** + * The current segment index. + */ + int index; + + /** + * The number of arc segments the source arc subdivided to be + * approximated by Bezier curves. Depends on extent value. + */ + int arcCount; + + /** + * The number of line segments. Depends on closure type. + */ + int lineCount; + + /** + * The step to calculate next arc subdivision point. + */ + double step; + + /** + * The temporary value of cosinus of the current angle. + */ + double cos; + + /** + * The temporary value of sinus of the current angle. + */ + double sin; + + /** The coefficient to calculate control points of Bezier curves. */ + double k; + + /** + * The temporary value of x coordinate of the Bezier curve control + * vector. + */ + double kx; + + /** + * The temporary value of y coordinate of the Bezier curve control + * vector. + */ + double ky; + + /** + * The x coordinate of the first path point (MOVE_TO). + */ + double mx; + + /** + * The y coordinate of the first path point (MOVE_TO). + */ + double my; + + /** + * Constructs a new Arc2D.Iterator for given line and transformation + * + * @param a + * the source Arc2D object. + * @param t + * the AffineTransformation. + */ + Iterator(Arc2D a, AffineTransform t) { + if (width < 0 || height < 0) { + arcCount = 0; + lineCount = 0; + index = 1; + return; + } + + this.width = a.getWidth() / 2.0; + this.height = a.getHeight() / 2.0; + this.x = a.getX() + width; + this.y = a.getY() + height; + this.angle = -Math.toRadians(a.getAngleStart()); + this.extent = -a.getAngleExtent(); + this.type = a.getArcType(); + this.t = t; + + if (Math.abs(extent) >= 360.0) { + arcCount = 4; + k = 4.0 / 3.0 * (Math.sqrt(2.0) - 1.0); + step = Math.PI / 2.0; + if (extent < 0.0) { + step = -step; + k = -k; + } + } else { + arcCount = (int)Math.rint(Math.abs(extent) / 90.0); + step = Math.toRadians(extent / arcCount); + k = 4.0 / 3.0 * (1.0 - Math.cos(step / 2.0)) / Math.sin(step / 2.0); + } + + lineCount = 0; + if (type == Arc2D.CHORD) { + lineCount++; + } else if (type == Arc2D.PIE) { + lineCount += 2; + } + } + + public int getWindingRule() { + return WIND_NON_ZERO; + } + + public boolean isDone() { + return index > arcCount + lineCount; + } + + public void next() { + index++; + } + + public int currentSegment(double[] coords) { + if (isDone()) { + // awt.4B=Iterator out of bounds + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + int type; + int count; + if (index == 0) { + type = SEG_MOVETO; + count = 1; + cos = Math.cos(angle); + sin = Math.sin(angle); + kx = k * width * sin; + ky = k * height * cos; + coords[0] = mx = x + cos * width; + coords[1] = my = y + sin * height; + } else if (index <= arcCount) { + type = SEG_CUBICTO; + count = 3; + coords[0] = mx - kx; + coords[1] = my + ky; + angle += step; + cos = Math.cos(angle); + sin = Math.sin(angle); + kx = k * width * sin; + ky = k * height * cos; + coords[4] = mx = x + cos * width; + coords[5] = my = y + sin * height; + coords[2] = mx + kx; + coords[3] = my - ky; + } else if (index == arcCount + lineCount) { + type = SEG_CLOSE; + count = 0; + } else { + type = SEG_LINETO; + count = 1; + coords[0] = x; + coords[1] = y; + } + if (t != null) { + t.transform(coords, 0, coords, 0, count); + } + return type; + } + + public int currentSegment(float[] coords) { + if (isDone()) { + // awt.4B=Iterator out of bounds + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + int type; + int count; + if (index == 0) { + type = SEG_MOVETO; + count = 1; + cos = Math.cos(angle); + sin = Math.sin(angle); + kx = k * width * sin; + ky = k * height * cos; + coords[0] = (float)(mx = x + cos * width); + coords[1] = (float)(my = y + sin * height); + } else if (index <= arcCount) { + type = SEG_CUBICTO; + count = 3; + coords[0] = (float)(mx - kx); + coords[1] = (float)(my + ky); + angle += step; + cos = Math.cos(angle); + sin = Math.sin(angle); + kx = k * width * sin; + ky = k * height * cos; + coords[4] = (float)(mx = x + cos * width); + coords[5] = (float)(my = y + sin * height); + coords[2] = (float)(mx + kx); + coords[3] = (float)(my - ky); + } else if (index == arcCount + lineCount) { + type = SEG_CLOSE; + count = 0; + } else { + type = SEG_LINETO; + count = 1; + coords[0] = (float)x; + coords[1] = (float)y; + } + if (t != null) { + t.transform(coords, 0, coords, 0, count); + } + return type; + } + + } + + /** + * The closure type of the arc. + */ + private int type; + + /** + * Instantiates a new arc2D. + * + * @param type + * the closure type. + */ + protected Arc2D(int type) { + setArcType(type); + } + + /** + * Takes the double-valued data and creates the corresponding Rectangle2D + * object with values either of type float or of type double depending on + * whether this Arc2D instance is of type Float or Double. + * + * @param x + * the x coordinate of the upper left corner of the bounding + * rectangle. + * @param y + * the y coordinate of the upper left corner of the bounding + * rectangle. + * @param width + * the width of the bounding rectangle. + * @param height + * the height of the bounding rectangle. + * @return the corresponding Rectangle2D object. + */ + protected abstract Rectangle2D makeBounds(double x, double y, double width, double height); + + /** + * Gets the start angle. + * + * @return the start angle. + */ + public abstract double getAngleStart(); + + /** + * Gets the width angle. + * + * @return the width angle. + */ + public abstract double getAngleExtent(); + + /** + * Sets the start angle. + * + * @param start + * the new start angle. + */ + public abstract void setAngleStart(double start); + + /** + * Sets the width angle. + * + * @param extent + * the new width angle. + */ + public abstract void setAngleExtent(double extent); + + /** + * Sets the data values that define the arc. + * + * @param x + * the x coordinate of the upper left corner of the rectangle + * that contains the arc. + * @param y + * the y coordinate of the upper left corner of the rectangle + * that contains the arc. + * @param width + * the width of the rectangle that contains the arc. + * @param height + * the height of the rectangle that contains the arc. + * @param start + * the start angle of the arc in degrees. + * @param extent + * the width angle of the arc in degrees. + * @param type + * the type of the new Arc2D, either {@link Arc2D#OPEN}, + * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + */ + public abstract void setArc(double x, double y, double width, double height, double start, + double extent, int type); + + /** + * Gets the arc type, either {@link Arc2D#OPEN}, {@link Arc2D#CHORD}, or + * {@link Arc2D#PIE}. + * + * @return the arc type. + */ + public int getArcType() { + return type; + } + + /** + * Sets the arc type, either {@link Arc2D#OPEN}, {@link Arc2D#CHORD}, or + * {@link Arc2D#PIE}. + * + * @param type + * the new arc type. + */ + public void setArcType(int type) { + if (type != OPEN && type != CHORD && type != PIE) { + // awt.205=Invalid type of Arc: {0} + throw new IllegalArgumentException(Messages.getString("awt.205", type)); //$NON-NLS-1$ + } + this.type = type; + } + + /** + * Gets the start point of the arc as a Point2D. + * + * @return the start point of the curved arc segment. + */ + public Point2D getStartPoint() { + double a = Math.toRadians(getAngleStart()); + return new Point2D.Double(getX() + (1.0 + Math.cos(a)) * getWidth() / 2.0, getY() + + (1.0 - Math.sin(a)) * getHeight() / 2.0); + } + + /** + * Gets the end point of the arc as a Point2D. + * + * @return the end point of the curved arc segment. + */ + public Point2D getEndPoint() { + double a = Math.toRadians(getAngleStart() + getAngleExtent()); + return new Point2D.Double(getX() + (1.0 + Math.cos(a)) * getWidth() / 2.0, getY() + + (1.0 - Math.sin(a)) * getHeight() / 2.0); + } + + public Rectangle2D getBounds2D() { + if (isEmpty()) { + return makeBounds(getX(), getY(), getWidth(), getHeight()); + } + double rx1 = getX(); + double ry1 = getY(); + double rx2 = rx1 + getWidth(); + double ry2 = ry1 + getHeight(); + + Point2D p1 = getStartPoint(); + Point2D p2 = getEndPoint(); + + double bx1 = containsAngle(180.0) ? rx1 : Math.min(p1.getX(), p2.getX()); + double by1 = containsAngle(90.0) ? ry1 : Math.min(p1.getY(), p2.getY()); + double bx2 = containsAngle(0.0) ? rx2 : Math.max(p1.getX(), p2.getX()); + double by2 = containsAngle(270.0) ? ry2 : Math.max(p1.getY(), p2.getY()); + + if (type == PIE) { + double cx = getCenterX(); + double cy = getCenterY(); + bx1 = Math.min(bx1, cx); + by1 = Math.min(by1, cy); + bx2 = Math.max(bx2, cx); + by2 = Math.max(by2, cy); + } + return makeBounds(bx1, by1, bx2 - bx1, by2 - by1); + } + + @Override + public void setFrame(double x, double y, double width, double height) { + setArc(x, y, width, height, getAngleStart(), getAngleExtent(), type); + } + + /** + * Sets the data that defines the arc. + * + * @param point + * the upper left corner of the bounding rectangle. + * @param size + * the size of the bounding rectangle. + * @param start + * the start angle of the arc in degrees. + * @param extent + * the angle width of the arc in degrees. + * @param type + * the closure type, either {@link Arc2D#OPEN}, + * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + */ + public void setArc(Point2D point, Dimension2D size, double start, double extent, int type) { + setArc(point.getX(), point.getY(), size.getWidth(), size.getHeight(), start, extent, type); + } + + /** + * Sets the data that defines the arc. + * + * @param rect + * the arc's bounding rectangle. + * @param start + * the start angle of the arc in degrees. + * @param extent + * the angle width of the arc in degrees. + * @param type + * the closure type, either {@link Arc2D#OPEN}, + * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + */ + public void setArc(Rectangle2D rect, double start, double extent, int type) { + setArc(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight(), start, extent, type); + } + + /** + * Sets the data that defines the arc by copying it from another Arc2D. + * + * @param arc + * the arc whose data is copied into this arc. + */ + public void setArc(Arc2D arc) { + setArc(arc.getX(), arc.getY(), arc.getWidth(), arc.getHeight(), arc.getAngleStart(), arc + .getAngleExtent(), arc.getArcType()); + } + + /** + * Sets the data for a circular arc by giving its center and radius. + * + * @param x + * the x coordinate of the center of the circle. + * @param y + * the y coordinate of the center of the circle. + * @param radius + * the radius of the circle. + * @param start + * the start angle of the arc in degrees. + * @param extent + * the angle width of the arc in degrees. + * @param type + * the closure type, either {@link Arc2D#OPEN}, + * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + */ + public void setArcByCenter(double x, double y, double radius, double start, double extent, + int type) { + setArc(x - radius, y - radius, radius * 2.0, radius * 2.0, start, extent, type); + } + + /** + * Sets the arc data for a circular arc based on two tangent lines and the + * radius. The two tangent lines are the lines from p1 to p2 and from p2 to + * p3, which determine a unique circle with the given radius. The start and + * end points of the arc are the points where the circle touches the two + * lines, and the arc itself is the shorter of the two circle segments + * determined by the two points (in other words, it is the piece of the + * circle that is closer to the lines' intersection point p2 and forms a + * concave shape with the segments from p1 to p2 and from p2 to p3). + * + * @param p1 + * a point which determines one of the two tangent lines (with + * p2). + * @param p2 + * the point of intersection of the two tangent lines. + * @param p3 + * a point which determines one of the two tangent lines (with + * p2). + * @param radius + * the radius of the circular arc. + */ + public void setArcByTangent(Point2D p1, Point2D p2, Point2D p3, double radius) { + // Used simple geometric calculations of arc center, radius and angles + // by tangents + double a1 = -Math.atan2(p1.getY() - p2.getY(), p1.getX() - p2.getX()); + double a2 = -Math.atan2(p3.getY() - p2.getY(), p3.getX() - p2.getX()); + double am = (a1 + a2) / 2.0; + double ah = a1 - am; + double d = radius / Math.abs(Math.sin(ah)); + double x = p2.getX() + d * Math.cos(am); + double y = p2.getY() - d * Math.sin(am); + ah = ah >= 0.0 ? Math.PI * 1.5 - ah : Math.PI * 0.5 - ah; + a1 = getNormAngle(Math.toDegrees(am - ah)); + a2 = getNormAngle(Math.toDegrees(am + ah)); + double delta = a2 - a1; + if (delta <= 0.0) { + delta += 360.0; + } + setArcByCenter(x, y, radius, a1, delta, type); + } + + /** + * Sets a new start angle to be the angle given by the the vector from the + * current center point to the specified point. + * + * @param point + * the point that determines the new start angle. + */ + public void setAngleStart(Point2D point) { + double angle = Math.atan2(point.getY() - getCenterY(), point.getX() - getCenterX()); + setAngleStart(getNormAngle(-Math.toDegrees(angle))); + } + + /** + * Sets the angles in terms of vectors from the current arc center to the + * points (x1, y1) and (x2, y2). The start angle is given by the vector from + * the current center to the point (x1, y1) and the end angle is given by + * the vector from the center to the point (x2, y2). + * + * @param x1 + * the x coordinate of the point whose vector from the center + * point determines the new start angle of the arc. + * @param y1 + * the y coordinate of the point whose vector from the center + * point determines the new start angle of the arc. + * @param x2 + * the x coordinate of the point whose vector from the center + * point determines the new end angle of the arc. + * @param y2 + * the y coordinate of the point whose vector from the center + * point determines the new end angle of the arc. + */ + public void setAngles(double x1, double y1, double x2, double y2) { + double cx = getCenterX(); + double cy = getCenterY(); + double a1 = getNormAngle(-Math.toDegrees(Math.atan2(y1 - cy, x1 - cx))); + double a2 = getNormAngle(-Math.toDegrees(Math.atan2(y2 - cy, x2 - cx))); + a2 -= a1; + if (a2 <= 0.0) { + a2 += 360.0; + } + setAngleStart(a1); + setAngleExtent(a2); + } + + /** + * Sets the angles in terms of vectors from the current arc center to the + * points p1 and p2. The start angle is given by the vector from the current + * center to the point p1 and the end angle is given by the vector from the + * center to the point p2. + * + * @param p1 + * the point whose vector from the center point determines the + * new start angle of the arc. + * @param p2 + * the point whose vector from the center point determines the + * new end angle of the arc. + */ + public void setAngles(Point2D p1, Point2D p2) { + setAngles(p1.getX(), p1.getY(), p2.getX(), p2.getY()); + } + + /** + * Normalizes the angle by removing extra winding (past 360 degrees) and + * placing it in the positive degree range. + * + * @param angle + * the source angle in degrees. + * @return an angle between 0 and 360 degrees which corresponds to the same + * direction vector as the source angle. + */ + double getNormAngle(double angle) { + double n = Math.floor(angle / 360.0); + return angle - n * 360.0; + } + + /** + * Determines whether the given angle is contained in the span of the arc. + * + * @param angle + * the angle to test in degrees. + * @return true, if the given angle is between the start angle and the end + * angle of the arc. + */ + public boolean containsAngle(double angle) { + double extent = getAngleExtent(); + if (extent >= 360.0) { + return true; + } + angle = getNormAngle(angle); + double a1 = getNormAngle(getAngleStart()); + double a2 = a1 + extent; + if (a2 > 360.0) { + return angle >= a1 || angle <= a2 - 360.0; + } + if (a2 < 0.0) { + return angle >= a2 + 360.0 || angle <= a1; + } + return extent > 0.0 ? a1 <= angle && angle <= a2 : a2 <= angle && angle <= a1; + } + + public boolean contains(double px, double py) { + // Normalize point + double nx = (px - getX()) / getWidth() - 0.5; + double ny = (py - getY()) / getHeight() - 0.5; + + if ((nx * nx + ny * ny) > 0.25) { + return false; + } + + double extent = getAngleExtent(); + double absExtent = Math.abs(extent); + if (absExtent >= 360.0) { + return true; + } + + boolean containsAngle = containsAngle(Math.toDegrees(-Math.atan2(ny, nx))); + if (type == PIE) { + return containsAngle; + } + if (absExtent <= 180.0 && !containsAngle) { + return false; + } + + Line2D l = new Line2D.Double(getStartPoint(), getEndPoint()); + int ccw1 = l.relativeCCW(px, py); + int ccw2 = l.relativeCCW(getCenterX(), getCenterY()); + return ccw1 == 0 || ccw2 == 0 || ((ccw1 + ccw2) == 0 ^ absExtent > 180.0); + } + + public boolean contains(double rx, double ry, double rw, double rh) { + + if (!(contains(rx, ry) && contains(rx + rw, ry) && contains(rx + rw, ry + rh) && contains( + rx, ry + rh))) { + return false; + } + + double absExtent = Math.abs(getAngleExtent()); + if (type != PIE || absExtent <= 180.0 || absExtent >= 360.0) { + return true; + } + + Rectangle2D r = new Rectangle2D.Double(rx, ry, rw, rh); + + double cx = getCenterX(); + double cy = getCenterY(); + if (r.contains(cx, cy)) { + return false; + } + + Point2D p1 = getStartPoint(); + Point2D p2 = getEndPoint(); + + return !r.intersectsLine(cx, cy, p1.getX(), p1.getY()) + && !r.intersectsLine(cx, cy, p2.getX(), p2.getY()); + } + + @Override + public boolean contains(Rectangle2D rect) { + return contains(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); + } + + public boolean intersects(double rx, double ry, double rw, double rh) { + + if (isEmpty() || rw <= 0.0 || rh <= 0.0) { + return false; + } + + // Check: Does arc contain rectangle's points + if (contains(rx, ry) || contains(rx + rw, ry) || contains(rx, ry + rh) + || contains(rx + rw, ry + rh)) { + return true; + } + + double cx = getCenterX(); + double cy = getCenterY(); + Point2D p1 = getStartPoint(); + Point2D p2 = getEndPoint(); + Rectangle2D r = new Rectangle2D.Double(rx, ry, rw, rh); + + // Check: Does rectangle contain arc's points + if (r.contains(p1) || r.contains(p2) || (type == PIE && r.contains(cx, cy))) { + return true; + } + + if (type == PIE) { + if (r.intersectsLine(p1.getX(), p1.getY(), cx, cy) + || r.intersectsLine(p2.getX(), p2.getY(), cx, cy)) { + return true; + } + } else { + if (r.intersectsLine(p1.getX(), p1.getY(), p2.getX(), p2.getY())) { + return true; + } + } + + // Nearest rectangle point + double nx = cx < rx ? rx : (cx > rx + rw ? rx + rw : cx); + double ny = cy < ry ? ry : (cy > ry + rh ? ry + rh : cy); + return contains(nx, ny); + } + + public PathIterator getPathIterator(AffineTransform at) { + return new Iterator(this, at); + } + +} diff --git a/awt/java/awt/geom/Area.java b/awt/java/awt/geom/Area.java new file mode 100644 index 0000000..e6619e3 --- /dev/null +++ b/awt/java/awt/geom/Area.java @@ -0,0 +1,330 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt.geom; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.PathIterator; +import java.awt.geom.Rectangle2D; +import java.util.NoSuchElementException; + +import org.apache.harmony.awt.internal.nls.Messages; +import org.apache.harmony.luni.util.NotImplementedException; + +/** + * The Class Area provides a minimal implementation for a generic shape. + * + * @since Android 1.0 + */ +public class Area implements Shape, Cloneable { + + /** + * The source Shape object. + */ + Shape s; + + /** + * The Class NullIterator. + */ + private static class NullIterator implements PathIterator { + + /** + * Instantiates a new null iterator. + */ + NullIterator() { + } + + public int getWindingRule() { + return WIND_NON_ZERO; + } + + public boolean isDone() { + return true; + } + + public void next() { + // nothing + } + + public int currentSegment(double[] coords) { + // awt.4B=Iterator out of bounds + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + + public int currentSegment(float[] coords) { + // awt.4B=Iterator out of bounds + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + + } + + /** + * Instantiates a new area with no data. + */ + public Area() { + } + + /** + * Instantiates a new area with data given by the specified shape. + * + * @param s + * the shape that gives the data for this Area. + */ + public Area(Shape s) { + if (s == null) { + throw new NullPointerException(); + } + this.s = s; + } + + public boolean contains(double x, double y) { + return s == null ? false : s.contains(x, y); + } + + public boolean contains(double x, double y, double width, double height) { + return s == null ? false : s.contains(x, y, width, height); + } + + public boolean contains(Point2D p) { + if (p == null) { + throw new NullPointerException(); + } + return s == null ? false : s.contains(p); + } + + public boolean contains(Rectangle2D r) { + if (r == null) { + throw new NullPointerException(); + } + return s == null ? false : s.contains(r); + } + + /** + * Tests whether the object is equal to this Area. + * + * @param obj + * the object to compare. + * @return true, if successful. + * @throws NotImplementedException + * if this method is not implemented. + */ + public boolean equals(Area obj) throws org.apache.harmony.luni.util.NotImplementedException { + throw new RuntimeException("Not implemented"); //$NON-NLS-1$ + } + + public boolean intersects(double x, double y, double width, double height) { + return s == null ? false : s.intersects(x, y, width, height); + } + + public boolean intersects(Rectangle2D r) { + if (r == null) { + throw new NullPointerException(); + } + return s == null ? false : s.intersects(r); + } + + public Rectangle getBounds() { + return s == null ? new Rectangle() : s.getBounds(); + } + + public Rectangle2D getBounds2D() { + return s == null ? new Rectangle2D.Double() : s.getBounds2D(); + } + + public PathIterator getPathIterator(AffineTransform t) { + return s == null ? new NullIterator() : s.getPathIterator(t); + } + + public PathIterator getPathIterator(AffineTransform t, double flatness) { + return s == null ? new NullIterator() : s.getPathIterator(t, flatness); + } + + /** + * Adds the specified area to this area. + * + * @param area + * the area to add to this area. + * @throws NotImplementedException + * if this method is not implemented. + */ + public void add(Area area) throws org.apache.harmony.luni.util.NotImplementedException { + throw new RuntimeException("Not implemented"); //$NON-NLS-1$ + } + + /** + * Performs an exclusive or operation between this shape and the specified + * shape. + * + * @param area + * the area to XOR against this area. + * @throws NotImplementedException + * if this method is not implemented. + */ + public void exclusiveOr(Area area) throws org.apache.harmony.luni.util.NotImplementedException { + throw new RuntimeException("Not implemented"); //$NON-NLS-1$ + } + + /** + * Extracts a Rectangle2D from the source shape if the underlying shape data + * describes a rectangle. + * + * @return a Rectangle2D object if the source shape is rectangle, or null if + * shape is empty or not rectangle. + */ + Rectangle2D extractRectangle() { + if (s == null) { + return null; + } + float[] points = new float[12]; + int count = 0; + PathIterator p = s.getPathIterator(null); + float[] coords = new float[6]; + while (!p.isDone()) { + int type = p.currentSegment(coords); + if (count > 12 || type == PathIterator.SEG_QUADTO || type == PathIterator.SEG_CUBICTO) { + return null; + } + points[count++] = coords[0]; + points[count++] = coords[1]; + p.next(); + } + if (points[0] == points[6] && points[6] == points[8] && points[2] == points[4] + && points[1] == points[3] && points[3] == points[9] && points[5] == points[7]) { + return new Rectangle2D.Float(points[0], points[1], points[2] - points[0], points[7] + - points[1]); + } + return null; + } + + /** + * Reduces the size of this Area by intersecting it with the specified Area + * if they are both rectangles. + * + * @see java.awt.geom.Rectangle2D#intersect(Rectangle2D, Rectangle2D, + * Rectangle2D) + * @param area + * the area. + */ + public void intersect(Area area) { + Rectangle2D src1 = extractRectangle(); + Rectangle2D src2 = area.extractRectangle(); + if (src1 != null && src2 != null) { + Rectangle2D.intersect(src1, src2, (Rectangle2D)s); + } + } + + /** + * Subtract the specified area from this area. + * + * @param area + * the area to subtract. + * @throws NotImplementedException + * if this method is not implemented. + */ + public void subtract(Area area) throws org.apache.harmony.luni.util.NotImplementedException { + throw new RuntimeException("Not implemented"); //$NON-NLS-1$ + } + + /** + * Checks if this Area is empty. + * + * @return true, if this Area is empty. + * @throws NotImplementedException + * if this method is not implemented. + */ + public boolean isEmpty() throws org.apache.harmony.luni.util.NotImplementedException { + throw new RuntimeException("Not implemented"); //$NON-NLS-1$ + } + + /** + * Checks if this Area is polygonal. + * + * @return true, if this Area is polygonal. + * @throws NotImplementedException + * if this method is not implemented. + */ + public boolean isPolygonal() throws org.apache.harmony.luni.util.NotImplementedException { + throw new RuntimeException("Not implemented"); //$NON-NLS-1$ + } + + /** + * Checks if this Area is rectangular. + * + * @return true, if this Area is rectangular. + * @throws NotImplementedException + * if this method is not implemented. + */ + public boolean isRectangular() throws org.apache.harmony.luni.util.NotImplementedException { + throw new RuntimeException("Not implemented"); //$NON-NLS-1$ + } + + /** + * Checks if this Area is singular. + * + * @return true, if this Area is singular. + * @throws NotImplementedException + * if this method is not implemented. + */ + public boolean isSingular() throws org.apache.harmony.luni.util.NotImplementedException { + throw new RuntimeException("Not implemented"); //$NON-NLS-1$ + } + + /** + * Resets the data of this Area. + * + * @throws NotImplementedException + * if this method is not implemented. + */ + public void reset() throws org.apache.harmony.luni.util.NotImplementedException { + throw new RuntimeException("Not implemented"); //$NON-NLS-1$ + } + + /** + * Transforms the data of this Area according to the specified + * AffineTransform. + * + * @param t + * the transform to use to transform the data. + */ + public void transform(AffineTransform t) { + s = t.createTransformedShape(s); + } + + /** + * Creates a new Area that is the result of transforming the data of this + * Area according to the specified AffineTransform. + * + * @param t + * the transform to use to transform the data. + * @return the new Area that is the result of transforming the data of this + * Area according to the specified AffineTransform. + */ + public Area createTransformedArea(AffineTransform t) { + return s == null ? new Area() : new Area(t.createTransformedShape(s)); + } + + @Override + public Object clone() { + return new Area(this); + } + +} diff --git a/awt/java/awt/geom/CubicCurve2D.java b/awt/java/awt/geom/CubicCurve2D.java new file mode 100644 index 0000000..1ddedf3 --- /dev/null +++ b/awt/java/awt/geom/CubicCurve2D.java @@ -0,0 +1,1047 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt.geom; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.util.NoSuchElementException; + +import org.apache.harmony.awt.gl.Crossing; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class CubicCurve2D is a Shape that represents a segment of a quadratic + * (Bezier) curve. The curved segment is determined by four points: a start + * point, an end point, and two control points. The control points give + * information about the tangent and next derivative at the endpoints according + * to the standard theory of Bezier curves. For more information on Bezier + * curves, see <a href="http://en.wikipedia.org/wiki/B%C3%A9zier_curve">this + * article</a>. + * + * @since Android 1.0 + */ +public abstract class CubicCurve2D implements Shape, Cloneable { + + /** + * The Class Float is the subclass of CubicCurve2D that has all of its data + * values stored with float-level precision. + * + * @since Android 1.0 + */ + public static class Float extends CubicCurve2D { + + /** + * The x coordinate of the starting point. + */ + public float x1; + + /** + * The y coordinate of the starting point. + */ + public float y1; + + /** + * The x coordinate of the first control point. + */ + public float ctrlx1; + + /** + * The y coordinate of the first control point. + */ + public float ctrly1; + + /** + * The x coordinate of the second control point. + */ + public float ctrlx2; + + /** + * The y coordinate of the second control point. + */ + public float ctrly2; + + /** + * The x coordinate of the end point. + */ + public float x2; + + /** + * The y coordinate of the end point. + */ + public float y2; + + /** + * Instantiates a new float-valued CubicCurve2D with all coordinate + * values set to zero. + */ + public Float() { + } + + /** + * Instantiates a new float-valued CubicCurve2D with the specified + * coordinate values. + * + * @param x1 + * the x coordinate of the starting point. + * @param y1 + * the y coordinate of the starting point. + * @param ctrlx1 + * the x coordinate of the first control point. + * @param ctrly1 + * the y coordinate of the first control point. + * @param ctrlx2 + * the x coordinate of the second control point. + * @param ctrly2 + * the y coordinate of the second control point. + * @param x2 + * the x coordinate of the end point. + * @param y2 + * the y coordinate of the end point. + */ + public Float(float x1, float y1, float ctrlx1, float ctrly1, float ctrlx2, float ctrly2, + float x2, float y2) { + setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2); + } + + @Override + public double getX1() { + return x1; + } + + @Override + public double getY1() { + return y1; + } + + @Override + public double getCtrlX1() { + return ctrlx1; + } + + @Override + public double getCtrlY1() { + return ctrly1; + } + + @Override + public double getCtrlX2() { + return ctrlx2; + } + + @Override + public double getCtrlY2() { + return ctrly2; + } + + @Override + public double getX2() { + return x2; + } + + @Override + public double getY2() { + return y2; + } + + @Override + public Point2D getP1() { + return new Point2D.Float(x1, y1); + } + + @Override + public Point2D getCtrlP1() { + return new Point2D.Float(ctrlx1, ctrly1); + } + + @Override + public Point2D getCtrlP2() { + return new Point2D.Float(ctrlx2, ctrly2); + } + + @Override + public Point2D getP2() { + return new Point2D.Float(x2, y2); + } + + @Override + public void setCurve(double x1, double y1, double ctrlx1, double ctrly1, double ctrlx2, + double ctrly2, double x2, double y2) { + this.x1 = (float)x1; + this.y1 = (float)y1; + this.ctrlx1 = (float)ctrlx1; + this.ctrly1 = (float)ctrly1; + this.ctrlx2 = (float)ctrlx2; + this.ctrly2 = (float)ctrly2; + this.x2 = (float)x2; + this.y2 = (float)y2; + } + + /** + * Sets the data values of the curve. + * + * @param x1 + * the x coordinate of the starting point. + * @param y1 + * the y coordinate of the starting point. + * @param ctrlx1 + * the x coordinate of the first control point. + * @param ctrly1 + * the y coordinate of the first control point. + * @param ctrlx2 + * the x coordinate of the second control point. + * @param ctrly2 + * the y coordinate of the second control point. + * @param x2 + * the x coordinate of the end point. + * @param y2 + * the y coordinate of the end point. + */ + public void setCurve(float x1, float y1, float ctrlx1, float ctrly1, float ctrlx2, + float ctrly2, float x2, float y2) { + this.x1 = x1; + this.y1 = y1; + this.ctrlx1 = ctrlx1; + this.ctrly1 = ctrly1; + this.ctrlx2 = ctrlx2; + this.ctrly2 = ctrly2; + this.x2 = x2; + this.y2 = y2; + } + + public Rectangle2D getBounds2D() { + float rx1 = Math.min(Math.min(x1, x2), Math.min(ctrlx1, ctrlx2)); + float ry1 = Math.min(Math.min(y1, y2), Math.min(ctrly1, ctrly2)); + float rx2 = Math.max(Math.max(x1, x2), Math.max(ctrlx1, ctrlx2)); + float ry2 = Math.max(Math.max(y1, y2), Math.max(ctrly1, ctrly2)); + return new Rectangle2D.Float(rx1, ry1, rx2 - rx1, ry2 - ry1); + } + } + + /** + * The Class Double is the subclass of CubicCurve2D that has all of its data + * values stored with double-level precision. + * + * @since Android 1.0 + */ + public static class Double extends CubicCurve2D { + + /** + * The x coordinate of the starting point. + */ + public double x1; + + /** + * The y coordinate of the starting point. + */ + public double y1; + + /** + * The x coordinate of the first control point. + */ + public double ctrlx1; + + /** + * The y coordinate of the first control point. + */ + public double ctrly1; + + /** + * The x coordinate of the second control point. + */ + public double ctrlx2; + + /** + * The y coordinate of the second control point. + */ + public double ctrly2; + + /** + * The x coordinate of the end point. + */ + public double x2; + + /** + * The y coordinate of the end point. + */ + public double y2; + + /** + * Instantiates a new double-valued CubicCurve2D with all coordinate + * values set to zero. + */ + public Double() { + } + + /** + * Instantiates a new double-valued CubicCurve2D with the specified + * coordinate values. + * + * @param x1 + * the x coordinate of the starting point. + * @param y1 + * the y coordinate of the starting point. + * @param ctrlx1 + * the x coordinate of the first control point. + * @param ctrly1 + * the y coordinate of the first control point. + * @param ctrlx2 + * the x coordinate of the second control point. + * @param ctrly2 + * the y coordinate of the second control point. + * @param x2 + * the x coordinate of the end point. + * @param y2 + * the y coordinate of the end point. + */ + public Double(double x1, double y1, double ctrlx1, double ctrly1, double ctrlx2, + double ctrly2, double x2, double y2) { + setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2); + } + + @Override + public double getX1() { + return x1; + } + + @Override + public double getY1() { + return y1; + } + + @Override + public double getCtrlX1() { + return ctrlx1; + } + + @Override + public double getCtrlY1() { + return ctrly1; + } + + @Override + public double getCtrlX2() { + return ctrlx2; + } + + @Override + public double getCtrlY2() { + return ctrly2; + } + + @Override + public double getX2() { + return x2; + } + + @Override + public double getY2() { + return y2; + } + + @Override + public Point2D getP1() { + return new Point2D.Double(x1, y1); + } + + @Override + public Point2D getCtrlP1() { + return new Point2D.Double(ctrlx1, ctrly1); + } + + @Override + public Point2D getCtrlP2() { + return new Point2D.Double(ctrlx2, ctrly2); + } + + @Override + public Point2D getP2() { + return new Point2D.Double(x2, y2); + } + + @Override + public void setCurve(double x1, double y1, double ctrlx1, double ctrly1, double ctrlx2, + double ctrly2, double x2, double y2) { + this.x1 = x1; + this.y1 = y1; + this.ctrlx1 = ctrlx1; + this.ctrly1 = ctrly1; + this.ctrlx2 = ctrlx2; + this.ctrly2 = ctrly2; + this.x2 = x2; + this.y2 = y2; + } + + public Rectangle2D getBounds2D() { + double rx1 = Math.min(Math.min(x1, x2), Math.min(ctrlx1, ctrlx2)); + double ry1 = Math.min(Math.min(y1, y2), Math.min(ctrly1, ctrly2)); + double rx2 = Math.max(Math.max(x1, x2), Math.max(ctrlx1, ctrlx2)); + double ry2 = Math.max(Math.max(y1, y2), Math.max(ctrly1, ctrly2)); + return new Rectangle2D.Double(rx1, ry1, rx2 - rx1, ry2 - ry1); + } + } + + /* + * CubicCurve2D path iterator + */ + /** + * The Iterator class for the Shape CubicCurve2D. + */ + class Iterator implements PathIterator { + + /** + * The source CubicCurve2D object. + */ + CubicCurve2D c; + + /** + * The path iterator transformation. + */ + AffineTransform t; + + /** + * The current segment index. + */ + int index; + + /** + * Constructs a new CubicCurve2D.Iterator for given line and + * transformation + * + * @param c + * the source CubicCurve2D object. + * @param t + * the affine transformation object. + */ + Iterator(CubicCurve2D c, AffineTransform t) { + this.c = c; + this.t = t; + } + + public int getWindingRule() { + return WIND_NON_ZERO; + } + + public boolean isDone() { + return index > 1; + } + + public void next() { + index++; + } + + public int currentSegment(double[] coords) { + if (isDone()) { + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + int type; + int count; + if (index == 0) { + type = SEG_MOVETO; + coords[0] = c.getX1(); + coords[1] = c.getY1(); + count = 1; + } else { + type = SEG_CUBICTO; + coords[0] = c.getCtrlX1(); + coords[1] = c.getCtrlY1(); + coords[2] = c.getCtrlX2(); + coords[3] = c.getCtrlY2(); + coords[4] = c.getX2(); + coords[5] = c.getY2(); + count = 3; + } + if (t != null) { + t.transform(coords, 0, coords, 0, count); + } + return type; + } + + public int currentSegment(float[] coords) { + if (isDone()) { + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + int type; + int count; + if (index == 0) { + type = SEG_MOVETO; + coords[0] = (float)c.getX1(); + coords[1] = (float)c.getY1(); + count = 1; + } else { + type = SEG_CUBICTO; + coords[0] = (float)c.getCtrlX1(); + coords[1] = (float)c.getCtrlY1(); + coords[2] = (float)c.getCtrlX2(); + coords[3] = (float)c.getCtrlY2(); + coords[4] = (float)c.getX2(); + coords[5] = (float)c.getY2(); + count = 3; + } + if (t != null) { + t.transform(coords, 0, coords, 0, count); + } + return type; + } + + } + + /** + * Instantiates a new 2-D cubic curve. + */ + protected CubicCurve2D() { + } + + /** + * Gets the x coordinate of the starting point. + * + * @return the x coordinate of the starting point. + */ + public abstract double getX1(); + + /** + * Gets the y coordinate of the starting point. + * + * @return the y coordinate of the starting point. + */ + public abstract double getY1(); + + /** + * Gets the starting point. + * + * @return the starting point. + */ + public abstract Point2D getP1(); + + /** + * Gets the x coordinate of the first control point. + * + * @return the x coordinate of the first control point. + */ + public abstract double getCtrlX1(); + + /** + * Gets the y coordinate of the first control point. + * + * @return the y coordinate of the first control point. + */ + public abstract double getCtrlY1(); + + /** + * Gets the second control point. + * + * @return the second control point. + */ + public abstract Point2D getCtrlP1(); + + /** + * Gets the x coordinate of the second control point. + * + * @return the x coordinate of the second control point + */ + public abstract double getCtrlX2(); + + /** + * Gets the y coordinate of the second control point. + * + * @return the y coordinate of the second control point + */ + public abstract double getCtrlY2(); + + /** + * Gets the second control point. + * + * @return the second control point. + */ + public abstract Point2D getCtrlP2(); + + /** + * Gets the x coordinate of the end point. + * + * @return the x coordinate of the end point. + */ + public abstract double getX2(); + + /** + * Gets the y coordinate of the end point. + * + * @return the y coordinate of the end point. + */ + public abstract double getY2(); + + /** + * Gets the end point. + * + * @return the end point. + */ + public abstract Point2D getP2(); + + /** + * Sets the data of the curve. + * + * @param x1 + * the x coordinate of the starting point. + * @param y1 + * the y coordinate of the starting point. + * @param ctrlx1 + * the x coordinate of the first control point. + * @param ctrly1 + * the y coordinate of the first control point. + * @param ctrlx2 + * the x coordinate of the second control point. + * @param ctrly2 + * the y coordinate of the second control point. + * @param x2 + * the x coordinate of the end point. + * @param y2 + * the y coordinate of the end point. + */ + public abstract void setCurve(double x1, double y1, double ctrlx1, double ctrly1, + double ctrlx2, double ctrly2, double x2, double y2); + + /** + * Sets the data of the curve as point objects. + * + * @param p1 + * the starting point. + * @param cp1 + * the first control point. + * @param cp2 + * the second control point. + * @param p2 + * the end point. + * @throws NullPointerException + * if any of the points is null. + */ + public void setCurve(Point2D p1, Point2D cp1, Point2D cp2, Point2D p2) { + setCurve(p1.getX(), p1.getY(), cp1.getX(), cp1.getY(), cp2.getX(), cp2.getY(), p2.getX(), + p2.getY()); + } + + /** + * Sets the data of the curve by reading the data from an array of values. + * The values are read in the same order as the arguments of the method + * {@link CubicCurve2D#setCurve(double, double, double, double, double, double, double, double)} + * . + * + * @param coords + * the array of values containing the new coordinates. + * @param offset + * the offset of the data to read within the array. + * @throws ArrayIndexOutOfBoundsException + * if {@code coords.length} < offset + 8. + * @throws NullPointerException + * if the coordinate array is null. + */ + public void setCurve(double[] coords, int offset) { + setCurve(coords[offset + 0], coords[offset + 1], coords[offset + 2], coords[offset + 3], + coords[offset + 4], coords[offset + 5], coords[offset + 6], coords[offset + 7]); + } + + /** + * Sets the data of the curve by reading the data from an array of points. + * The values are read in the same order as the arguments of the method + * {@link CubicCurve2D#setCurve(Point2D, Point2D, Point2D, Point2D)} + * + * @param points + * the array of points containing the new coordinates. + * @param offset + * the offset of the data to read within the array. + * @throws ArrayIndexOutOfBoundsException + * if {@code points.length} < offset + . + * @throws NullPointerException + * if the point array is null. + */ + public void setCurve(Point2D[] points, int offset) { + setCurve(points[offset + 0].getX(), points[offset + 0].getY(), points[offset + 1].getX(), + points[offset + 1].getY(), points[offset + 2].getX(), points[offset + 2].getY(), + points[offset + 3].getX(), points[offset + 3].getY()); + } + + /** + * Sets the data of the curve by copying it from another CubicCurve2D. + * + * @param curve + * the curve to copy the data points from. + * @throws NullPointerException + * if the curve is null. + */ + public void setCurve(CubicCurve2D curve) { + setCurve(curve.getX1(), curve.getY1(), curve.getCtrlX1(), curve.getCtrlY1(), curve + .getCtrlX2(), curve.getCtrlY2(), curve.getX2(), curve.getY2()); + } + + /** + * Gets the square of the flatness of this curve, where the flatness is the + * maximum distance from the curves control points to the line segment + * connecting the two points. + * + * @return the square of the flatness. + */ + public double getFlatnessSq() { + return getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(), getCtrlX2(), getCtrlY2(), + getX2(), getY2()); + } + + /** + * Gets the square of the flatness of the cubic curve segment defined by the + * specified values. + * + * @param x1 + * the x coordinate of the starting point. + * @param y1 + * the y coordinate of the starting point. + * @param ctrlx1 + * the x coordinate of the first control point. + * @param ctrly1 + * the y coordinate of the first control point. + * @param ctrlx2 + * the x coordinate of the second control point. + * @param ctrly2 + * the y coordinate of the second control point. + * @param x2 + * the x coordinate of the end point. + * @param y2 + * the y coordinate of the end point. + * @return the square of the flatness. + */ + public static double getFlatnessSq(double x1, double y1, double ctrlx1, double ctrly1, + double ctrlx2, double ctrly2, double x2, double y2) { + return Math.max(Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx1, ctrly1), Line2D.ptSegDistSq(x1, + y1, x2, y2, ctrlx2, ctrly2)); + } + + /** + * Gets the square of the flatness of the cubic curve segment defined by the + * specified values. The values are read in the same order as the arguments + * of the method + * {@link CubicCurve2D#getFlatnessSq(double, double, double, double, double, double, double, double)} + * . + * + * @param coords + * the array of points containing the new coordinates. + * @param offset + * the offset of the data to read within the array. + * @return the square of the flatness. + * @throws ArrayIndexOutOfBoundsException + * if points.length < offset + . + * @throws NullPointerException + * if the point array is null. + */ + public static double getFlatnessSq(double coords[], int offset) { + return getFlatnessSq(coords[offset + 0], coords[offset + 1], coords[offset + 2], + coords[offset + 3], coords[offset + 4], coords[offset + 5], coords[offset + 6], + coords[offset + 7]); + } + + /** + * Gets the flatness of this curve, where the flatness is the maximum + * distance from the curves control points to the line segment connecting + * the two points. + * + * @return the flatness of this curve. + */ + public double getFlatness() { + return getFlatness(getX1(), getY1(), getCtrlX1(), getCtrlY1(), getCtrlX2(), getCtrlY2(), + getX2(), getY2()); + } + + /** + * Gets the flatness of the cubic curve segment defined by the specified + * values. + * + * @param x1 + * the x coordinate of the starting point. + * @param y1 + * the y coordinate of the starting point. + * @param ctrlx1 + * the x coordinate of the first control point. + * @param ctrly1 + * the y coordinate of the first control point. + * @param ctrlx2 + * the x coordinate of the second control point. + * @param ctrly2 + * the y coordinate of the second control point. + * @param x2 + * the x coordinate of the end point. + * @param y2 + * the y coordinate of the end point. + * @return the flatness. + */ + public static double getFlatness(double x1, double y1, double ctrlx1, double ctrly1, + double ctrlx2, double ctrly2, double x2, double y2) { + return Math.sqrt(getFlatnessSq(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2)); + } + + /** + * Gets the flatness of the cubic curve segment defined by the specified + * values. The values are read in the same order as the arguments of the + * method + * {@link CubicCurve2D#getFlatness(double, double, double, double, double, double, double, double)} + * . + * + * @param coords + * the array of points containing the new coordinates. + * @param offset + * the offset of the data to read within the array. + * @return the flatness. + * @throws ArrayIndexOutOfBoundsException + * if points.length < offset + . + * @throws NullPointerException + * if the point array is null. + */ + public static double getFlatness(double coords[], int offset) { + return getFlatness(coords[offset + 0], coords[offset + 1], coords[offset + 2], + coords[offset + 3], coords[offset + 4], coords[offset + 5], coords[offset + 6], + coords[offset + 7]); + } + + /** + * Creates the data for two cubic curves by dividing this curve in two. The + * division point is the point on the curve that is closest to the average + * of curve's two control points. The two new control points (nearest the + * new endpoint) are computed by averaging the original control points with + * the new endpoint. The data of this curve is left unchanged. + * + * @param left + * the CubicCurve2D where the left (start) segment's data is + * written. + * @param right + * the CubicCurve2D where the right (end) segment's data is + * written. + * @throws NullPointerException + * if either curve is null. + */ + public void subdivide(CubicCurve2D left, CubicCurve2D right) { + subdivide(this, left, right); + } + + /** + * Creates the data for two cubic curves by dividing the specified curve in + * two. The division point is the point on the curve that is closest to the + * average of curve's two control points. The two new control points + * (nearest the new endpoint) are computed by averaging the original control + * points with the new endpoint. The data of the source curve is left + * unchanged. + * + * @param src + * the original curve to be divided in two. + * @param left + * the CubicCurve2D where the left (start) segment's data is + * written. + * @param right + * the CubicCurve2D where the right (end) segment's data is + * written. + * @throws NullPointerException + * if either curve is null. + */ + public static void subdivide(CubicCurve2D src, CubicCurve2D left, CubicCurve2D right) { + double x1 = src.getX1(); + double y1 = src.getY1(); + double cx1 = src.getCtrlX1(); + double cy1 = src.getCtrlY1(); + double cx2 = src.getCtrlX2(); + double cy2 = src.getCtrlY2(); + double x2 = src.getX2(); + double y2 = src.getY2(); + double cx = (cx1 + cx2) / 2.0; + double cy = (cy1 + cy2) / 2.0; + cx1 = (x1 + cx1) / 2.0; + cy1 = (y1 + cy1) / 2.0; + cx2 = (x2 + cx2) / 2.0; + cy2 = (y2 + cy2) / 2.0; + double ax = (cx1 + cx) / 2.0; + double ay = (cy1 + cy) / 2.0; + double bx = (cx2 + cx) / 2.0; + double by = (cy2 + cy) / 2.0; + cx = (ax + bx) / 2.0; + cy = (ay + by) / 2.0; + if (left != null) { + left.setCurve(x1, y1, cx1, cy1, ax, ay, cx, cy); + } + if (right != null) { + right.setCurve(cx, cy, bx, by, cx2, cy2, x2, y2); + } + } + + /** + * Creates the data for two cubic curves by dividing the specified curve in + * two. The division point is the point on the curve that is closest to the + * average of curve's two control points. The two new control points + * (nearest the new endpoint) are computed by averaging the original control + * points with the new endpoint. The data of the source curve is left + * unchanged. The data for the three curves is read/written in the usual + * order: { x1, y1, ctrlx1, ctrly1, ctrlx2, crtry2, x2, y3 } + * + * @param src + * the array that gives the data values for the source curve. + * @param srcOff + * the offset in the src array to read the values from. + * @param left + * the array where the coordinates of the start curve should be + * written. + * @param leftOff + * the offset in the left array to start writing the values. + * @param right + * the array where the coordinates of the end curve should be + * written. + * @param rightOff + * the offset in the right array to start writing the values. + * @throws ArrayIndexOutOfBoundsException + * if src.length < srcoff + 8 or if left.length < leftOff + 8 or + * if right.length < rightOff + 8. + * @throws NullPointerException + * if one of the arrays is null. + */ + public static void subdivide(double src[], int srcOff, double left[], int leftOff, + double right[], int rightOff) { + double x1 = src[srcOff + 0]; + double y1 = src[srcOff + 1]; + double cx1 = src[srcOff + 2]; + double cy1 = src[srcOff + 3]; + double cx2 = src[srcOff + 4]; + double cy2 = src[srcOff + 5]; + double x2 = src[srcOff + 6]; + double y2 = src[srcOff + 7]; + double cx = (cx1 + cx2) / 2.0; + double cy = (cy1 + cy2) / 2.0; + cx1 = (x1 + cx1) / 2.0; + cy1 = (y1 + cy1) / 2.0; + cx2 = (x2 + cx2) / 2.0; + cy2 = (y2 + cy2) / 2.0; + double ax = (cx1 + cx) / 2.0; + double ay = (cy1 + cy) / 2.0; + double bx = (cx2 + cx) / 2.0; + double by = (cy2 + cy) / 2.0; + cx = (ax + bx) / 2.0; + cy = (ay + by) / 2.0; + if (left != null) { + left[leftOff + 0] = x1; + left[leftOff + 1] = y1; + left[leftOff + 2] = cx1; + left[leftOff + 3] = cy1; + left[leftOff + 4] = ax; + left[leftOff + 5] = ay; + left[leftOff + 6] = cx; + left[leftOff + 7] = cy; + } + if (right != null) { + right[rightOff + 0] = cx; + right[rightOff + 1] = cy; + right[rightOff + 2] = bx; + right[rightOff + 3] = by; + right[rightOff + 4] = cx2; + right[rightOff + 5] = cy2; + right[rightOff + 6] = x2; + right[rightOff + 7] = y2; + } + } + + /** + * Finds the roots of the cubic polynomial. This is accomplished by finding + * the (real) values of x that solve the following equation: eqn[3]*x*x*x + + * eqn[2]*x*x + eqn[1]*x + eqn[0] = 0. The solutions are written back into + * the array eqn starting from the index 0 in the array. The return value + * tells how many array elements have been changed by this method call. + * + * @param eqn + * an array containing the coefficients of the cubic polynomial + * to solve. + * @return the number of roots of the cubic polynomial. + * @throws ArrayIndexOutOfBoundsException + * if eqn.length < 4. + * @throws NullPointerException + * if the array is null. + */ + public static int solveCubic(double eqn[]) { + return solveCubic(eqn, eqn); + } + + /** + * Finds the roots of the cubic polynomial. This is accomplished by finding + * the (real) values of x that solve the following equation: eqn[3]*x*x*x + + * eqn[2]*x*x + eqn[1]*x + eqn[0] = 0. The solutions are written into the + * array res starting from the index 0 in the array. The return value tells + * how many array elements have been changed by this method call. + * + * @param eqn + * an array containing the coefficients of the cubic polynomial + * to solve. + * @param res + * the array that this method writes the results into. + * @return the number of roots of the cubic polynomial. + * @throws ArrayIndexOutOfBoundsException + * if eqn.length < 4 or if res.length is less than the number of + * roots. + * @throws NullPointerException + * if either array is null. + */ + public static int solveCubic(double eqn[], double res[]) { + return Crossing.solveCubic(eqn, res); + } + + public boolean contains(double px, double py) { + return Crossing.isInsideEvenOdd(Crossing.crossShape(this, px, py)); + } + + public boolean contains(double rx, double ry, double rw, double rh) { + int cross = Crossing.intersectShape(this, rx, ry, rw, rh); + return cross != Crossing.CROSSING && Crossing.isInsideEvenOdd(cross); + } + + public boolean intersects(double rx, double ry, double rw, double rh) { + int cross = Crossing.intersectShape(this, rx, ry, rw, rh); + return cross == Crossing.CROSSING || Crossing.isInsideEvenOdd(cross); + } + + public boolean contains(Point2D p) { + return contains(p.getX(), p.getY()); + } + + public boolean intersects(Rectangle2D r) { + return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + public boolean contains(Rectangle2D r) { + return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + public Rectangle getBounds() { + return getBounds2D().getBounds(); + } + + public PathIterator getPathIterator(AffineTransform t) { + return new Iterator(this, t); + } + + public PathIterator getPathIterator(AffineTransform at, double flatness) { + return new FlatteningPathIterator(getPathIterator(at), flatness); + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + } +}
\ No newline at end of file diff --git a/awt/java/awt/geom/Dimension2D.java b/awt/java/awt/geom/Dimension2D.java new file mode 100644 index 0000000..ea081c5 --- /dev/null +++ b/awt/java/awt/geom/Dimension2D.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt.geom; + +/** + * The Class Dimension2D represents a size (width and height) of a geometric + * object. It stores double-valued data in order to be compatible with + * high-precision geometric operations. + * + * @since Android 1.0 + */ +public abstract class Dimension2D implements Cloneable { + + /** + * Instantiates a new dimension 2d with no data. + */ + protected Dimension2D() { + } + + /** + * Gets the width. + * + * @return the width. + */ + public abstract double getWidth(); + + /** + * Gets the height. + * + * @return the height. + */ + public abstract double getHeight(); + + /** + * Sets the width and height. + * + * @param width + * the width. + * @param height + * the height. + */ + public abstract void setSize(double width, double height); + + /** + * Sets the width and height based on the data of another Dimension2D + * object. + * + * @param d + * the Dimension2D object providing the data to copy into this + * Dimension2D object. + */ + public void setSize(Dimension2D d) { + setSize(d.getWidth(), d.getHeight()); + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + } +} diff --git a/awt/java/awt/geom/Ellipse2D.java b/awt/java/awt/geom/Ellipse2D.java new file mode 100644 index 0000000..89fd0d0 --- /dev/null +++ b/awt/java/awt/geom/Ellipse2D.java @@ -0,0 +1,458 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt.geom; + +import java.util.NoSuchElementException; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class Ellipse2D describes an ellipse defined by a rectangular area in + * which it is inscribed. + * + * @since Android 1.0 + */ +public abstract class Ellipse2D extends RectangularShape { + + /** + * The Class Float is the subclass of Ellipse2D that has all of its data + * values stored with float-level precision. + * + * @since Android 1.0 + */ + public static class Float extends Ellipse2D { + + /** + * The x coordinate of the upper left corner of the ellipse's bounding + * rectangle. + */ + public float x; + + /** + * The y coordinate of the upper left corner of the ellipse's bounding + * rectangle. + */ + public float y; + + /** + * The width of the ellipse's bounding rectangle. + */ + public float width; + + /** + * The height of the ellipse's bounding rectangle. + */ + public float height; + + /** + * Instantiates a new float-valued Ellipse2D. + */ + public Float() { + } + + /** + * Instantiates a new float-valued Ellipse2D with the specified data. + * + * @param x + * the x coordinate of the upper left corner of the ellipse's + * bounding rectangle. + * @param y + * the y coordinate of the upper left corner of the ellipse's + * bounding rectangle. + * @param width + * the width of the ellipse's bounding rectangle. + * @param height + * the height of the ellipse's bounding rectangle. + */ + public Float(float x, float y, float width, float height) { + setFrame(x, y, width, height); + } + + @Override + public double getX() { + return x; + } + + @Override + public double getY() { + return y; + } + + @Override + public double getWidth() { + return width; + } + + @Override + public double getHeight() { + return height; + } + + @Override + public boolean isEmpty() { + return width <= 0.0 || height <= 0.0; + } + + /** + * Sets the data of the ellipse's bounding rectangle. + * + * @param x + * the x coordinate of the upper left corner of the ellipse's + * bounding rectangle. + * @param y + * the y coordinate of the upper left corner of the ellipse's + * bounding rectangle. + * @param width + * the width of the ellipse's bounding rectangle. + * @param height + * the height of the ellipse's bounding rectangle. + */ + public void setFrame(float x, float y, float width, float height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + @Override + public void setFrame(double x, double y, double width, double height) { + this.x = (float)x; + this.y = (float)y; + this.width = (float)width; + this.height = (float)height; + } + + public Rectangle2D getBounds2D() { + return new Rectangle2D.Float(x, y, width, height); + } + } + + /** + * The Class Double is the subclass of Ellipse2D that has all of its data + * values stored with double-level precision. + * + * @since Android 1.0 + */ + public static class Double extends Ellipse2D { + + /** + * The x coordinate of the upper left corner of the ellipse's bounding + * rectangle. + */ + public double x; + + /** + * The y coordinate of the upper left corner of the ellipse's bounding + * rectangle. + */ + public double y; + + /** + * The width of the ellipse's bounding rectangle. + */ + public double width; + + /** + * The height of the ellipse's bounding rectangle. + */ + public double height; + + /** + * Instantiates a new double-valued Ellipse2D. + */ + public Double() { + } + + /** + * Instantiates a new double-valued Ellipse2D with the specified data. + * + * @param x + * the x coordinate of the upper left corner of the ellipse's + * bounding rectangle. + * @param y + * the y coordinate of the upper left corner of the ellipse's + * bounding rectangle. + * @param width + * the width of the ellipse's bounding rectangle. + * @param height + * the height of the ellipse's bounding rectangle. + */ + public Double(double x, double y, double width, double height) { + setFrame(x, y, width, height); + } + + @Override + public double getX() { + return x; + } + + @Override + public double getY() { + return y; + } + + @Override + public double getWidth() { + return width; + } + + @Override + public double getHeight() { + return height; + } + + @Override + public boolean isEmpty() { + return width <= 0.0 || height <= 0.0; + } + + @Override + public void setFrame(double x, double y, double width, double height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + public Rectangle2D getBounds2D() { + return new Rectangle2D.Double(x, y, width, height); + } + } + + /* + * Ellipse2D path iterator + */ + /** + * The subclass of PathIterator to traverse an Ellipse2D. + */ + class Iterator implements PathIterator { + + /* + * Ellipse is subdivided into four quarters by x and y axis. Each part + * approximated by cubic Bezier curve. Arc in first quarter is started + * in (a, 0) and finished in (0, b) points. Control points for cubic + * curve wiil be (a, 0), (a, m), (n, b) and (0, b) where n and m are + * calculated based on requirement Bezier curve in point 0.5 should lay + * on the arc. + */ + + /** + * The coefficient to calculate control points of Bezier curves. + */ + final double u = 2.0 / 3.0 * (Math.sqrt(2.0) - 1.0); + + /** + * The points coordinates calculation table. + */ + final double points[][] = { + { + 1.0, 0.5 + u, 0.5 + u, 1.0, 0.5, 1.0 + }, { + 0.5 - u, 1.0, 0.0, 0.5 + u, 0.0, 0.5 + }, { + 0.0, 0.5 - u, 0.5 - u, 0.0, 0.5, 0.0 + }, { + 0.5 + u, 0.0, 1.0, 0.5 - u, 1.0, 0.5 + } + }; + + /** + * The x coordinate of left-upper corner of the ellipse bounds. + */ + double x; + + /** + * The y coordinate of left-upper corner of the ellipse bounds. + */ + double y; + + /** + * The width of the ellipse bounds. + */ + double width; + + /** + * The height of the ellipse bounds. + */ + double height; + + /** + * The path iterator transformation. + */ + AffineTransform t; + + /** + * The current segment index. + */ + int index; + + /** + * Constructs a new Ellipse2D.Iterator for given ellipse and + * transformation + * + * @param e + * the source Ellipse2D object. + * @param t + * the affine transformation object. + */ + Iterator(Ellipse2D e, AffineTransform t) { + this.x = e.getX(); + this.y = e.getY(); + this.width = e.getWidth(); + this.height = e.getHeight(); + this.t = t; + if (width < 0.0 || height < 0.0) { + index = 6; + } + } + + public int getWindingRule() { + return WIND_NON_ZERO; + } + + public boolean isDone() { + return index > 5; + } + + public void next() { + index++; + } + + public int currentSegment(double[] coords) { + if (isDone()) { + // awt.4B=Iterator out of bounds + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + if (index == 5) { + return SEG_CLOSE; + } + int type; + int count; + if (index == 0) { + type = SEG_MOVETO; + count = 1; + double p[] = points[3]; + coords[0] = x + p[4] * width; + coords[1] = y + p[5] * height; + } else { + type = SEG_CUBICTO; + count = 3; + double p[] = points[index - 1]; + int j = 0; + for (int i = 0; i < 3; i++) { + coords[j] = x + p[j++] * width; + coords[j] = y + p[j++] * height; + } + } + if (t != null) { + t.transform(coords, 0, coords, 0, count); + } + return type; + } + + public int currentSegment(float[] coords) { + if (isDone()) { + // awt.4B=Iterator out of bounds + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + if (index == 5) { + return SEG_CLOSE; + } + int type; + int count; + if (index == 0) { + type = SEG_MOVETO; + count = 1; + double p[] = points[3]; + coords[0] = (float)(x + p[4] * width); + coords[1] = (float)(y + p[5] * height); + } else { + type = SEG_CUBICTO; + count = 3; + int j = 0; + double p[] = points[index - 1]; + for (int i = 0; i < 3; i++) { + coords[j] = (float)(x + p[j++] * width); + coords[j] = (float)(y + p[j++] * height); + } + } + if (t != null) { + t.transform(coords, 0, coords, 0, count); + } + return type; + } + + } + + /** + * Instantiates a new Ellipse2D. + */ + protected Ellipse2D() { + } + + public boolean contains(double px, double py) { + if (isEmpty()) { + return false; + } + + double a = (px - getX()) / getWidth() - 0.5; + double b = (py - getY()) / getHeight() - 0.5; + + return a * a + b * b < 0.25; + } + + public boolean intersects(double rx, double ry, double rw, double rh) { + if (isEmpty() || rw <= 0.0 || rh <= 0.0) { + return false; + } + + double cx = getX() + getWidth() / 2.0; + double cy = getY() + getHeight() / 2.0; + + double rx1 = rx; + double ry1 = ry; + double rx2 = rx + rw; + double ry2 = ry + rh; + + double nx = cx < rx1 ? rx1 : (cx > rx2 ? rx2 : cx); + double ny = cy < ry1 ? ry1 : (cy > ry2 ? ry2 : cy); + + return contains(nx, ny); + } + + public boolean contains(double rx, double ry, double rw, double rh) { + if (isEmpty() || rw <= 0.0 || rh <= 0.0) { + return false; + } + + double rx1 = rx; + double ry1 = ry; + double rx2 = rx + rw; + double ry2 = ry + rh; + + return contains(rx1, ry1) && contains(rx2, ry1) && contains(rx2, ry2) && contains(rx1, ry2); + } + + public PathIterator getPathIterator(AffineTransform at) { + return new Iterator(this, at); + } +} diff --git a/awt/java/awt/geom/FlatteningPathIterator.java b/awt/java/awt/geom/FlatteningPathIterator.java new file mode 100644 index 0000000..8208f39 --- /dev/null +++ b/awt/java/awt/geom/FlatteningPathIterator.java @@ -0,0 +1,358 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt.geom; + +import java.util.NoSuchElementException; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class FlatteningPathIterator takes a PathIterator for traversing a curved + * shape and flattens it by estimating the curve as a series of line segments. + * The flattening factor indicates how far the estimating line segments are + * allowed to be from the actual curve: the FlatteningPathIterator will keep + * dividing each curved segment into smaller and smaller flat segments until + * either the segments are within the flattening factor of the curve or until + * the buffer limit is reached. + * + * @since Android 1.0 + */ +public class FlatteningPathIterator implements PathIterator { + + /** + * The default points buffer size. + */ + private static final int BUFFER_SIZE = 16; + + /** + * The default curve subdivision limit. + */ + private static final int BUFFER_LIMIT = 16; + + /** + * The points buffer capacity. + */ + private static final int BUFFER_CAPACITY = 16; + + /** + * The type of current segment to be flat. + */ + int bufType; + + /** + * The curve subdivision limit. + */ + int bufLimit; + + /** + * The current points buffer size. + */ + int bufSize; + + /** + * The inner cursor position in points buffer. + */ + int bufIndex; + + /** + * The current subdivision count. + */ + int bufSubdiv; + + /** + * The points buffer. + */ + double buf[]; + + /** + * The indicator of empty points buffer. + */ + boolean bufEmpty = true; + + /** + * The source PathIterator. + */ + PathIterator p; + + /** + * The flatness of new path. + */ + double flatness; + + /** + * The square of flatness. + */ + double flatness2; + + /** + * The x coordinate of previous path segment. + */ + double px; + + /** + * The y coordinate of previous path segment. + */ + double py; + + /** + * The temporary buffer for getting points from PathIterator. + */ + double coords[] = new double[6]; + + /** + * Instantiates a new flattening path iterator given the path iterator for a + * (possibly) curved path and a flattening factor which indicates how close + * together the points on the curve should be chosen. The buffer limit + * defaults to 16 which means that each curve will be divided into no more + * than 16 segments regardless of the flattening factor. + * + * @param path + * the path iterator of the original curve. + * @param flatness + * the flattening factor that indicates how far the flat path is + * allowed to be from the actual curve in order to decide when to + * stop dividing the path into smaller and smaller segments. + * @throws IllegalArgumentException + * if the flatness is less than zero. + * @throws NullPointerException + * if the path is null. + */ + public FlatteningPathIterator(PathIterator path, double flatness) { + this(path, flatness, BUFFER_LIMIT); + } + + /** + * Instantiates a new flattening path iterator given the path iterator for a + * (possibly) curved path and a flattening factor and a buffer limit. The + * FlatteningPathIterator will keep dividing each curved segment into + * smaller and smaller flat segments until either the segments are within + * the flattening factor of the curve or until the buffer limit is reached. + * + * @param path + * the path iterator of the original curve. + * @param flatness + * the flattening factor that indicates how far the flat path is + * allowed to be from the actual curve in order to decide when to + * stop dividing the path into smaller and smaller segments. + * @param limit + * the maximum number of flat segments to divide each curve into. + * @throws IllegalArgumentException + * if the flatness or limit is less than zero. + * @throws NullPointerException + * if the path is null. + */ + public FlatteningPathIterator(PathIterator path, double flatness, int limit) { + if (flatness < 0.0) { + // awt.206=Flatness is less then zero + throw new IllegalArgumentException(Messages.getString("awt.206")); //$NON-NLS-1$ + } + if (limit < 0) { + // awt.207=Limit is less then zero + throw new IllegalArgumentException(Messages.getString("awt.207")); //$NON-NLS-1$ + } + if (path == null) { + // awt.208=Path is null + throw new NullPointerException(Messages.getString("awt.208")); //$NON-NLS-1$ + } + this.p = path; + this.flatness = flatness; + this.flatness2 = flatness * flatness; + this.bufLimit = limit; + this.bufSize = Math.min(bufLimit, BUFFER_SIZE); + this.buf = new double[bufSize]; + this.bufIndex = bufSize; + } + + /** + * Gets the flattening factor. + * + * @return the flattening factor. + */ + public double getFlatness() { + return flatness; + } + + /** + * Gets the maximum number of subdivisions per curved segment. + * + * @return the maximum number of subdivisions per curved segment. + */ + public int getRecursionLimit() { + return bufLimit; + } + + public int getWindingRule() { + return p.getWindingRule(); + } + + public boolean isDone() { + return bufEmpty && p.isDone(); + } + + /** + * Calculates flat path points for current segment of the source shape. Line + * segment is flat by itself. Flatness of quad and cubic curves evaluated by + * getFlatnessSq() method. Curves subdivided until current flatness is + * bigger than user defined and subdivision limit isn't exhausted. Single + * source segment translated to series of buffer points. The less flatness + * the bigger series. Every currentSegment() call extract one point from the + * buffer. When series completed evaluate() takes next source shape segment. + */ + void evaluate() { + if (bufEmpty) { + bufType = p.currentSegment(coords); + } + + switch (bufType) { + case SEG_MOVETO: + case SEG_LINETO: + px = coords[0]; + py = coords[1]; + break; + case SEG_QUADTO: + if (bufEmpty) { + bufIndex -= 6; + buf[bufIndex + 0] = px; + buf[bufIndex + 1] = py; + System.arraycopy(coords, 0, buf, bufIndex + 2, 4); + bufSubdiv = 0; + } + + while (bufSubdiv < bufLimit) { + if (QuadCurve2D.getFlatnessSq(buf, bufIndex) < flatness2) { + break; + } + + // Realloc buffer + if (bufIndex <= 4) { + double tmp[] = new double[bufSize + BUFFER_CAPACITY]; + System.arraycopy(buf, bufIndex, tmp, bufIndex + BUFFER_CAPACITY, bufSize + - bufIndex); + buf = tmp; + bufSize += BUFFER_CAPACITY; + bufIndex += BUFFER_CAPACITY; + } + + QuadCurve2D.subdivide(buf, bufIndex, buf, bufIndex - 4, buf, bufIndex); + + bufIndex -= 4; + bufSubdiv++; + } + + bufIndex += 4; + px = buf[bufIndex]; + py = buf[bufIndex + 1]; + + bufEmpty = (bufIndex == bufSize - 2); + if (bufEmpty) { + bufIndex = bufSize; + bufType = SEG_LINETO; + } else { + bufSubdiv--; + } + break; + case SEG_CUBICTO: + if (bufEmpty) { + bufIndex -= 8; + buf[bufIndex + 0] = px; + buf[bufIndex + 1] = py; + System.arraycopy(coords, 0, buf, bufIndex + 2, 6); + bufSubdiv = 0; + } + + while (bufSubdiv < bufLimit) { + if (CubicCurve2D.getFlatnessSq(buf, bufIndex) < flatness2) { + break; + } + + // Realloc buffer + if (bufIndex <= 6) { + double tmp[] = new double[bufSize + BUFFER_CAPACITY]; + System.arraycopy(buf, bufIndex, tmp, bufIndex + BUFFER_CAPACITY, bufSize + - bufIndex); + buf = tmp; + bufSize += BUFFER_CAPACITY; + bufIndex += BUFFER_CAPACITY; + } + + CubicCurve2D.subdivide(buf, bufIndex, buf, bufIndex - 6, buf, bufIndex); + + bufIndex -= 6; + bufSubdiv++; + } + + bufIndex += 6; + px = buf[bufIndex]; + py = buf[bufIndex + 1]; + + bufEmpty = (bufIndex == bufSize - 2); + if (bufEmpty) { + bufIndex = bufSize; + bufType = SEG_LINETO; + } else { + bufSubdiv--; + } + break; + } + + } + + public void next() { + if (bufEmpty) { + p.next(); + } + } + + public int currentSegment(float[] coords) { + if (isDone()) { + // awt.4B=Iterator out of bounds + throw new NoSuchElementException(Messages.getString("awt.4Bx")); //$NON-NLS-1$ + } + evaluate(); + int type = bufType; + if (type != SEG_CLOSE) { + coords[0] = (float)px; + coords[1] = (float)py; + if (type != SEG_MOVETO) { + type = SEG_LINETO; + } + } + return type; + } + + public int currentSegment(double[] coords) { + if (isDone()) { + // awt.4B=Iterator out of bounds + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + evaluate(); + int type = bufType; + if (type != SEG_CLOSE) { + coords[0] = px; + coords[1] = py; + if (type != SEG_MOVETO) { + type = SEG_LINETO; + } + } + return type; + } +} diff --git a/awt/java/awt/geom/GeneralPath.java b/awt/java/awt/geom/GeneralPath.java new file mode 100644 index 0000000..0669bc7 --- /dev/null +++ b/awt/java/awt/geom/GeneralPath.java @@ -0,0 +1,624 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt.geom; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.util.NoSuchElementException; + +import org.apache.harmony.awt.gl.Crossing; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The class GeneralPath represents a shape whose outline is given by different + * types of curved and straight segments. + * + * @since Android 1.0 + */ +public final class GeneralPath implements Shape, Cloneable { + + /** + * The Constant WIND_EVEN_ODD see {@link PathIterator#WIND_EVEN_ODD}. + */ + public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD; + + /** + * The Constant WIND_NON_ZERO see {@link PathIterator#WIND_NON_ZERO}. + */ + public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO; + + /** + * The buffers size. + */ + private static final int BUFFER_SIZE = 10; + + /** + * The buffers capacity. + */ + private static final int BUFFER_CAPACITY = 10; + + /** + * The point's types buffer. + */ + byte[] types; + + /** + * The points buffer. + */ + float[] points; + + /** + * The point's type buffer size. + */ + int typeSize; + + /** + * The points buffer size. + */ + int pointSize; + + /** + * The path rule. + */ + int rule; + + /** + * The space amount in points buffer for different segmenet's types. + */ + static int pointShift[] = { + 2, // MOVETO + 2, // LINETO + 4, // QUADTO + 6, // CUBICTO + 0 + }; // CLOSE + + /* + * GeneralPath path iterator + */ + /** + * The Class Iterator is the subclass of Iterator for traversing the outline + * of a GeneralPath. + */ + class Iterator implements PathIterator { + + /** + * The current cursor position in types buffer. + */ + int typeIndex; + + /** + * The current cursor position in points buffer. + */ + int pointIndex; + + /** + * The source GeneralPath object. + */ + GeneralPath p; + + /** + * The path iterator transformation. + */ + AffineTransform t; + + /** + * Constructs a new GeneralPath.Iterator for given general path. + * + * @param path + * the source GeneralPath object. + */ + Iterator(GeneralPath path) { + this(path, null); + } + + /** + * Constructs a new GeneralPath.Iterator for given general path and + * transformation. + * + * @param path + * the source GeneralPath object. + * @param at + * the AffineTransform object to apply rectangle path. + */ + Iterator(GeneralPath path, AffineTransform at) { + this.p = path; + this.t = at; + } + + public int getWindingRule() { + return p.getWindingRule(); + } + + public boolean isDone() { + return typeIndex >= p.typeSize; + } + + public void next() { + typeIndex++; + } + + public int currentSegment(double[] coords) { + if (isDone()) { + // awt.4B=Iterator out of bounds + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + int type = p.types[typeIndex]; + int count = GeneralPath.pointShift[type]; + for (int i = 0; i < count; i++) { + coords[i] = p.points[pointIndex + i]; + } + if (t != null) { + t.transform(coords, 0, coords, 0, count / 2); + } + pointIndex += count; + return type; + } + + public int currentSegment(float[] coords) { + if (isDone()) { + // awt.4B=Iterator out of bounds + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + int type = p.types[typeIndex]; + int count = GeneralPath.pointShift[type]; + System.arraycopy(p.points, pointIndex, coords, 0, count); + if (t != null) { + t.transform(coords, 0, coords, 0, count / 2); + } + pointIndex += count; + return type; + } + + } + + /** + * Instantiates a new general path with the winding rule set to + * {@link PathIterator#WIND_NON_ZERO} and the initial capacity (number of + * segments) set to the default value 10. + */ + public GeneralPath() { + this(WIND_NON_ZERO, BUFFER_SIZE); + } + + /** + * Instantiates a new general path with the given winding rule and the + * initial capacity (number of segments) set to the default value 10. + * + * @param rule + * the winding rule, either {@link PathIterator#WIND_EVEN_ODD} or + * {@link PathIterator#WIND_NON_ZERO}. + */ + public GeneralPath(int rule) { + this(rule, BUFFER_SIZE); + } + + /** + * Instantiates a new general path with the given winding rule and initial + * capacity (number of segments). + * + * @param rule + * the winding rule, either {@link PathIterator#WIND_EVEN_ODD} or + * {@link PathIterator#WIND_NON_ZERO}. + * @param initialCapacity + * the number of segments the path is set to hold. + */ + public GeneralPath(int rule, int initialCapacity) { + setWindingRule(rule); + types = new byte[initialCapacity]; + points = new float[initialCapacity * 2]; + } + + /** + * Creates a new GeneralPath from the outline of the given shape. + * + * @param shape + * the shape. + */ + public GeneralPath(Shape shape) { + this(WIND_NON_ZERO, BUFFER_SIZE); + PathIterator p = shape.getPathIterator(null); + setWindingRule(p.getWindingRule()); + append(p, false); + } + + /** + * Sets the winding rule, which determines how to decide whether a point + * that isn't on the path itself is inside or outside of the shape. + * + * @param rule + * the new winding rule. + * @throws IllegalArgumentException + * if the winding rule is neither + * {@link PathIterator#WIND_EVEN_ODD} nor + * {@link PathIterator#WIND_NON_ZERO}. + */ + public void setWindingRule(int rule) { + if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) { + // awt.209=Invalid winding rule value + throw new java.lang.IllegalArgumentException(Messages.getString("awt.209")); //$NON-NLS-1$ + } + this.rule = rule; + } + + /** + * Gets the winding rule. + * + * @return the winding rule, either {@link PathIterator#WIND_EVEN_ODD} or + * {@link PathIterator#WIND_NON_ZERO}. + */ + public int getWindingRule() { + return rule; + } + + /** + * Checks the point data buffer sizes to see whether pointCount additional + * point-data elements can fit. (Note that the number of point data elements + * to add is more than one per point -- it depends on the type of point + * being added.) Reallocates the buffers to enlarge the size if necessary. + * + * @param pointCount + * the number of point data elements to be added. + * @param checkMove + * whether to check for existing points. + * @throws IllegalPathStateException + * checkMove is true and the path is currently empty. + */ + void checkBuf(int pointCount, boolean checkMove) { + if (checkMove && typeSize == 0) { + // awt.20A=First segment should be SEG_MOVETO type + throw new IllegalPathStateException(Messages.getString("awt.20A")); //$NON-NLS-1$ + } + if (typeSize == types.length) { + byte tmp[] = new byte[typeSize + BUFFER_CAPACITY]; + System.arraycopy(types, 0, tmp, 0, typeSize); + types = tmp; + } + if (pointSize + pointCount > points.length) { + float tmp[] = new float[pointSize + Math.max(BUFFER_CAPACITY * 2, pointCount)]; + System.arraycopy(points, 0, tmp, 0, pointSize); + points = tmp; + } + } + + /** + * Appends a new point to the end of this general path, disconnected from + * the existing path. + * + * @param x + * the x coordinate of the next point to append. + * @param y + * the y coordinate of the next point to append. + */ + public void moveTo(float x, float y) { + if (typeSize > 0 && types[typeSize - 1] == PathIterator.SEG_MOVETO) { + points[pointSize - 2] = x; + points[pointSize - 1] = y; + } else { + checkBuf(2, false); + types[typeSize++] = PathIterator.SEG_MOVETO; + points[pointSize++] = x; + points[pointSize++] = y; + } + } + + /** + * Appends a new segment to the end of this general path by making a + * straight line segment from the current endpoint to the given new point. + * + * @param x + * the x coordinate of the next point to append. + * @param y + * the y coordinate of the next point to append. + */ + public void lineTo(float x, float y) { + checkBuf(2, true); + types[typeSize++] = PathIterator.SEG_LINETO; + points[pointSize++] = x; + points[pointSize++] = y; + } + + /** + * Appends a new segment to the end of this general path by making a + * quadratic curve from the current endpoint to the point (x2, y2) using the + * point (x1, y1) as the quadratic curve's control point. + * + * @param x1 + * the x coordinate of the quadratic curve's control point. + * @param y1 + * the y coordinate of the quadratic curve's control point. + * @param x2 + * the x coordinate of the quadratic curve's end point. + * @param y2 + * the y coordinate of the quadratic curve's end point. + */ + public void quadTo(float x1, float y1, float x2, float y2) { + checkBuf(4, true); + types[typeSize++] = PathIterator.SEG_QUADTO; + points[pointSize++] = x1; + points[pointSize++] = y1; + points[pointSize++] = x2; + points[pointSize++] = y2; + } + + /** + * Appends a new segment to the end of this general path by making a cubic + * curve from the current endpoint to the point (x3, y3) using (x1, y1) and + * (x2, y2) as control points. + * + * @see java.awt.geom.CubicCurve2D + * @param x1 + * the x coordinate of the new cubic segment's first control + * point. + * @param y1 + * the y coordinate of the new cubic segment's first control + * point. + * @param x2 + * the x coordinate of the new cubic segment's second control + * point. + * @param y2 + * the y coordinate of the new cubic segment's second control + * point. + * @param x3 + * the x coordinate of the new cubic segment's end point. + * @param y3 + * the y coordinate of the new cubic segment's end point. + */ + public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) { + checkBuf(6, true); + types[typeSize++] = PathIterator.SEG_CUBICTO; + points[pointSize++] = x1; + points[pointSize++] = y1; + points[pointSize++] = x2; + points[pointSize++] = y2; + points[pointSize++] = x3; + points[pointSize++] = y3; + } + + /** + * Appends the type information to declare that the current endpoint closes + * the curve. + */ + public void closePath() { + if (typeSize == 0 || types[typeSize - 1] != PathIterator.SEG_CLOSE) { + checkBuf(0, true); + types[typeSize++] = PathIterator.SEG_CLOSE; + } + } + + /** + * Appends the outline of the specified shape onto the end of this + * GeneralPath. + * + * @param shape + * the shape whose outline is to be appended. + * @param connect + * true to connect this path's current endpoint to the first + * point of the shape's outline or false to append the shape's + * outline without connecting it. + * @throws NullPointerException + * if the shape parameter is null. + */ + public void append(Shape shape, boolean connect) { + PathIterator p = shape.getPathIterator(null); + append(p, connect); + } + + /** + * Appends the path defined by the specified PathIterator onto the end of + * this GeneralPath. + * + * @param path + * the PathIterator that defines the new path to append. + * @param connect + * true to connect this path's current endpoint to the first + * point of the shape's outline or false to append the shape's + * outline without connecting it. + */ + public void append(PathIterator path, boolean connect) { + while (!path.isDone()) { + float coords[] = new float[6]; + switch (path.currentSegment(coords)) { + case PathIterator.SEG_MOVETO: + if (!connect || typeSize == 0) { + moveTo(coords[0], coords[1]); + break; + } + if (types[typeSize - 1] != PathIterator.SEG_CLOSE + && points[pointSize - 2] == coords[0] + && points[pointSize - 1] == coords[1]) { + break; + } + // NO BREAK; + case PathIterator.SEG_LINETO: + lineTo(coords[0], coords[1]); + break; + case PathIterator.SEG_QUADTO: + quadTo(coords[0], coords[1], coords[2], coords[3]); + break; + case PathIterator.SEG_CUBICTO: + curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); + break; + case PathIterator.SEG_CLOSE: + closePath(); + break; + } + path.next(); + connect = false; + } + } + + /** + * Gets the current end point of the path. + * + * @return the current end point of the path. + */ + public Point2D getCurrentPoint() { + if (typeSize == 0) { + return null; + } + int j = pointSize - 2; + if (types[typeSize - 1] == PathIterator.SEG_CLOSE) { + + for (int i = typeSize - 2; i > 0; i--) { + int type = types[i]; + if (type == PathIterator.SEG_MOVETO) { + break; + } + j -= pointShift[type]; + } + } + return new Point2D.Float(points[j], points[j + 1]); + } + + /** + * Resets the GeneralPath to being an empty path. The underlying point and + * segment data is not deleted but rather the end indices of the data arrays + * are set to zero. + */ + public void reset() { + typeSize = 0; + pointSize = 0; + } + + /** + * Transform all of the coordinates of this path according to the specified + * AffineTransform. + * + * @param t + * the AffineTransform. + */ + public void transform(AffineTransform t) { + t.transform(points, 0, points, 0, pointSize / 2); + } + + /** + * Creates a new GeneralPath whose data is given by this path's data + * transformed according to the specified AffineTransform. + * + * @param t + * the AffineTransform. + * @return the new GeneralPath whose data is given by this path's data + * transformed according to the specified AffineTransform. + */ + public Shape createTransformedShape(AffineTransform t) { + GeneralPath p = (GeneralPath)clone(); + if (t != null) { + p.transform(t); + } + return p; + } + + public Rectangle2D getBounds2D() { + float rx1, ry1, rx2, ry2; + if (pointSize == 0) { + rx1 = ry1 = rx2 = ry2 = 0.0f; + } else { + int i = pointSize - 1; + ry1 = ry2 = points[i--]; + rx1 = rx2 = points[i--]; + while (i > 0) { + float y = points[i--]; + float x = points[i--]; + if (x < rx1) { + rx1 = x; + } else if (x > rx2) { + rx2 = x; + } + if (y < ry1) { + ry1 = y; + } else if (y > ry2) { + ry2 = y; + } + } + } + return new Rectangle2D.Float(rx1, ry1, rx2 - rx1, ry2 - ry1); + } + + public Rectangle getBounds() { + return getBounds2D().getBounds(); + } + + /** + * Checks the cross count (number of times a ray from the point crosses the + * shape's boundary) to determine whether the number of crossings + * corresponds to a point inside the shape or not (according to the shape's + * path rule). + * + * @param cross + * the point's cross count. + * @return true if the point is inside the path, or false otherwise. + */ + boolean isInside(int cross) { + if (rule == WIND_NON_ZERO) { + return Crossing.isInsideNonZero(cross); + } + return Crossing.isInsideEvenOdd(cross); + } + + public boolean contains(double px, double py) { + return isInside(Crossing.crossShape(this, px, py)); + } + + public boolean contains(double rx, double ry, double rw, double rh) { + int cross = Crossing.intersectShape(this, rx, ry, rw, rh); + return cross != Crossing.CROSSING && isInside(cross); + } + + public boolean intersects(double rx, double ry, double rw, double rh) { + int cross = Crossing.intersectShape(this, rx, ry, rw, rh); + return cross == Crossing.CROSSING || isInside(cross); + } + + public boolean contains(Point2D p) { + return contains(p.getX(), p.getY()); + } + + public boolean contains(Rectangle2D r) { + return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + public boolean intersects(Rectangle2D r) { + return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + public PathIterator getPathIterator(AffineTransform t) { + return new Iterator(this, t); + } + + public PathIterator getPathIterator(AffineTransform t, double flatness) { + return new FlatteningPathIterator(getPathIterator(t), flatness); + } + + @Override + public Object clone() { + try { + GeneralPath p = (GeneralPath)super.clone(); + p.types = types.clone(); + p.points = points.clone(); + return p; + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + } + +} diff --git a/awt/java/awt/geom/IllegalPathStateException.java b/awt/java/awt/geom/IllegalPathStateException.java new file mode 100644 index 0000000..750ba29 --- /dev/null +++ b/awt/java/awt/geom/IllegalPathStateException.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt.geom; + +/** + * The Class IllegalPathStateException indicates errors where the current state + * of a path object is incompatible with the desired action, such as performing + * non-trivial actions on an empty path. + * + * @since Android 1.0 + */ +public class IllegalPathStateException extends RuntimeException { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -5158084205220481094L; + + /** + * Instantiates a new illegal path state exception. + */ + public IllegalPathStateException() { + } + + /** + * Instantiates a new illegal path state exception with the specified detail + * message. + * + * @param s + * the details of the error. + */ + public IllegalPathStateException(String s) { + super(s); + } + +} diff --git a/awt/java/awt/geom/Line2D.java b/awt/java/awt/geom/Line2D.java new file mode 100644 index 0000000..fcd51b6 --- /dev/null +++ b/awt/java/awt/geom/Line2D.java @@ -0,0 +1,948 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt.geom; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.util.NoSuchElementException; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class Line2D represents a line whose data is given in high-precision + * values appropriate for graphical operations. + * + * @since Android 1.0 + */ +public abstract class Line2D implements Shape, Cloneable { + + /** + * The Class Float is the subclass of Line2D that has all of its data values + * stored with float-level precision. + * + * @since Android 1.0 + */ + public static class Float extends Line2D { + + /** + * The x coordinate of the starting point. + */ + public float x1; + + /** + * The y coordinate of the starting point. + */ + public float y1; + + /** + * The x coordinate of the end point. + */ + public float x2; + + /** + * The y coordinate of the end point. + */ + public float y2; + + /** + * Instantiates a new float-valued Line2D with its data values set to + * zero. + */ + public Float() { + } + + /** + * Instantiates a new float-valued Line2D with the specified endpoints. + * + * @param x1 + * the x coordinate of the starting point. + * @param y1 + * the y coordinate of the starting point. + * @param x2 + * the x coordinate of the end point. + * @param y2 + * the y coordinate of the end point. + */ + public Float(float x1, float y1, float x2, float y2) { + setLine(x1, y1, x2, y2); + } + + /** + * Instantiates a new float-valued Line2D with the specified endpoints. + * + * @param p1 + * the starting point. + * @param p2 + * the end point. + */ + public Float(Point2D p1, Point2D p2) { + setLine(p1, p2); + } + + @Override + public double getX1() { + return x1; + } + + @Override + public double getY1() { + return y1; + } + + @Override + public double getX2() { + return x2; + } + + @Override + public double getY2() { + return y2; + } + + @Override + public Point2D getP1() { + return new Point2D.Float(x1, y1); + } + + @Override + public Point2D getP2() { + return new Point2D.Float(x2, y2); + } + + @Override + public void setLine(double x1, double y1, double x2, double y2) { + this.x1 = (float)x1; + this.y1 = (float)y1; + this.x2 = (float)x2; + this.y2 = (float)y2; + } + + /** + * Sets the data values that define the line. + * + * @param x1 + * the x coordinate of the starting point. + * @param y1 + * the y coordinate of the starting point. + * @param x2 + * the x coordinate of the end point. + * @param y2 + * the y coordinate of the end point. + */ + public void setLine(float x1, float y1, float x2, float y2) { + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + } + + public Rectangle2D getBounds2D() { + float rx, ry, rw, rh; + if (x1 < x2) { + rx = x1; + rw = x2 - x1; + } else { + rx = x2; + rw = x1 - x2; + } + if (y1 < y2) { + ry = y1; + rh = y2 - y1; + } else { + ry = y2; + rh = y1 - y2; + } + return new Rectangle2D.Float(rx, ry, rw, rh); + } + } + + /** + * The Class Double is the subclass of Line2D that has all of its data + * values stored with double-level precision. + * + * @since Android 1.0 + */ + public static class Double extends Line2D { + + /** + * The x coordinate of the starting point. + */ + public double x1; + + /** + * The y coordinate of the starting point. + */ + public double y1; + + /** + * The x coordinate of the end point. + */ + public double x2; + + /** + * The y coordinate of the end point. + */ + public double y2; + + /** + * Instantiates a new double-valued Line2D with its data values set to + * zero. + */ + public Double() { + } + + /** + * Instantiates a new double-valued Line2D with the specified endpoints. + * + * @param x1 + * the x coordinate of the starting point. + * @param y1 + * the y coordinate of the starting point. + * @param x2 + * the x coordinate of the end point. + * @param y2 + * the y coordinate of the end point. + */ + public Double(double x1, double y1, double x2, double y2) { + setLine(x1, y1, x2, y2); + } + + /** + * Instantiates a new double-valued Line2D with the specified endpoints. + * + * @param p1 + * the starting point. + * @param p2 + * the end point. + */ + public Double(Point2D p1, Point2D p2) { + setLine(p1, p2); + } + + @Override + public double getX1() { + return x1; + } + + @Override + public double getY1() { + return y1; + } + + @Override + public double getX2() { + return x2; + } + + @Override + public double getY2() { + return y2; + } + + @Override + public Point2D getP1() { + return new Point2D.Double(x1, y1); + } + + @Override + public Point2D getP2() { + return new Point2D.Double(x2, y2); + } + + @Override + public void setLine(double x1, double y1, double x2, double y2) { + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + } + + public Rectangle2D getBounds2D() { + double rx, ry, rw, rh; + if (x1 < x2) { + rx = x1; + rw = x2 - x1; + } else { + rx = x2; + rw = x1 - x2; + } + if (y1 < y2) { + ry = y1; + rh = y2 - y1; + } else { + ry = y2; + rh = y1 - y2; + } + return new Rectangle2D.Double(rx, ry, rw, rh); + } + } + + /* + * Line2D path iterator + */ + /** + * The subclass of PathIterator to traverse a Line2D. + */ + class Iterator implements PathIterator { + + /** + * The x coordinate of the start line point. + */ + double x1; + + /** + * The y coordinate of the start line point. + */ + double y1; + + /** + * The x coordinate of the end line point. + */ + double x2; + + /** + * The y coordinate of the end line point. + */ + double y2; + + /** + * The path iterator transformation. + */ + AffineTransform t; + + /** + * The current segment index. + */ + int index; + + /** + * Constructs a new Line2D.Iterator for given line and transformation. + * + * @param l + * the source Line2D object. + * @param at + * the AffineTransform object to apply rectangle path. + */ + Iterator(Line2D l, AffineTransform at) { + this.x1 = l.getX1(); + this.y1 = l.getY1(); + this.x2 = l.getX2(); + this.y2 = l.getY2(); + this.t = at; + } + + public int getWindingRule() { + return WIND_NON_ZERO; + } + + public boolean isDone() { + return index > 1; + } + + public void next() { + index++; + } + + public int currentSegment(double[] coords) { + if (isDone()) { + // awt.4B=Iterator out of bounds + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + int type; + if (index == 0) { + type = SEG_MOVETO; + coords[0] = x1; + coords[1] = y1; + } else { + type = SEG_LINETO; + coords[0] = x2; + coords[1] = y2; + } + if (t != null) { + t.transform(coords, 0, coords, 0, 1); + } + return type; + } + + public int currentSegment(float[] coords) { + if (isDone()) { + // awt.4B=Iterator out of bounds + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + int type; + if (index == 0) { + type = SEG_MOVETO; + coords[0] = (float)x1; + coords[1] = (float)y1; + } else { + type = SEG_LINETO; + coords[0] = (float)x2; + coords[1] = (float)y2; + } + if (t != null) { + t.transform(coords, 0, coords, 0, 1); + } + return type; + } + + } + + /** + * Instantiates a new Line2D. + */ + protected Line2D() { + } + + /** + * Gets the x coordinate of the starting point. + * + * @return the x coordinate of the starting point. + */ + public abstract double getX1(); + + /** + * Gets the y coordinate of the starting point. + * + * @return the y coordinate of the starting point. + */ + public abstract double getY1(); + + /** + * Gets the x coordinate of the end point. + * + * @return the x2. + */ + public abstract double getX2(); + + /** + * Gets the y coordinate of the end point. + * + * @return the y coordinate of the end point. + */ + public abstract double getY2(); + + /** + * Gets the p the starting point. + * + * @return the p the starting point. + */ + public abstract Point2D getP1(); + + /** + * Gets the p end point. + * + * @return the p end point. + */ + public abstract Point2D getP2(); + + /** + * Sets the line's endpoints. + * + * @param x1 + * the x coordinate of the starting point. + * @param y1 + * the y coordinate of the starting point. + * @param x2 + * the x coordinate of the end point. + * @param y2 + * the y coordinate of the end point. + */ + public abstract void setLine(double x1, double y1, double x2, double y2); + + /** + * Sets the line's endpoints. + * + * @param p1 + * the starting point. + * @param p2 + * the end point. + */ + public void setLine(Point2D p1, Point2D p2) { + setLine(p1.getX(), p1.getY(), p2.getX(), p2.getY()); + } + + /** + * Sets the line's endpoints by copying the data from another Line2D. + * + * @param line + * the Line2D to copy the endpoint data from. + */ + public void setLine(Line2D line) { + setLine(line.getX1(), line.getY1(), line.getX2(), line.getY2()); + } + + public Rectangle getBounds() { + return getBounds2D().getBounds(); + } + + /** + * Tells where the point is with respect to the line segment, given the + * orientation of the line segment. If the ray found by extending the line + * segment from its starting point is rotated, this method tells whether the + * ray should rotate in a clockwise direction or a counter-clockwise + * direction to hit the point first. The return value is 0 if the point is + * on the line segment, it's 1 if the point is on the ray or if the ray + * should rotate in a counter-clockwise direction to get to the point, and + * it's -1 if the ray should rotate in a clockwise direction to get to the + * point or if the point is on the line determined by the line segment but + * not on the ray from the segment's starting point and through its end + * point. + * + * @param x1 + * the x coordinate of the starting point of the line segment. + * @param y1 + * the y coordinate of the starting point of the line segment. + * @param x2 + * the x coordinate of the end point of the line segment. + * @param y2 + * the y coordinate of the end point of the line segment. + * @param px + * the x coordinate of the test point. + * @param py + * the p coordinate of the test point. + * @return the value that describes where the point is with respect to the + * line segment, given the orientation of the line segment. + */ + public static int relativeCCW(double x1, double y1, double x2, double y2, double px, double py) { + /* + * A = (x2-x1, y2-y1) P = (px-x1, py-y1) + */ + x2 -= x1; + y2 -= y1; + px -= x1; + py -= y1; + double t = px * y2 - py * x2; // PxA + if (t == 0.0) { + t = px * x2 + py * y2; // P*A + if (t > 0.0) { + px -= x2; // B-A + py -= y2; + t = px * x2 + py * y2; // (P-A)*A + if (t < 0.0) { + t = 0.0; + } + } + } + + return t < 0.0 ? -1 : (t > 0.0 ? 1 : 0); + } + + /** + * Tells where the point is with respect to this line segment, given the + * orientation of this line segment. If the ray found by extending the line + * segment from its starting point is rotated, this method tells whether the + * ray should rotate in a clockwise direction or a counter-clockwise + * direction to hit the point first. The return value is 0 if the point is + * on the line segment, it's 1 if the point is on the ray or if the ray + * should rotate in a counter-clockwise direction to get to the point, and + * it's -1 if the ray should rotate in a clockwise direction to get to the + * point or if the point is on the line determined by the line segment but + * not on the ray from the segment's starting point and through its end + * point. + * + * @param px + * the x coordinate of the test point. + * @param py + * the p coordinate of the test point. + * @return the value that describes where the point is with respect to this + * line segment, given the orientation of this line segment. + */ + public int relativeCCW(double px, double py) { + return relativeCCW(getX1(), getY1(), getX2(), getY2(), px, py); + } + + /** + * Tells where the point is with respect to this line segment, given the + * orientation of this line segment. If the ray found by extending the line + * segment from its starting point is rotated, this method tells whether the + * ray should rotate in a clockwise direction or a counter-clockwise + * direction to hit the point first. The return value is 0 if the point is + * on the line segment, it's 1 if the point is on the ray or if the ray + * should rotate in a counter-clockwise direction to get to the point, and + * it's -1 if the ray should rotate in a clockwise direction to get to the + * point or if the point is on the line determined by the line segment but + * not on the ray from the segment's starting point and through its end + * point. + * + * @param p + * the test point. + * @return the value that describes where the point is with respect to this + * line segment, given the orientation of this line segment. + */ + public int relativeCCW(Point2D p) { + return relativeCCW(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); + } + + /** + * Tells whether the two line segments cross. + * + * @param x1 + * the x coordinate of the starting point of the first segment. + * @param y1 + * the y coordinate of the starting point of the first segment. + * @param x2 + * the x coordinate of the end point of the first segment. + * @param y2 + * the y coordinate of the end point of the first segment. + * @param x3 + * the x coordinate of the starting point of the second segment. + * @param y3 + * the y coordinate of the starting point of the second segment. + * @param x4 + * the x coordinate of the end point of the second segment. + * @param y4 + * the y coordinate of the end point of the second segment. + * @return true, if the two line segments cross. + */ + public static boolean linesIntersect(double x1, double y1, double x2, double y2, double x3, + double y3, double x4, double y4) { + /* + * A = (x2-x1, y2-y1) B = (x3-x1, y3-y1) C = (x4-x1, y4-y1) D = (x4-x3, + * y4-y3) = C-B E = (x1-x3, y1-y3) = -B F = (x2-x3, y2-y3) = A-B Result + * is ((AxB) (AxC) <=0) and ((DxE) (DxF) <= 0) DxE = (C-B)x(-B) = + * BxB-CxB = BxC DxF = (C-B)x(A-B) = CxA-CxB-BxA+BxB = AxB+BxC-AxC + */ + + x2 -= x1; // A + y2 -= y1; + x3 -= x1; // B + y3 -= y1; + x4 -= x1; // C + y4 -= y1; + + double AvB = x2 * y3 - x3 * y2; + double AvC = x2 * y4 - x4 * y2; + + // Online + if (AvB == 0.0 && AvC == 0.0) { + if (x2 != 0.0) { + return (x4 * x3 <= 0.0) + || ((x3 * x2 >= 0.0) && (x2 > 0.0 ? x3 <= x2 || x4 <= x2 : x3 >= x2 + || x4 >= x2)); + } + if (y2 != 0.0) { + return (y4 * y3 <= 0.0) + || ((y3 * y2 >= 0.0) && (y2 > 0.0 ? y3 <= y2 || y4 <= y2 : y3 >= y2 + || y4 >= y2)); + } + return false; + } + + double BvC = x3 * y4 - x4 * y3; + + return (AvB * AvC <= 0.0) && (BvC * (AvB + BvC - AvC) <= 0.0); + } + + /** + * Tells whether the specified line segments crosses this line segment. + * + * @param x1 + * the x coordinate of the starting point of the test segment. + * @param y1 + * the y coordinate of the starting point of the test segment. + * @param x2 + * the x coordinate of the end point of the test segment. + * @param y2 + * the y coordinate of the end point of the test segment. + * @return true, if the specified line segments crosses this line segment. + */ + public boolean intersectsLine(double x1, double y1, double x2, double y2) { + return linesIntersect(x1, y1, x2, y2, getX1(), getY1(), getX2(), getY2()); + } + + /** + * Tells whether the specified line segments crosses this line segment. + * + * @param l + * the test segment. + * @return true, if the specified line segments crosses this line segment. + * @throws NullPointerException + * if l is null. + */ + public boolean intersectsLine(Line2D l) { + return linesIntersect(l.getX1(), l.getY1(), l.getX2(), l.getY2(), getX1(), getY1(), + getX2(), getY2()); + } + + /** + * Gives the square of the distance between the point and the line segment. + * + * @param x1 + * the x coordinate of the starting point of the line segment. + * @param y1 + * the y coordinate of the starting point of the line segment. + * @param x2 + * the x coordinate of the end point of the line segment. + * @param y2 + * the y coordinate of the end point of the line segment. + * @param px + * the x coordinate of the test point. + * @param py + * the y coordinate of the test point. + * @return the the square of the distance between the point and the line + * segment. + */ + public static double ptSegDistSq(double x1, double y1, double x2, double y2, double px, + double py) { + /* + * A = (x2 - x1, y2 - y1) P = (px - x1, py - y1) + */ + x2 -= x1; // A = (x2, y2) + y2 -= y1; + px -= x1; // P = (px, py) + py -= y1; + double dist; + if (px * x2 + py * y2 <= 0.0) { // P*A + dist = px * px + py * py; + } else { + px = x2 - px; // P = A - P = (x2 - px, y2 - py) + py = y2 - py; + if (px * x2 + py * y2 <= 0.0) { // P*A + dist = px * px + py * py; + } else { + dist = px * y2 - py * x2; + dist = dist * dist / (x2 * x2 + y2 * y2); // pxA/|A| + } + } + if (dist < 0) { + dist = 0; + } + return dist; + } + + /** + * Gives the distance between the point and the line segment. + * + * @param x1 + * the x coordinate of the starting point of the line segment. + * @param y1 + * the y coordinate of the starting point of the line segment. + * @param x2 + * the x coordinate of the end point of the line segment. + * @param y2 + * the y coordinate of the end point of the line segment. + * @param px + * the x coordinate of the test point. + * @param py + * the y coordinate of the test point. + * @return the the distance between the point and the line segment. + */ + public static double ptSegDist(double x1, double y1, double x2, double y2, double px, double py) { + return Math.sqrt(ptSegDistSq(x1, y1, x2, y2, px, py)); + } + + /** + * Gives the square of the distance between the point and this line segment. + * + * @param px + * the x coordinate of the test point. + * @param py + * the y coordinate of the test point. + * @return the the square of the distance between the point and this line + * segment. + */ + public double ptSegDistSq(double px, double py) { + return ptSegDistSq(getX1(), getY1(), getX2(), getY2(), px, py); + } + + /** + * Gives the square of the distance between the point and this line segment. + * + * @param p + * the test point. + * @return the square of the distance between the point and this line + * segment. + */ + public double ptSegDistSq(Point2D p) { + return ptSegDistSq(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); + } + + /** + * Gives the distance between the point and this line segment. + * + * @param px + * the x coordinate of the test point. + * @param py + * the y coordinate of the test point. + * @return the distance between the point and this line segment. + */ + public double ptSegDist(double px, double py) { + return ptSegDist(getX1(), getY1(), getX2(), getY2(), px, py); + } + + /** + * Gives the distance between the point and this line segment. + * + * @param p + * the test point. + * @return the distance between the point and this line segment. + */ + public double ptSegDist(Point2D p) { + return ptSegDist(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); + } + + /** + * Gives the square of the distance between the point and the line. + * + * @param x1 + * the x coordinate of the starting point of the line segment. + * @param y1 + * the y coordinate of the starting point of the line segment. + * @param x2 + * the x coordinate of the end point of the line segment. + * @param y2 + * the y coordinate of the end point of the line segment. + * @param px + * the x coordinate of the test point. + * @param py + * the y coordinate of the test point. + * @return the square of the distance between the point and the line. + */ + public static double ptLineDistSq(double x1, double y1, double x2, double y2, double px, + double py) { + x2 -= x1; + y2 -= y1; + px -= x1; + py -= y1; + double s = px * y2 - py * x2; + return s * s / (x2 * x2 + y2 * y2); + } + + /** + * Gives the square of the distance between the point and the line. + * + * @param x1 + * the x coordinate of the starting point of the line segment. + * @param y1 + * the y coordinate of the starting point of the line segment. + * @param x2 + * the x coordinate of the end point of the line segment. + * @param y2 + * the y coordinate of the end point of the line segment. + * @param px + * the x coordinate of the test point. + * @param py + * the y coordinate of the test point. + * @return the square of the distance between the point and the line. + */ + public static double ptLineDist(double x1, double y1, double x2, double y2, double px, double py) { + return Math.sqrt(ptLineDistSq(x1, y1, x2, y2, px, py)); + } + + /** + * Gives the square of the distance between the point and the line + * determined by this Line2D. + * + * @param px + * the x coordinate of the test point. + * @param py + * the y coordinate of the test point. + * @return the square of the distance between the point and the line + * determined by this Line2D. + */ + public double ptLineDistSq(double px, double py) { + return ptLineDistSq(getX1(), getY1(), getX2(), getY2(), px, py); + } + + /** + * Gives the square of the distance between the point and the line + * determined by this Line2D. + * + * @param p + * the test point. + * @return the square of the distance between the point and the line + * determined by this Line2D. + */ + public double ptLineDistSq(Point2D p) { + return ptLineDistSq(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); + } + + /** + * Gives the distance between the point and the line determined by this + * Line2D. + * + * @param px + * the x coordinate of the test point. + * @param py + * the y coordinate of the test point. + * @return the distance between the point and the line determined by this + * Line2D. + */ + public double ptLineDist(double px, double py) { + return ptLineDist(getX1(), getY1(), getX2(), getY2(), px, py); + } + + /** + * Gives the distance between the point and the line determined by this + * Line2D. + * + * @param p + * the test point. + * @return the distance between the point and the line determined by this + * Line2D. + */ + public double ptLineDist(Point2D p) { + return ptLineDist(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); + } + + public boolean contains(double px, double py) { + return false; + } + + public boolean contains(Point2D p) { + return false; + } + + public boolean contains(Rectangle2D r) { + return false; + } + + public boolean contains(double rx, double ry, double rw, double rh) { + return false; + } + + public boolean intersects(double rx, double ry, double rw, double rh) { + return intersects(new Rectangle2D.Double(rx, ry, rw, rh)); + } + + public boolean intersects(Rectangle2D r) { + return r.intersectsLine(getX1(), getY1(), getX2(), getY2()); + } + + public PathIterator getPathIterator(AffineTransform at) { + return new Iterator(this, at); + } + + public PathIterator getPathIterator(AffineTransform at, double flatness) { + return new Iterator(this, at); + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + } + +} diff --git a/awt/java/awt/geom/NoninvertibleTransformException.java b/awt/java/awt/geom/NoninvertibleTransformException.java new file mode 100644 index 0000000..a4e6f0f --- /dev/null +++ b/awt/java/awt/geom/NoninvertibleTransformException.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt.geom; + +/** + * The Class NoninvertibleTransformException is the exception that is thrown + * when an action requires inverting an {@link AffineTransform} that is not + * invertible (has determinant 0). + * + * @since Android 1.0 + */ +public class NoninvertibleTransformException extends java.lang.Exception { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 6137225240503990466L; + + /** + * Instantiates a new non-invertible transform exception. + * + * @param s + * the error message. + */ + public NoninvertibleTransformException(String s) { + super(s); + } + +} diff --git a/awt/java/awt/geom/PathIterator.java b/awt/java/awt/geom/PathIterator.java new file mode 100644 index 0000000..2d1c0ff --- /dev/null +++ b/awt/java/awt/geom/PathIterator.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt.geom; + +/** + * The Interface PathIterator represents an iterator object that can be used to + * traverse the outline of a {@link java.awt.Shape}. It returns points along the + * boundary of the Shape which may be actual vertices (in the case of a shape + * made of line segments) or may be points on a curved segment with the distance + * between the points determined by a chosen flattening factor. + * <p> + * If the shape is closed, the outline is traversed in the counter-clockwise + * direction. That means that moving forward along the boundary is to travel in + * such a way that the interior of the shape is to the left of the outline path + * and the exterior of the shape is to the right of the outline path. The + * interior and exterior of the shape are determined by a winding rule. + * </p> + * + * @since Android 1.0 + */ +public interface PathIterator { + + /** + * The Constant WIND_EVEN_ODD indicates the winding rule that says that a + * point is outside the shape if any infinite ray from the point crosses the + * outline of the shape an even number of times, otherwise it is inside. + */ + public static final int WIND_EVEN_ODD = 0; + + /** + * The Constant WIND_NON_ZERO indicates the winding rule that says that a + * point is inside the shape if every infinite ray starting from that point + * crosses the outline of the shape a non-zero number of times. + */ + public static final int WIND_NON_ZERO = 1; + + /** + * The Constant SEG_MOVETO indicates that to follow the shape's outline from + * the previous point to the current point, the cursor (traversal point) + * should be placed directly on the current point. + */ + public static final int SEG_MOVETO = 0; + + /** + * The Constant SEG_LINETO indicates that to follow the shape's outline from + * the previous point to the current point, the cursor (traversal point) + * should follow a straight line. + */ + public static final int SEG_LINETO = 1; + + /** + * The Constant SEG_QUADTO indicates that to follow the shape's outline from + * the previous point to the current point, the cursor (traversal point) + * should follow a quadratic curve. + */ + public static final int SEG_QUADTO = 2; + + /** + * The Constant SEG_CUBICTO indicates that to follow the shape's outline + * from the previous point to the current point, the cursor (traversal + * point) should follow a cubic curve. + */ + public static final int SEG_CUBICTO = 3; + + /** + * The Constant SEG_CLOSE indicates that the previous point was the end of + * the shape's outline. + */ + public static final int SEG_CLOSE = 4; + + /** + * Gets the winding rule, either {@link PathIterator#WIND_EVEN_ODD} or + * {@link PathIterator#WIND_NON_ZERO}. + * + * @return the winding rule. + */ + public int getWindingRule(); + + /** + * Checks if this PathIterator has been completely traversed. + * + * @return true, if this PathIterator has been completely traversed. + */ + public boolean isDone(); + + /** + * Tells this PathIterator to skip to the next segment. + */ + public void next(); + + /** + * Gets the coordinates of the next vertex point along the shape's outline + * and a flag that indicates what kind of segment to use in order to connect + * the previous vertex point to the current vertex point to form the current + * segment. + * + * @param coords + * the array that the coordinates of the end point of the current + * segment are written into. + * @return the flag that indicates how to follow the shape's outline from + * the previous point to the current one, chosen from the following + * constants: {@link PathIterator#SEG_MOVETO}, + * {@link PathIterator#SEG_LINETO}, {@link PathIterator#SEG_QUADTO}, + * {@link PathIterator#SEG_CUBICTO}, or + * {@link PathIterator#SEG_CLOSE}. + */ + public int currentSegment(float[] coords); + + /** + * Gets the coordinates of the next vertex point along the shape's outline + * and a flag that indicates what kind of segment to use in order to connect + * the previous vertex point to the current vertex point to form the current + * segment. + * + * @param coords + * the array that the coordinates of the end point of the current + * segment are written into. + * @return the flag that indicates how to follow the shape's outline from + * the previous point to the current one, chosen from the following + * constants: {@link PathIterator#SEG_MOVETO}, + * {@link PathIterator#SEG_LINETO}, {@link PathIterator#SEG_QUADTO}, + * {@link PathIterator#SEG_CUBICTO}, or + * {@link PathIterator#SEG_CLOSE}. + */ + public int currentSegment(double[] coords); + +} diff --git a/awt/java/awt/geom/Point2D.java b/awt/java/awt/geom/Point2D.java new file mode 100644 index 0000000..f7026c8 --- /dev/null +++ b/awt/java/awt/geom/Point2D.java @@ -0,0 +1,323 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt.geom; + +import org.apache.harmony.misc.HashCode; + +/** + * The Class Point2D represents a point whose data is given in high-precision + * values appropriate for graphical operations. + * + * @since Android 1.0 + */ +public abstract class Point2D implements Cloneable { + + /** + * The Class Float is the subclass of Point2D that has all of its data + * values stored with float-level precision. + * + * @since Android 1.0 + */ + public static class Float extends Point2D { + + /** + * The x coordinate. + */ + public float x; + + /** + * The y coordinate. + */ + public float y; + + /** + * Instantiates a new float-valued Point2D with its data set to zero. + */ + public Float() { + } + + /** + * Instantiates a new float-valued Point2D with the specified + * coordinates. + * + * @param x + * the x coordinate. + * @param y + * the y coordinate. + */ + public Float(float x, float y) { + this.x = x; + this.y = y; + } + + @Override + public double getX() { + return x; + } + + @Override + public double getY() { + return y; + } + + /** + * Sets the point's coordinates. + * + * @param x + * the x coordinate. + * @param y + * the y coordinate. + */ + public void setLocation(float x, float y) { + this.x = x; + this.y = y; + } + + @Override + public void setLocation(double x, double y) { + this.x = (float)x; + this.y = (float)y; + } + + @Override + public String toString() { + return getClass().getName() + "[x=" + x + ",y=" + y + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + } + + /** + * The Class Double is the subclass of Point2D that has all of its data + * values stored with double-level precision. + * + * @since Android 1.0 + */ + public static class Double extends Point2D { + + /** + * The x coordinate. + */ + public double x; + + /** + * The y coordinate. + */ + public double y; + + /** + * Instantiates a new double-valued Point2D with its data set to zero. + */ + public Double() { + } + + /** + * Instantiates a new double-valued Point2D with the specified + * coordinates. + * + * @param x + * the x coordinate. + * @param y + * the y coordinate. + */ + public Double(double x, double y) { + this.x = x; + this.y = y; + } + + @Override + public double getX() { + return x; + } + + @Override + public double getY() { + return y; + } + + @Override + public void setLocation(double x, double y) { + this.x = x; + this.y = y; + } + + @Override + public String toString() { + return getClass().getName() + "[x=" + x + ",y=" + y + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + } + + /** + * Instantiates a new Point2D. + */ + protected Point2D() { + } + + /** + * Gets the x coordinate. + * + * @return the x coordinate. + */ + public abstract double getX(); + + /** + * Gets the y coordinate. + * + * @return the y coordinate. + */ + public abstract double getY(); + + /** + * Sets the point's coordinates. + * + * @param x + * the x coordinate. + * @param y + * the y coordinate. + */ + public abstract void setLocation(double x, double y); + + /** + * Sets the point's coordinates by copying them from another point. + * + * @param p + * the point to copy the data from. + */ + public void setLocation(Point2D p) { + setLocation(p.getX(), p.getY()); + } + + /** + * Finds the square of the distance between the two specified points. + * + * @param x1 + * the x coordinate of the first point. + * @param y1 + * the y coordinate of the first point. + * @param x2 + * the x coordinate of the second point. + * @param y2 + * the y coordinate of the second point. + * @return the square of the distance between the two specified points. + */ + public static double distanceSq(double x1, double y1, double x2, double y2) { + x2 -= x1; + y2 -= y1; + return x2 * x2 + y2 * y2; + } + + /** + * Finds the square of the distance between this point and the specified + * point. + * + * @param px + * the x coordinate of the point. + * @param py + * the y coordinate of the point. + * @return the square of the distance between this point and the specified + * point. + */ + public double distanceSq(double px, double py) { + return Point2D.distanceSq(getX(), getY(), px, py); + } + + /** + * Finds the square of the distance between this point and the specified + * point. + * + * @param p + * the other point. + * @return the square of the distance between this point and the specified + * point. + */ + public double distanceSq(Point2D p) { + return Point2D.distanceSq(getX(), getY(), p.getX(), p.getY()); + } + + /** + * Finds the distance between the two specified points. + * + * @param x1 + * the x coordinate of the first point. + * @param y1 + * the y coordinate of the first point. + * @param x2 + * the x coordinate of the second point. + * @param y2 + * the y coordinate of the second point. + * @return the distance between the two specified points. + */ + public static double distance(double x1, double y1, double x2, double y2) { + return Math.sqrt(distanceSq(x1, y1, x2, y2)); + } + + /** + * Finds the distance between this point and the specified point. + * + * @param px + * the x coordinate of the point. + * @param py + * the y coordinate of the point. + * @return the distance between this point and the specified point. + */ + public double distance(double px, double py) { + return Math.sqrt(distanceSq(px, py)); + } + + /** + * Finds the distance between this point and the specified point. + * + * @param p + * the other point. + * @return the distance between this point and the specified point. + */ + public double distance(Point2D p) { + return Math.sqrt(distanceSq(p)); + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + } + + @Override + public int hashCode() { + HashCode hash = new HashCode(); + hash.append(getX()); + hash.append(getY()); + return hash.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Point2D) { + Point2D p = (Point2D)obj; + return getX() == p.getX() && getY() == p.getY(); + } + return false; + } +} diff --git a/awt/java/awt/geom/QuadCurve2D.java b/awt/java/awt/geom/QuadCurve2D.java new file mode 100644 index 0000000..7a86a48 --- /dev/null +++ b/awt/java/awt/geom/QuadCurve2D.java @@ -0,0 +1,918 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt.geom; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.util.NoSuchElementException; + +import org.apache.harmony.awt.gl.Crossing; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class QuadCurve2D is a Shape that represents a segment of a quadratic + * (Bezier) curve. The curved segment is determined by three points: a start + * point, an end point, and a control point. The line from the control point to + * the starting point gives the tangent to the curve at the starting point, and + * the line from the control point to the end point gives the tangent to the + * curve at the end point. + * + * @since Android 1.0 + */ +public abstract class QuadCurve2D implements Shape, Cloneable { + + /** + * The Class Float is the subclass of QuadCurve2D that has all of its data + * values stored with float-level precision. + * + * @since Android 1.0 + */ + public static class Float extends QuadCurve2D { + + /** + * The x coordinate of the starting point of the curved segment. + */ + public float x1; + + /** + * The y coordinate of the starting point of the curved segment. + */ + public float y1; + + /** + * The x coordinate of the control point. + */ + public float ctrlx; + + /** + * The y coordinate of the control point. + */ + public float ctrly; + + /** + * The x coordinate of the end point of the curved segment. + */ + public float x2; + + /** + * The y coordinate of the end point of the curved segment. + */ + public float y2; + + /** + * Instantiates a new float-valued QuadCurve2D with all coordinate + * values set to zero. + */ + public Float() { + } + + /** + * Instantiates a new float-valued QuadCurve2D with the specified + * coordinate values. + * + * @param x1 + * the x coordinate of the starting point of the curved + * segment. + * @param y1 + * the y coordinate of the starting point of the curved + * segment. + * @param ctrlx + * the x coordinate of the control point. + * @param ctrly + * the y coordinate of the control point. + * @param x2 + * the x coordinate of the end point of the curved segment. + * @param y2 + * the y coordinate of the end point of the curved segment. + */ + public Float(float x1, float y1, float ctrlx, float ctrly, float x2, float y2) { + setCurve(x1, y1, ctrlx, ctrly, x2, y2); + } + + @Override + public double getX1() { + return x1; + } + + @Override + public double getY1() { + return y1; + } + + @Override + public double getCtrlX() { + return ctrlx; + } + + @Override + public double getCtrlY() { + return ctrly; + } + + @Override + public double getX2() { + return x2; + } + + @Override + public double getY2() { + return y2; + } + + @Override + public Point2D getP1() { + return new Point2D.Float(x1, y1); + } + + @Override + public Point2D getCtrlPt() { + return new Point2D.Float(ctrlx, ctrly); + } + + @Override + public Point2D getP2() { + return new Point2D.Float(x2, y2); + } + + @Override + public void setCurve(double x1, double y1, double ctrlx, double ctrly, double x2, double y2) { + this.x1 = (float)x1; + this.y1 = (float)y1; + this.ctrlx = (float)ctrlx; + this.ctrly = (float)ctrly; + this.x2 = (float)x2; + this.y2 = (float)y2; + } + + /** + * Sets the data values of the curve. + * + * @param x1 + * the x coordinate of the starting point of the curved + * segment. + * @param y1 + * the y coordinate of the starting point of the curved + * segment. + * @param ctrlx + * the x coordinate of the control point. + * @param ctrly + * the y coordinate of the control point. + * @param x2 + * the x coordinate of the end point of the curved segment. + * @param y2 + * the y coordinate of the end point of the curved segment. + */ + public void setCurve(float x1, float y1, float ctrlx, float ctrly, float x2, float y2) { + this.x1 = x1; + this.y1 = y1; + this.ctrlx = ctrlx; + this.ctrly = ctrly; + this.x2 = x2; + this.y2 = y2; + } + + public Rectangle2D getBounds2D() { + float rx0 = Math.min(Math.min(x1, x2), ctrlx); + float ry0 = Math.min(Math.min(y1, y2), ctrly); + float rx1 = Math.max(Math.max(x1, x2), ctrlx); + float ry1 = Math.max(Math.max(y1, y2), ctrly); + return new Rectangle2D.Float(rx0, ry0, rx1 - rx0, ry1 - ry0); + } + } + + /** + * The Class Double is the subclass of QuadCurve2D that has all of its data + * values stored with double-level precision. + * + * @since Android 1.0 + */ + public static class Double extends QuadCurve2D { + + /** + * The x coordinate of the starting point of the curved segment. + */ + public double x1; + + /** + * The y coordinate of the starting point of the curved segment. + */ + public double y1; + + /** + * The x coordinate of the control point. + */ + public double ctrlx; + + /** + * The y coordinate of the control point. + */ + public double ctrly; + + /** + * The x coordinate of the end point of the curved segment. + */ + public double x2; + + /** + * The y coordinate of the end point of the curved segment. + */ + public double y2; + + /** + * Instantiates a new double-valued QuadCurve2D with all coordinate + * values set to zero. + */ + public Double() { + } + + /** + * Instantiates a new double-valued QuadCurve2D with the specified + * coordinate values. + * + * @param x1 + * the x coordinate of the starting point of the curved + * segment. + * @param y1 + * the y coordinate of the starting point of the curved + * segment. + * @param ctrlx + * the x coordinate of the control point. + * @param ctrly + * the y coordinate of the control point. + * @param x2 + * the x coordinate of the end point of the curved segment. + * @param y2 + * the y coordinate of the end point of the curved segment. + */ + public Double(double x1, double y1, double ctrlx, double ctrly, double x2, double y2) { + setCurve(x1, y1, ctrlx, ctrly, x2, y2); + } + + @Override + public double getX1() { + return x1; + } + + @Override + public double getY1() { + return y1; + } + + @Override + public double getCtrlX() { + return ctrlx; + } + + @Override + public double getCtrlY() { + return ctrly; + } + + @Override + public double getX2() { + return x2; + } + + @Override + public double getY2() { + return y2; + } + + @Override + public Point2D getP1() { + return new Point2D.Double(x1, y1); + } + + @Override + public Point2D getCtrlPt() { + return new Point2D.Double(ctrlx, ctrly); + } + + @Override + public Point2D getP2() { + return new Point2D.Double(x2, y2); + } + + @Override + public void setCurve(double x1, double y1, double ctrlx, double ctrly, double x2, double y2) { + this.x1 = x1; + this.y1 = y1; + this.ctrlx = ctrlx; + this.ctrly = ctrly; + this.x2 = x2; + this.y2 = y2; + } + + public Rectangle2D getBounds2D() { + double rx0 = Math.min(Math.min(x1, x2), ctrlx); + double ry0 = Math.min(Math.min(y1, y2), ctrly); + double rx1 = Math.max(Math.max(x1, x2), ctrlx); + double ry1 = Math.max(Math.max(y1, y2), ctrly); + return new Rectangle2D.Double(rx0, ry0, rx1 - rx0, ry1 - ry0); + } + } + + /* + * QuadCurve2D path iterator + */ + /** + * The PathIterator for a Quad2D curve. + */ + class Iterator implements PathIterator { + + /** + * The source QuadCurve2D object. + */ + QuadCurve2D c; + + /** + * The path iterator transformation. + */ + AffineTransform t; + + /** + * The current segment index. + */ + int index; + + /** + * Constructs a new QuadCurve2D.Iterator for given curve and + * transformation + * + * @param q + * the source QuadCurve2D object. + * @param t + * the AffineTransform that acts on the coordinates before + * returning them (or null). + */ + Iterator(QuadCurve2D q, AffineTransform t) { + this.c = q; + this.t = t; + } + + public int getWindingRule() { + return WIND_NON_ZERO; + } + + public boolean isDone() { + return (index > 1); + } + + public void next() { + index++; + } + + public int currentSegment(double[] coords) { + if (isDone()) { + // awt.4B=Iterator out of bounds + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + int type; + int count; + if (index == 0) { + type = SEG_MOVETO; + coords[0] = c.getX1(); + coords[1] = c.getY1(); + count = 1; + } else { + type = SEG_QUADTO; + coords[0] = c.getCtrlX(); + coords[1] = c.getCtrlY(); + coords[2] = c.getX2(); + coords[3] = c.getY2(); + count = 2; + } + if (t != null) { + t.transform(coords, 0, coords, 0, count); + } + return type; + } + + public int currentSegment(float[] coords) { + if (isDone()) { + // awt.4B=Iterator out of bounds + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + int type; + int count; + if (index == 0) { + type = SEG_MOVETO; + coords[0] = (float)c.getX1(); + coords[1] = (float)c.getY1(); + count = 1; + } else { + type = SEG_QUADTO; + coords[0] = (float)c.getCtrlX(); + coords[1] = (float)c.getCtrlY(); + coords[2] = (float)c.getX2(); + coords[3] = (float)c.getY2(); + count = 2; + } + if (t != null) { + t.transform(coords, 0, coords, 0, count); + } + return type; + } + + } + + /** + * Instantiates a new quadratic curve. + */ + protected QuadCurve2D() { + } + + /** + * Gets the x coordinate of the starting point. + * + * @return the x coordinate of the starting point. + */ + public abstract double getX1(); + + /** + * Gets the y coordinate of the starting point. + * + * @return the y coordinate of the starting point. + */ + public abstract double getY1(); + + /** + * Gets the starting point. + * + * @return the starting point. + */ + public abstract Point2D getP1(); + + /** + * Gets the x coordinate of the control point. + * + * @return the x coordinate of the control point. + */ + public abstract double getCtrlX(); + + /** + * Gets the y coordinate of the control point. + * + * @return y coordinate of the control point. + */ + public abstract double getCtrlY(); + + /** + * Gets the control point. + * + * @return the control point. + */ + public abstract Point2D getCtrlPt(); + + /** + * Gets the x coordinate of the end point. + * + * @return the x coordinate of the end point. + */ + public abstract double getX2(); + + /** + * Gets the y coordinate of the end point. + * + * @return the y coordinate of the end point. + */ + public abstract double getY2(); + + /** + * Gets the end point. + * + * @return the end point. + */ + public abstract Point2D getP2(); + + /** + * Sets the data of the curve. + * + * @param x1 + * the x coordinate of the starting point of the curved segment. + * @param y1 + * the y coordinate of the starting point of the curved segment. + * @param ctrlx + * the x coordinate of the control point. + * @param ctrly + * the y coordinate of the control point. + * @param x2 + * the x coordinate of the end point of the curved segment. + * @param y2 + * the y coordinate of the end point of the curved segment. + */ + public abstract void setCurve(double x1, double y1, double ctrlx, double ctrly, double x2, + double y2); + + /** + * Sets the data of the curve. + * + * @param p1 + * the starting point of the curved segment. + * @param cp + * the control point. + * @param p2 + * the end point of the curved segment. + * @throws NullPointerException + * if any of the three points is null. + */ + public void setCurve(Point2D p1, Point2D cp, Point2D p2) { + setCurve(p1.getX(), p1.getY(), cp.getX(), cp.getY(), p2.getX(), p2.getY()); + } + + /** + * Sets the data of the curve by reading the data from an array of values. + * The values are read in the same order as the arguments of the method + * {@link QuadCurve2D#setCurve(double, double, double, double, double, double)} + * . + * + * @param coords + * the array of values containing the new coordinates. + * @param offset + * the offset of the data to read within the array. + * @throws ArrayIndexOutOfBoundsException + * if {@code coords.length} < offset + 6. + * @throws NullPointerException + * if the coordinate array is null. + */ + public void setCurve(double[] coords, int offset) { + setCurve(coords[offset + 0], coords[offset + 1], coords[offset + 2], coords[offset + 3], + coords[offset + 4], coords[offset + 5]); + } + + /** + * Sets the data of the curve by reading the data from an array of points. + * The values are read in the same order as the arguments of the method + * {@link QuadCurve2D#setCurve(Point2D, Point2D, Point2D)}. + * + * @param points + * the array of points containing the new coordinates. + * @param offset + * the offset of the data to read within the array. + * @throws ArrayIndexOutOfBoundsException + * if points.length < offset + 3. + * @throws NullPointerException + * if the point array is null. + */ + public void setCurve(Point2D[] points, int offset) { + setCurve(points[offset + 0].getX(), points[offset + 0].getY(), points[offset + 1].getX(), + points[offset + 1].getY(), points[offset + 2].getX(), points[offset + 2].getY()); + } + + /** + * Sets the data of the curve by copying it from another QuadCurve2D. + * + * @param curve + * the curve to copy the data points from. + * @throws NullPointerException + * if the curve is null. + */ + public void setCurve(QuadCurve2D curve) { + setCurve(curve.getX1(), curve.getY1(), curve.getCtrlX(), curve.getCtrlY(), curve.getX2(), + curve.getY2()); + } + + /** + * Gets the square of the distance from the control point to the straight + * line segment connecting the start point and the end point for this curve. + * + * @return the square of the distance from the control point to the straight + * line segment connecting the start point and the end point. + */ + public double getFlatnessSq() { + return Line2D.ptSegDistSq(getX1(), getY1(), getX2(), getY2(), getCtrlX(), getCtrlY()); + } + + /** + * Gets the square of the distance from the control point to the straight + * line segment connecting the start point and the end point. + * + * @param x1 + * the x coordinate of the starting point of the curved segment. + * @param y1 + * the y coordinate of the starting point of the curved segment. + * @param ctrlx + * the x coordinate of the control point. + * @param ctrly + * the y coordinate of the control point. + * @param x2 + * the x coordinate of the end point of the curved segment. + * @param y2 + * the y coordinate of the end point of the curved segment. + * @return the square of the distance from the control point to the straight + * line segment connecting the start point and the end point. + */ + public static double getFlatnessSq(double x1, double y1, double ctrlx, double ctrly, double x2, + double y2) { + return Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx, ctrly); + } + + /** + * Gets the square of the distance from the control point to the straight + * line segment connecting the start point and the end point by reading the + * coordinates of the points from an array of values. The values are read in + * the same order as the arguments of the method + * {@link QuadCurve2D#getFlatnessSq(double, double, double, double, double, double)} + * . + * + * @param coords + * the array of points containing the coordinates to use for the + * calculation + * @param offset + * the offset of the data to read within the array + * @return the square of the distance from the control point to the straight + * line segment connecting the start point and the end point. + * @throws ArrayIndexOutOfBoundsException + * if {@code coords.length} < offset + 6. + * @throws NullPointerException + * if the coordinate array is null. + */ + public static double getFlatnessSq(double coords[], int offset) { + return Line2D.ptSegDistSq(coords[offset + 0], coords[offset + 1], coords[offset + 4], + coords[offset + 5], coords[offset + 2], coords[offset + 3]); + } + + /** + * Gets the distance from the control point to the straight line segment + * connecting the start point and the end point of this QuadCurve2D. + * + * @return the the distance from the control point to the straight line + * segment connecting the start point and the end point of this + * QuadCurve2D. + */ + public double getFlatness() { + return Line2D.ptSegDist(getX1(), getY1(), getX2(), getY2(), getCtrlX(), getCtrlY()); + } + + /** + * Gets the distance from the control point to the straight line segment + * connecting the start point and the end point. + * + * @param x1 + * the x coordinate of the starting point of the curved segment. + * @param y1 + * the y coordinate of the starting point of the curved segment. + * @param ctrlx + * the x coordinate of the control point. + * @param ctrly + * the y coordinate of the control point. + * @param x2 + * the x coordinate of the end point of the curved segment. + * @param y2 + * the y coordinate of the end point of the curved segment. + * @return the the distance from the control point to the straight line + * segment connecting the start point and the end point. + */ + public static double getFlatness(double x1, double y1, double ctrlx, double ctrly, double x2, + double y2) { + return Line2D.ptSegDist(x1, y1, x2, y2, ctrlx, ctrly); + } + + /** + * Gets the the distance from the control point to the straight line segment + * connecting the start point and the end point. The values are read in the + * same order as the arguments of the method + * {@link QuadCurve2D#getFlatness(double, double, double, double, double, double)} + * . + * + * @param coords + * the array of points containing the coordinates to use for the + * calculation. + * @param offset + * the offset of the data to read within the array. + * @return the the distance from the control point to the straight line + * segment connecting the start point and the end point. + * @throws ArrayIndexOutOfBoundsException + * if {code coords.length} < offset + 6. + * @throws NullPointerException + * if the coordinate array is null. + */ + public static double getFlatness(double coords[], int offset) { + return Line2D.ptSegDist(coords[offset + 0], coords[offset + 1], coords[offset + 4], + coords[offset + 5], coords[offset + 2], coords[offset + 3]); + } + + /** + * Creates the data for two quadratic curves by dividing this curve in two. + * The division point is the point on the curve that is closest to this + * curve's control point. The data of this curve is left unchanged. + * + * @param left + * the QuadCurve2D where the left (start) segment's data is + * written. + * @param right + * the QuadCurve2D where the right (end) segment's data is + * written. + * @throws NullPointerException + * if either curve is null. + */ + public void subdivide(QuadCurve2D left, QuadCurve2D right) { + subdivide(this, left, right); + } + + /** + * Creates the data for two quadratic curves by dividing a source curve in + * two. The division point is the point on the curve that is closest to the + * source curve's control point. The data of the source curve is left + * unchanged. + * + * @param src + * the curve that provides the initial data. + * @param left + * the QuadCurve2D where the left (start) segment's data is + * written. + * @param right + * the QuadCurve2D where the right (end) segment's data is + * written. + * @throws NullPointerException + * if one of the curves is null. + */ + public static void subdivide(QuadCurve2D src, QuadCurve2D left, QuadCurve2D right) { + double x1 = src.getX1(); + double y1 = src.getY1(); + double cx = src.getCtrlX(); + double cy = src.getCtrlY(); + double x2 = src.getX2(); + double y2 = src.getY2(); + double cx1 = (x1 + cx) / 2.0; + double cy1 = (y1 + cy) / 2.0; + double cx2 = (x2 + cx) / 2.0; + double cy2 = (y2 + cy) / 2.0; + cx = (cx1 + cx2) / 2.0; + cy = (cy1 + cy2) / 2.0; + if (left != null) { + left.setCurve(x1, y1, cx1, cy1, cx, cy); + } + if (right != null) { + right.setCurve(cx, cy, cx2, cy2, x2, y2); + } + } + + /** + * Creates the data for two quadratic curves by dividing a source curve in + * two. The division point is the point on the curve that is closest to the + * source curve's control point. The data for the three curves is read and + * written from arrays of values in the usual order: x1, y1, cx, cy, x2, y2. + * + * @param src + * the array that gives the data values for the source curve. + * @param srcoff + * the offset in the src array to read the values from. + * @param left + * the array where the coordinates of the start curve should be + * written. + * @param leftOff + * the offset in the left array to start writing the values. + * @param right + * the array where the coordinates of the end curve should be + * written. + * @param rightOff + * the offset in the right array to start writing the values. + * @throws ArrayIndexOutOfBoundsException + * if {@code src.length} < srcoff + 6 or if {@code left.length} + * < leftOff + 6 or if {@code right.length} < rightOff + 6. + * @throws NullPointerException + * if one of the arrays is null. + */ + public static void subdivide(double src[], int srcoff, double left[], int leftOff, + double right[], int rightOff) { + double x1 = src[srcoff + 0]; + double y1 = src[srcoff + 1]; + double cx = src[srcoff + 2]; + double cy = src[srcoff + 3]; + double x2 = src[srcoff + 4]; + double y2 = src[srcoff + 5]; + double cx1 = (x1 + cx) / 2.0; + double cy1 = (y1 + cy) / 2.0; + double cx2 = (x2 + cx) / 2.0; + double cy2 = (y2 + cy) / 2.0; + cx = (cx1 + cx2) / 2.0; + cy = (cy1 + cy2) / 2.0; + if (left != null) { + left[leftOff + 0] = x1; + left[leftOff + 1] = y1; + left[leftOff + 2] = cx1; + left[leftOff + 3] = cy1; + left[leftOff + 4] = cx; + left[leftOff + 5] = cy; + } + if (right != null) { + right[rightOff + 0] = cx; + right[rightOff + 1] = cy; + right[rightOff + 2] = cx2; + right[rightOff + 3] = cy2; + right[rightOff + 4] = x2; + right[rightOff + 5] = y2; + } + } + + /** + * Finds the roots of the quadratic polynomial. This is accomplished by + * finding the (real) values of x that solve the following equation: + * eqn[2]*x*x + eqn[1]*x + eqn[0] = 0. The solutions are written back into + * the array eqn starting from the index 0 in the array. The return value + * tells how many array elements have been changed by this method call. + * + * @param eqn + * an array containing the coefficients of the quadratic + * polynomial to solve. + * @return the number of roots of the quadratic polynomial. + * @throws ArrayIndexOutOfBoundsException + * if {@code eqn.length} < 3. + * @throws NullPointerException + * if the array is null. + */ + public static int solveQuadratic(double eqn[]) { + return solveQuadratic(eqn, eqn); + } + + /** + * Finds the roots of the quadratic polynomial. This is accomplished by + * finding the (real) values of x that solve the following equation: + * eqn[2]*x*x + eqn[1]*x + eqn[0] = 0. The solutions are written into the + * array res starting from the index 0 in the array. The return value tells + * how many array elements have been written by this method call. + * + * @param eqn + * an array containing the coefficients of the quadratic + * polynomial to solve. + * @param res + * the array that this method writes the results into. + * @return the number of roots of the quadratic polynomial. + * @throws ArrayIndexOutOfBoundsException + * if {@code eqn.length} < 3 or if {@code res.length} is less + * than the number of roots. + * @throws NullPointerException + * if either array is null. + */ + public static int solveQuadratic(double eqn[], double res[]) { + return Crossing.solveQuad(eqn, res); + } + + public boolean contains(double px, double py) { + return Crossing.isInsideEvenOdd(Crossing.crossShape(this, px, py)); + } + + public boolean contains(double rx, double ry, double rw, double rh) { + int cross = Crossing.intersectShape(this, rx, ry, rw, rh); + return cross != Crossing.CROSSING && Crossing.isInsideEvenOdd(cross); + } + + public boolean intersects(double rx, double ry, double rw, double rh) { + int cross = Crossing.intersectShape(this, rx, ry, rw, rh); + return cross == Crossing.CROSSING || Crossing.isInsideEvenOdd(cross); + } + + public boolean contains(Point2D p) { + return contains(p.getX(), p.getY()); + } + + public boolean intersects(Rectangle2D r) { + return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + public boolean contains(Rectangle2D r) { + return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + public Rectangle getBounds() { + return getBounds2D().getBounds(); + } + + public PathIterator getPathIterator(AffineTransform t) { + return new Iterator(this, t); + } + + public PathIterator getPathIterator(AffineTransform t, double flatness) { + return new FlatteningPathIterator(getPathIterator(t), flatness); + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + } + +} diff --git a/awt/java/awt/geom/Rectangle2D.java b/awt/java/awt/geom/Rectangle2D.java new file mode 100644 index 0000000..8166134 --- /dev/null +++ b/awt/java/awt/geom/Rectangle2D.java @@ -0,0 +1,824 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt.geom; + +import java.util.NoSuchElementException; + +import org.apache.harmony.awt.internal.nls.Messages; +import org.apache.harmony.misc.HashCode; + +/** + * The Class Rectangle2D represents a rectangle whose coordinates are given with + * the correct precision to be used with the Graphics2D classes. + * + * @since Android 1.0 + */ +public abstract class Rectangle2D extends RectangularShape { + + /** + * The Constant OUT_LEFT is a mask that is used to indicate that a given + * point is outside the rectangle and to its left. + */ + public static final int OUT_LEFT = 1; + + /** + * The Constant OUT_TOP is a mask that is used to indicate that a given + * point is outside the rectangle and above it. + */ + public static final int OUT_TOP = 2; + + /** + * The Constant OUT_RIGHT is a mask that is used to indicate that a given + * point is outside the rectangle and to its right. + */ + public static final int OUT_RIGHT = 4; + + /** + * The Constant OUT_BOTTOM is a mask that is used to indicate that a given + * point is outside the rectangle and above it. + */ + public static final int OUT_BOTTOM = 8; + + /** + * The Class Float is the subclass of Rectangle2D that represents a + * rectangle whose data values are given as floats (with float-level + * precision). + * + * @since Android 1.0 + */ + public static class Float extends Rectangle2D { + + /** + * The x coordinate of the rectangle's upper left corner. + */ + public float x; + + /** + * The y coordinate of the rectangle's upper left corner. + */ + public float y; + + /** + * The width of the rectangle. + */ + public float width; + + /** + * The height of the rectangle. + */ + public float height; + + /** + * Instantiates a new empty rectangle with float-precision data fields. + */ + public Float() { + } + + /** + * Instantiates a new rectangle with the specified float-precision data. + * + * @param x + * the x coordinate of the rectangle's upper left corner. + * @param y + * the y coordinate of the rectangle's upper left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + */ + public Float(float x, float y, float width, float height) { + setRect(x, y, width, height); + } + + @Override + public double getX() { + return x; + } + + @Override + public double getY() { + return y; + } + + @Override + public double getWidth() { + return width; + } + + @Override + public double getHeight() { + return height; + } + + @Override + public boolean isEmpty() { + return width <= 0.0f || height <= 0.0f; + } + + /** + * Sets the rectangle's data to the given values. + * + * @param x + * the x coordinate of the rectangle's upper left corner. + * @param y + * the y coordinate of the rectangle's upper left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + */ + public void setRect(float x, float y, float width, float height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + @Override + public void setRect(double x, double y, double width, double height) { + this.x = (float)x; + this.y = (float)y; + this.width = (float)width; + this.height = (float)height; + } + + @Override + public void setRect(Rectangle2D r) { + this.x = (float)r.getX(); + this.y = (float)r.getY(); + this.width = (float)r.getWidth(); + this.height = (float)r.getHeight(); + } + + @Override + public int outcode(double px, double py) { + int code = 0; + + if (width <= 0.0f) { + code |= OUT_LEFT | OUT_RIGHT; + } else if (px < x) { + code |= OUT_LEFT; + } else if (px > x + width) { + code |= OUT_RIGHT; + } + + if (height <= 0.0f) { + code |= OUT_TOP | OUT_BOTTOM; + } else if (py < y) { + code |= OUT_TOP; + } else if (py > y + height) { + code |= OUT_BOTTOM; + } + + return code; + } + + @Override + public Rectangle2D getBounds2D() { + return new Float(x, y, width, height); + } + + @Override + public Rectangle2D createIntersection(Rectangle2D r) { + Rectangle2D dst; + if (r instanceof Double) { + dst = new Rectangle2D.Double(); + } else { + dst = new Rectangle2D.Float(); + } + Rectangle2D.intersect(this, r, dst); + return dst; + } + + @Override + public Rectangle2D createUnion(Rectangle2D r) { + Rectangle2D dst; + if (r instanceof Double) { + dst = new Rectangle2D.Double(); + } else { + dst = new Rectangle2D.Float(); + } + Rectangle2D.union(this, r, dst); + return dst; + } + + @Override + public String toString() { + // The output format based on 1.5 release behaviour. It could be + // obtained in the following way + // System.out.println(new Rectangle2D.Float().toString()) + return getClass().getName() + + "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + } + } + + /** + * The Class Double is the subclass of Rectangle2D that represents a + * rectangle whose data values are given as doubles (with + * double-precision-level precision). + * + * @since Android 1.0 + */ + public static class Double extends Rectangle2D { + + /** + * The x coordinate of the rectangle's upper left corner. + */ + public double x; + + /** + * The y coordinate of the rectangle's upper left corner. + */ + public double y; + + /** + * The width of the rectangle. + */ + public double width; + + /** + * The height of the rectangle. + */ + public double height; + + /** + * Instantiates a new empty rectangle with double-precision data fields. + */ + public Double() { + } + + /** + * Instantiates a new rectangle with the given double values. + * + * @param x + * the x coordinate of the rectangle's upper left corner. + * @param y + * the y coordinate of the rectangle's upper left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + */ + public Double(double x, double y, double width, double height) { + setRect(x, y, width, height); + } + + @Override + public double getX() { + return x; + } + + @Override + public double getY() { + return y; + } + + @Override + public double getWidth() { + return width; + } + + @Override + public double getHeight() { + return height; + } + + @Override + public boolean isEmpty() { + return width <= 0.0 || height <= 0.0; + } + + @Override + public void setRect(double x, double y, double width, double height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + @Override + public void setRect(Rectangle2D r) { + this.x = r.getX(); + this.y = r.getY(); + this.width = r.getWidth(); + this.height = r.getHeight(); + } + + @Override + public int outcode(double px, double py) { + int code = 0; + + if (width <= 0.0) { + code |= OUT_LEFT | OUT_RIGHT; + } else if (px < x) { + code |= OUT_LEFT; + } else if (px > x + width) { + code |= OUT_RIGHT; + } + + if (height <= 0.0) { + code |= OUT_TOP | OUT_BOTTOM; + } else if (py < y) { + code |= OUT_TOP; + } else if (py > y + height) { + code |= OUT_BOTTOM; + } + + return code; + } + + @Override + public Rectangle2D getBounds2D() { + return new Double(x, y, width, height); + } + + @Override + public Rectangle2D createIntersection(Rectangle2D r) { + Rectangle2D dst = new Rectangle2D.Double(); + Rectangle2D.intersect(this, r, dst); + return dst; + } + + @Override + public Rectangle2D createUnion(Rectangle2D r) { + Rectangle2D dest = new Rectangle2D.Double(); + Rectangle2D.union(this, r, dest); + return dest; + } + + @Override + public String toString() { + // The output format based on 1.5 release behaviour. It could be + // obtained in the following way + // System.out.println(new Rectangle2D.Double().toString()) + return getClass().getName() + + "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + } + } + + /** + * The Class Iterator provides access to the coordinates of the + * Rectangle2D's boundary modified by an AffineTransform. + */ + class Iterator implements PathIterator { + + /** + * The x coordinate of the rectangle's upper left corner. + */ + double x; + + /** + * The y coordinate of the rectangle's upper left corner. + */ + double y; + + /** + * The width of the rectangle. + */ + double width; + + /** + * The height of the rectangle. + */ + double height; + + /** + * The AffineTransform that is used to modify the coordinates that are + * returned by the path iterator. + */ + AffineTransform t; + + /** + * The current segment index. + */ + int index; + + /** + * Constructs a new Rectangle2D.Iterator for given rectangle and + * transformation. + * + * @param r + * the source Rectangle2D object. + * @param at + * the AffineTransform object to apply to the coordinates + * before returning them. + */ + Iterator(Rectangle2D r, AffineTransform at) { + this.x = r.getX(); + this.y = r.getY(); + this.width = r.getWidth(); + this.height = r.getHeight(); + this.t = at; + if (width < 0.0 || height < 0.0) { + index = 6; + } + } + + public int getWindingRule() { + return WIND_NON_ZERO; + } + + public boolean isDone() { + return index > 5; + } + + public void next() { + index++; + } + + public int currentSegment(double[] coords) { + if (isDone()) { + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + if (index == 5) { + return SEG_CLOSE; + } + int type; + if (index == 0) { + type = SEG_MOVETO; + coords[0] = x; + coords[1] = y; + } else { + type = SEG_LINETO; + switch (index) { + case 1: + coords[0] = x + width; + coords[1] = y; + break; + case 2: + coords[0] = x + width; + coords[1] = y + height; + break; + case 3: + coords[0] = x; + coords[1] = y + height; + break; + case 4: + coords[0] = x; + coords[1] = y; + break; + } + } + if (t != null) { + t.transform(coords, 0, coords, 0, 1); + } + return type; + } + + public int currentSegment(float[] coords) { + if (isDone()) { + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + if (index == 5) { + return SEG_CLOSE; + } + int type; + if (index == 0) { + coords[0] = (float)x; + coords[1] = (float)y; + type = SEG_MOVETO; + } else { + type = SEG_LINETO; + switch (index) { + case 1: + coords[0] = (float)(x + width); + coords[1] = (float)y; + break; + case 2: + coords[0] = (float)(x + width); + coords[1] = (float)(y + height); + break; + case 3: + coords[0] = (float)x; + coords[1] = (float)(y + height); + break; + case 4: + coords[0] = (float)x; + coords[1] = (float)y; + break; + } + } + if (t != null) { + t.transform(coords, 0, coords, 0, 1); + } + return type; + } + + } + + /** + * Instantiates a new Rectangle2D. + */ + protected Rectangle2D() { + } + + /** + * Sets the rectangle's location and dimension. + * + * @param x + * the x coordinate of the rectangle's upper left corner. + * @param y + * the y coordinate of the rectangle's upper left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + */ + public abstract void setRect(double x, double y, double width, double height); + + /** + * Gets the location of the point with respect to the rectangle and packs + * the information into a single integer using the bitmasks + * {@link Rectangle2D#OUT_LEFT}, {@link Rectangle2D#OUT_RIGHT}, + * {@link Rectangle2D#OUT_TOP}, and {@link Rectangle2D#OUT_BOTTOM}. If the + * rectangle has zero or negative width, then every point is regarded as + * being both to the left and to the right of the rectangle. Similarly, if + * the height is zero or negative then all points are considered to be both + * both above and below it. + * + * @param x + * the x coordinate of the point to check. + * @param y + * the y coordinate of the point to check. + * @return the point's location with respect to the rectangle. + */ + public abstract int outcode(double x, double y); + + /** + * Creates an new rectangle that is the intersection of this rectangle with + * the given rectangle. The resulting rectangle may be empty. The data of + * this rectangle is left unchanged. + * + * @param r + * the rectangle to intersect with this rectangle. + * @return the new rectangle given by intersection. + */ + public abstract Rectangle2D createIntersection(Rectangle2D r); + + /** + * Creates an new rectangle that is the union of this rectangle with the + * given rectangle. The new rectangle is the smallest rectangle which + * contains both this rectangle and the rectangle specified as a parameter. + * The data of this rectangle is left unchanged. + * + * @param r + * the rectangle to combine with this rectangle. + * @return the new rectangle given by union. + */ + public abstract Rectangle2D createUnion(Rectangle2D r); + + /** + * Sets the data of this rectangle to match the data of the given rectangle. + * + * @param r + * the rectangle whose data is to be copied into this rectangle's + * fields. + */ + public void setRect(Rectangle2D r) { + setRect(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + @Override + public void setFrame(double x, double y, double width, double height) { + setRect(x, y, width, height); + } + + public Rectangle2D getBounds2D() { + return (Rectangle2D)clone(); + } + + /** + * Determines whether any part of the line segment between (and including) + * the two given points touches any part of the rectangle, including its + * boundary. + * + * @param x1 + * the x coordinate of one of the points that determines the line + * segment to test. + * @param y1 + * the y coordinate of one of the points that determines the line + * segment to test. + * @param x2 + * the x coordinate of one of the points that determines the line + * segment to test. + * @param y2 + * the y coordinate of one of the points that determines the line + * segment to test. + * @return true, if at least one point of the line segment between the two + * points matches any point of the interior of the rectangle or the + * rectangle's boundary. + */ + public boolean intersectsLine(double x1, double y1, double x2, double y2) { + double rx1 = getX(); + double ry1 = getY(); + double rx2 = rx1 + getWidth(); + double ry2 = ry1 + getHeight(); + return (rx1 <= x1 && x1 <= rx2 && ry1 <= y1 && y1 <= ry2) + || (rx1 <= x2 && x2 <= rx2 && ry1 <= y2 && y2 <= ry2) + || Line2D.linesIntersect(rx1, ry1, rx2, ry2, x1, y1, x2, y2) + || Line2D.linesIntersect(rx2, ry1, rx1, ry2, x1, y1, x2, y2); + } + + /** + * Determines whether any part of the specified line segment touches any + * part of the rectangle, including its boundary. + * + * @param l + * the line segment to test. + * @return true, if at least one point of the given line segment matches any + * point of the interior of the rectangle or the rectangle's + * boundary. + */ + public boolean intersectsLine(Line2D l) { + return intersectsLine(l.getX1(), l.getY1(), l.getX2(), l.getY2()); + } + + /** + * Gets the location of the point with respect to the rectangle and packs + * the information into a single integer using the bitmasks + * {@link Rectangle2D#OUT_LEFT}, {@link Rectangle2D#OUT_RIGHT}, + * {@link Rectangle2D#OUT_TOP}, and {@link Rectangle2D#OUT_BOTTOM}. If the + * rectangle has zero or negative width, then every point is regarded as + * being both to the left and to the right of the rectangle. Similarly, if + * the height is zero or negative then all points are considered to be both + * both above and below it. + * + * @param p + * the point to check. + * @return the point's location with respect to the rectangle. + */ + public int outcode(Point2D p) { + return outcode(p.getX(), p.getY()); + } + + public boolean contains(double x, double y) { + if (isEmpty()) { + return false; + } + + double x1 = getX(); + double y1 = getY(); + double x2 = x1 + getWidth(); + double y2 = y1 + getHeight(); + + return x1 <= x && x < x2 && y1 <= y && y < y2; + } + + public boolean intersects(double x, double y, double width, double height) { + if (isEmpty() || width <= 0.0 || height <= 0.0) { + return false; + } + + double x1 = getX(); + double y1 = getY(); + double x2 = x1 + getWidth(); + double y2 = y1 + getHeight(); + + return x + width > x1 && x < x2 && y + height > y1 && y < y2; + } + + public boolean contains(double x, double y, double width, double height) { + if (isEmpty() || width <= 0.0 || height <= 0.0) { + return false; + } + + double x1 = getX(); + double y1 = getY(); + double x2 = x1 + getWidth(); + double y2 = y1 + getHeight(); + + return x1 <= x && x + width <= x2 && y1 <= y && y + height <= y2; + } + + /** + * Changes the data values of the destination rectangle to match the + * intersection of the two source rectangles, leaving the two source + * rectangles unchanged. The resulting rectangle may be empty. + * + * @param src1 + * one of the two source rectangles giving the data to intersect. + * @param src2 + * one of the two source rectangles giving the data to intersect. + * @param dst + * the destination object where the data of the intersection is + * written. + */ + public static void intersect(Rectangle2D src1, Rectangle2D src2, Rectangle2D dst) { + double x1 = Math.max(src1.getMinX(), src2.getMinX()); + double y1 = Math.max(src1.getMinY(), src2.getMinY()); + double x2 = Math.min(src1.getMaxX(), src2.getMaxX()); + double y2 = Math.min(src1.getMaxY(), src2.getMaxY()); + dst.setFrame(x1, y1, x2 - x1, y2 - y1); + } + + /** + * Changes the data values of the destination rectangle to match the union + * of the two source rectangles, leaving the two source rectangles + * unchanged. The union is the smallest rectangle that completely covers the + * two source rectangles. + * + * @param src1 + * one of the two source rectangles giving the data. + * @param src2 + * one of the two source rectangles giving the data. + * @param dst + * the destination object where the data of the union is written. + */ + public static void union(Rectangle2D src1, Rectangle2D src2, Rectangle2D dst) { + double x1 = Math.min(src1.getMinX(), src2.getMinX()); + double y1 = Math.min(src1.getMinY(), src2.getMinY()); + double x2 = Math.max(src1.getMaxX(), src2.getMaxX()); + double y2 = Math.max(src1.getMaxY(), src2.getMaxY()); + dst.setFrame(x1, y1, x2 - x1, y2 - y1); + } + + /** + * Enlarges the rectangle so that it includes the given point. + * + * @param x + * the x coordinate of the new point to be covered by the + * rectangle. + * @param y + * the y coordinate of the new point to be covered by the + * rectangle. + */ + public void add(double x, double y) { + double x1 = Math.min(getMinX(), x); + double y1 = Math.min(getMinY(), y); + double x2 = Math.max(getMaxX(), x); + double y2 = Math.max(getMaxY(), y); + setRect(x1, y1, x2 - x1, y2 - y1); + } + + /** + * Enlarges the rectangle so that it includes the given point. + * + * @param p + * the new point to be covered by the rectangle. + */ + public void add(Point2D p) { + add(p.getX(), p.getY()); + } + + /** + * Enlarges the rectangle so that it covers the given rectangle. + * + * @param r + * the new rectangle to be covered by this rectangle. + */ + public void add(Rectangle2D r) { + union(this, r, this); + } + + public PathIterator getPathIterator(AffineTransform t) { + return new Iterator(this, t); + } + + @Override + public PathIterator getPathIterator(AffineTransform t, double flatness) { + return new Iterator(this, t); + } + + @Override + public int hashCode() { + HashCode hash = new HashCode(); + hash.append(getX()); + hash.append(getY()); + hash.append(getWidth()); + hash.append(getHeight()); + return hash.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Rectangle2D) { + Rectangle2D r = (Rectangle2D)obj; + return getX() == r.getX() && getY() == r.getY() && getWidth() == r.getWidth() + && getHeight() == r.getHeight(); + } + return false; + } + +} diff --git a/awt/java/awt/geom/RectangularShape.java b/awt/java/awt/geom/RectangularShape.java new file mode 100644 index 0000000..0b0d05c --- /dev/null +++ b/awt/java/awt/geom/RectangularShape.java @@ -0,0 +1,297 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt.geom; + +import java.awt.Rectangle; +import java.awt.Shape; + +/** + * The Class RectangularShape represents a Shape whose data is (at least + * partially) described by a rectangular frame. This includes shapes which are + * obviously rectangular (such as Rectangle2D) as well as shapes like Arc2D + * which are largely determined by the rectangle they fit inside. + * + * @since Android 1.0 + */ +public abstract class RectangularShape implements Shape, Cloneable { + + /** + * Instantiates a new rectangular shape. + */ + protected RectangularShape() { + } + + /** + * Gets the x coordinate of the upper left corner of the rectangle. + * + * @return the x coordinate of the upper left corner of the rectangle. + */ + public abstract double getX(); + + /** + * Gets the y coordinate of the upper left corner of the rectangle. + * + * @return the y coordinate of the upper left corner of the rectangle. + */ + public abstract double getY(); + + /** + * Gets the width of the rectangle. + * + * @return the width of the rectangle. + */ + public abstract double getWidth(); + + /** + * Gets the height of the rectangle. + * + * @return the height of the rectangle. + */ + public abstract double getHeight(); + + /** + * Checks if this is an empty rectangle: one with zero as its width or + * height. + * + * @return true, if the width or height is empty. + */ + public abstract boolean isEmpty(); + + /** + * Sets the data for the bounding rectangle in terms of double values. + * + * @param x + * the x coordinate of the upper left corner of the rectangle. + * @param y + * the y coordinate of the upper left corner of the rectangle. + * @param w + * the width of the rectangle. + * @param h + * the height of the rectangle. + */ + public abstract void setFrame(double x, double y, double w, double h); + + /** + * Gets the minimum x value of the bounding rectangle (the x coordinate of + * the upper left corner of the rectangle). + * + * @return the minimum x value of the bounding rectangle. + */ + public double getMinX() { + return getX(); + } + + /** + * Gets the minimum y value of the bounding rectangle (the y coordinate of + * the upper left corner of the rectangle). + * + * @return the minimum y value of the bounding rectangle. + */ + public double getMinY() { + return getY(); + } + + /** + * Gets the maximum x value of the bounding rectangle (the x coordinate of + * the upper left corner of the rectangle plus the rectangle's width). + * + * @return the maximum x value of the bounding rectangle. + */ + public double getMaxX() { + return getX() + getWidth(); + } + + /** + * Gets the maximum y value of the bounding rectangle (the y coordinate of + * the upper left corner of the rectangle plus the rectangle's height). + * + * @return the maximum y value of the bounding rectangle. + */ + public double getMaxY() { + return getY() + getHeight(); + } + + /** + * Gets the x coordinate of the center of the rectangle. + * + * @return the x coordinate of the center of the rectangle. + */ + public double getCenterX() { + return getX() + getWidth() / 2.0; + } + + /** + * Gets the y coordinate of the center of the rectangle. + * + * @return the y coordinate of the center of the rectangle. + */ + public double getCenterY() { + return getY() + getHeight() / 2.0; + } + + /** + * Places the rectangle's size and location data in a new Rectangle2D object + * and returns it. + * + * @return the bounding rectangle as a new Rectangle2D object. + */ + public Rectangle2D getFrame() { + return new Rectangle2D.Double(getX(), getY(), getWidth(), getHeight()); + } + + /** + * Sets the bounding rectangle in terms of a Point2D which gives its upper + * left corner and a Dimension2D object giving its width and height. + * + * @param loc + * the new upper left corner coordinate. + * @param size + * the new size dimensions. + */ + public void setFrame(Point2D loc, Dimension2D size) { + setFrame(loc.getX(), loc.getY(), size.getWidth(), size.getHeight()); + } + + /** + * Sets the bounding rectangle to match the data contained in the specified + * Rectangle2D. + * + * @param r + * the rectangle that gives the new frame data. + */ + public void setFrame(Rectangle2D r) { + setFrame(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Sets the framing rectangle given two opposite corners. Any two corners + * may be used in any order as long as they are diagonally opposite one + * another. + * + * @param x1 + * the x coordinate of one of the corner points. + * @param y1 + * the y coordinate of one of the corner points. + * @param x2 + * the x coordinate of the other corner point. + * @param y2 + * the y coordinate of the other corner point. + */ + public void setFrameFromDiagonal(double x1, double y1, double x2, double y2) { + double rx, ry, rw, rh; + if (x1 < x2) { + rx = x1; + rw = x2 - x1; + } else { + rx = x2; + rw = x1 - x2; + } + if (y1 < y2) { + ry = y1; + rh = y2 - y1; + } else { + ry = y2; + rh = y1 - y2; + } + setFrame(rx, ry, rw, rh); + } + + /** + * Sets the framing rectangle given two opposite corners. Any two corners + * may be used in any order as long as they are diagonally opposite one + * another. + * + * @param p1 + * one of the corner points. + * @param p2 + * the other corner point. + */ + public void setFrameFromDiagonal(Point2D p1, Point2D p2) { + setFrameFromDiagonal(p1.getX(), p1.getY(), p2.getX(), p2.getY()); + } + + /** + * Sets the framing rectangle given the center point and one corner. Any + * corner may be used. + * + * @param centerX + * the x coordinate of the center point. + * @param centerY + * the y coordinate of the center point. + * @param cornerX + * the x coordinate of one of the corner points. + * @param cornerY + * the y coordinate of one of the corner points. + */ + public void setFrameFromCenter(double centerX, double centerY, double cornerX, double cornerY) { + double width = Math.abs(cornerX - centerX); + double height = Math.abs(cornerY - centerY); + setFrame(centerX - width, centerY - height, width * 2.0, height * 2.0); + } + + /** + * Sets the framing rectangle given the center point and one corner. Any + * corner may be used. + * + * @param center + * the center point. + * @param corner + * a corner point. + */ + public void setFrameFromCenter(Point2D center, Point2D corner) { + setFrameFromCenter(center.getX(), center.getY(), corner.getX(), corner.getY()); + } + + public boolean contains(Point2D point) { + return contains(point.getX(), point.getY()); + } + + public boolean intersects(Rectangle2D rect) { + return intersects(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); + } + + public boolean contains(Rectangle2D rect) { + return contains(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); + } + + public Rectangle getBounds() { + int x1 = (int)Math.floor(getMinX()); + int y1 = (int)Math.floor(getMinY()); + int x2 = (int)Math.ceil(getMaxX()); + int y2 = (int)Math.ceil(getMaxY()); + return new Rectangle(x1, y1, x2 - x1, y2 - y1); + } + + public PathIterator getPathIterator(AffineTransform t, double flatness) { + return new FlatteningPathIterator(getPathIterator(t), flatness); + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + } + +} diff --git a/awt/java/awt/geom/RoundRectangle2D.java b/awt/java/awt/geom/RoundRectangle2D.java new file mode 100644 index 0000000..8fbddd6 --- /dev/null +++ b/awt/java/awt/geom/RoundRectangle2D.java @@ -0,0 +1,635 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt.geom; + +import java.util.NoSuchElementException; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class RoundRectangle2D describes a rectangle with rounded corners with + * high-precision data that is appropriate for geometric operations. + * + * @since Android 1.0 + */ +public abstract class RoundRectangle2D extends RectangularShape { + + /** + * The Class Float is the subclass of RoundRectangle2D that has all of its + * data values stored with float-level precision. + * + * @since Android 1.0 + */ + public static class Float extends RoundRectangle2D { + + /** + * The x coordinate of the rectangle's upper left corner. + */ + public float x; + + /** + * The y coordinate of the rectangle's upper left corner. + */ + public float y; + + /** + * The width of the rectangle. + */ + public float width; + + /** + * The height of the rectangle. + */ + public float height; + + /** + * The arc width of the rounded corners. + */ + public float arcwidth; + + /** + * The arc height of the rounded corners. + */ + public float archeight; + + /** + * Instantiates a new float-valued RoundRectangle2D with its data-values + * set to zero. + */ + public Float() { + } + + /** + * Instantiates a new float-valued RoundRectangle2D with the specified + * data values. + * + * @param x + * the x coordinate of the rectangle's upper left corner. + * @param y + * the y coordinate of the rectangle's upper left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + * @param arcwidth + * the arc width of the rounded corners. + * @param archeight + * the arc height of the rounded corners. + */ + public Float(float x, float y, float width, float height, float arcwidth, float archeight) { + setRoundRect(x, y, width, height, arcwidth, archeight); + } + + @Override + public double getX() { + return x; + } + + @Override + public double getY() { + return y; + } + + @Override + public double getWidth() { + return width; + } + + @Override + public double getHeight() { + return height; + } + + @Override + public double getArcWidth() { + return arcwidth; + } + + @Override + public double getArcHeight() { + return archeight; + } + + @Override + public boolean isEmpty() { + return width <= 0.0f || height <= 0.0f; + } + + /** + * Sets the data of the round rectangle. + * + * @param x + * the x coordinate of the rectangle's upper left corner. + * @param y + * the y coordinate of the rectangle's upper left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + * @param arcwidth + * the arc width of the rounded corners. + * @param archeight + * the arc height of the rounded corners. + */ + public void setRoundRect(float x, float y, float width, float height, float arcwidth, + float archeight) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.arcwidth = arcwidth; + this.archeight = archeight; + } + + @Override + public void setRoundRect(double x, double y, double width, double height, double arcwidth, + double archeight) { + this.x = (float)x; + this.y = (float)y; + this.width = (float)width; + this.height = (float)height; + this.arcwidth = (float)arcwidth; + this.archeight = (float)archeight; + } + + @Override + public void setRoundRect(RoundRectangle2D rr) { + this.x = (float)rr.getX(); + this.y = (float)rr.getY(); + this.width = (float)rr.getWidth(); + this.height = (float)rr.getHeight(); + this.arcwidth = (float)rr.getArcWidth(); + this.archeight = (float)rr.getArcHeight(); + } + + public Rectangle2D getBounds2D() { + return new Rectangle2D.Float(x, y, width, height); + } + } + + /** + * The Class Double is the subclass of RoundRectangle2D that has all of its + * data values stored with double-level precision. + * + * @since Android 1.0 + */ + public static class Double extends RoundRectangle2D { + + /** + * The x coordinate of the rectangle's upper left corner. + */ + public double x; + + /** + * The y coordinate of the rectangle's upper left corner. + */ + public double y; + + /** + * The width of the rectangle. + */ + public double width; + + /** + * The height of the rectangle. + */ + public double height; + + /** + * The arc width of the rounded corners. + */ + public double arcwidth; + + /** + * The arc height of the rounded corners. + */ + public double archeight; + + /** + * Instantiates a new double-valued RoundRectangle2D with its + * data-values set to zero. + */ + public Double() { + } + + /** + * Instantiates a new double-valued RoundRectangle2D with the specified + * data values. + * + * @param x + * the x coordinate of the rectangle's upper left corner. + * @param y + * the y coordinate of the rectangle's upper left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + * @param arcwidth + * the arc width of the rounded corners. + * @param archeight + * the arc height of the rounded corners. + */ + public Double(double x, double y, double width, double height, double arcwidth, + double archeight) { + setRoundRect(x, y, width, height, arcwidth, archeight); + } + + @Override + public double getX() { + return x; + } + + @Override + public double getY() { + return y; + } + + @Override + public double getWidth() { + return width; + } + + @Override + public double getHeight() { + return height; + } + + @Override + public double getArcWidth() { + return arcwidth; + } + + @Override + public double getArcHeight() { + return archeight; + } + + @Override + public boolean isEmpty() { + return width <= 0.0 || height <= 0.0; + } + + @Override + public void setRoundRect(double x, double y, double width, double height, double arcwidth, + double archeight) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.arcwidth = arcwidth; + this.archeight = archeight; + } + + @Override + public void setRoundRect(RoundRectangle2D rr) { + this.x = rr.getX(); + this.y = rr.getY(); + this.width = rr.getWidth(); + this.height = rr.getHeight(); + this.arcwidth = rr.getArcWidth(); + this.archeight = rr.getArcHeight(); + } + + public Rectangle2D getBounds2D() { + return new Rectangle2D.Double(x, y, width, height); + } + } + + /* + * RoundRectangle2D path iterator + */ + /** + * The subclass of PathIterator to traverse a RoundRectangle2D. + */ + class Iterator implements PathIterator { + + /* + * Path for round corners generated the same way as Ellipse2D + */ + + /** + * The coefficient to calculate control points of Bezier curves. + */ + double u = 0.5 - 2.0 / 3.0 * (Math.sqrt(2.0) - 1.0); + + /** + * The points coordinates calculation table. + */ + double points[][] = { + { + 0.0, 0.5, 0.0, 0.0 + }, // MOVETO + { + 1.0, -0.5, 0.0, 0.0 + }, // LINETO + { + 1.0, -u, 0.0, 0.0, // CUBICTO + 1.0, 0.0, 0.0, u, 1.0, 0.0, 0.0, 0.5 + }, { + 1.0, 0.0, 1.0, -0.5 + }, // LINETO + { + 1.0, 0.0, 1.0, -u, // CUBICTO + 1.0, -u, 1.0, 0.0, 1.0, -0.5, 1.0, 0.0 + }, { + 0.0, 0.5, 1.0, 0.0 + }, // LINETO + { + 0.0, u, 1.0, 0.0, // CUBICTO + 0.0, 0.0, 1.0, -u, 0.0, 0.0, 1.0, -0.5 + }, { + 0.0, 0.0, 0.0, 0.5 + }, // LINETO + { + 0.0, 0.0, 0.0, u, // CUBICTO + 0.0, u, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0 + } + }; + + /** + * The segment types correspond to points array. + */ + int types[] = { + SEG_MOVETO, SEG_LINETO, SEG_CUBICTO, SEG_LINETO, SEG_CUBICTO, SEG_LINETO, + SEG_CUBICTO, SEG_LINETO, SEG_CUBICTO + }; + + /** + * The x coordinate of left-upper corner of the round rectangle bounds. + */ + double x; + + /** + * The y coordinate of left-upper corner of the round rectangle bounds. + */ + double y; + + /** + * The width of the round rectangle bounds. + */ + double width; + + /** + * The height of the round rectangle bounds. + */ + double height; + + /** + * The width of arc corners of the round rectangle. + */ + double aw; + + /** + * The height of arc corners of the round rectangle. + */ + double ah; + + /** + * The path iterator transformation. + */ + AffineTransform t; + + /** + * The current segment index. + */ + int index; + + /** + * Constructs a new RoundRectangle2D.Iterator for given round rectangle + * and transformation. + * + * @param rr + * - the source RoundRectangle2D object + * @param at + * - the AffineTransform object to apply rectangle path + */ + Iterator(RoundRectangle2D rr, AffineTransform at) { + this.x = rr.getX(); + this.y = rr.getY(); + this.width = rr.getWidth(); + this.height = rr.getHeight(); + this.aw = Math.min(width, rr.getArcWidth()); + this.ah = Math.min(height, rr.getArcHeight()); + this.t = at; + if (width < 0.0 || height < 0.0 || aw < 0.0 || ah < 0.0) { + index = points.length; + } + } + + public int getWindingRule() { + return WIND_NON_ZERO; + } + + public boolean isDone() { + return index > points.length; + } + + public void next() { + index++; + } + + public int currentSegment(double[] coords) { + if (isDone()) { + // awt.4B=Iterator out of bounds + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + if (index == points.length) { + return SEG_CLOSE; + } + int j = 0; + double p[] = points[index]; + for (int i = 0; i < p.length; i += 4) { + coords[j++] = x + p[i + 0] * width + p[i + 1] * aw; + coords[j++] = y + p[i + 2] * height + p[i + 3] * ah; + } + if (t != null) { + t.transform(coords, 0, coords, 0, j / 2); + } + return types[index]; + } + + public int currentSegment(float[] coords) { + if (isDone()) { + // awt.4B=Iterator out of bounds + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + if (index == points.length) { + return SEG_CLOSE; + } + int j = 0; + double p[] = points[index]; + for (int i = 0; i < p.length; i += 4) { + coords[j++] = (float)(x + p[i + 0] * width + p[i + 1] * aw); + coords[j++] = (float)(y + p[i + 2] * height + p[i + 3] * ah); + } + if (t != null) { + t.transform(coords, 0, coords, 0, j / 2); + } + return types[index]; + } + + } + + /** + * Instantiates a new RoundRectangle2D. + */ + protected RoundRectangle2D() { + } + + /** + * Gets the arc width. + * + * @return the arc width. + */ + public abstract double getArcWidth(); + + /** + * Gets the arc height. + * + * @return the arc height. + */ + public abstract double getArcHeight(); + + /** + * Sets the data of the RoundRectangle2D. + * + * @param x + * the x coordinate of the rectangle's upper left corner. + * @param y + * the y coordinate of the rectangle's upper left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + * @param arcWidth + * the arc width of the rounded corners. + * @param arcHeight + * the arc height of the rounded corners. + */ + public abstract void setRoundRect(double x, double y, double width, double height, + double arcWidth, double arcHeight); + + /** + * Sets the data of the RoundRectangle2D by copying the values from an + * existing RoundRectangle2D. + * + * @param rr + * the round rectangle to copy the data from. + * @throws NullPointerException + * if rr is null. + */ + public void setRoundRect(RoundRectangle2D rr) { + setRoundRect(rr.getX(), rr.getY(), rr.getWidth(), rr.getHeight(), rr.getArcWidth(), rr + .getArcHeight()); + } + + @Override + public void setFrame(double x, double y, double width, double height) { + setRoundRect(x, y, width, height, getArcWidth(), getArcHeight()); + } + + public boolean contains(double px, double py) { + if (isEmpty()) { + return false; + } + + double rx1 = getX(); + double ry1 = getY(); + double rx2 = rx1 + getWidth(); + double ry2 = ry1 + getHeight(); + + if (px < rx1 || px >= rx2 || py < ry1 || py >= ry2) { + return false; + } + + double aw = getArcWidth() / 2.0; + double ah = getArcHeight() / 2.0; + + double cx, cy; + + if (px < rx1 + aw) { + cx = rx1 + aw; + } else if (px > rx2 - aw) { + cx = rx2 - aw; + } else { + return true; + } + + if (py < ry1 + ah) { + cy = ry1 + ah; + } else if (py > ry2 - ah) { + cy = ry2 - ah; + } else { + return true; + } + + px = (px - cx) / aw; + py = (py - cy) / ah; + return px * px + py * py <= 1.0; + } + + public boolean intersects(double rx, double ry, double rw, double rh) { + if (isEmpty() || rw <= 0.0 || rh <= 0.0) { + return false; + } + + double x1 = getX(); + double y1 = getY(); + double x2 = x1 + getWidth(); + double y2 = y1 + getHeight(); + + double rx1 = rx; + double ry1 = ry; + double rx2 = rx + rw; + double ry2 = ry + rh; + + if (rx2 < x1 || x2 < rx1 || ry2 < y1 || y2 < ry1) { + return false; + } + + double cx = (x1 + x2) / 2.0; + double cy = (y1 + y2) / 2.0; + + double nx = cx < rx1 ? rx1 : (cx > rx2 ? rx2 : cx); + double ny = cy < ry1 ? ry1 : (cy > ry2 ? ry2 : cy); + + return contains(nx, ny); + } + + public boolean contains(double rx, double ry, double rw, double rh) { + if (isEmpty() || rw <= 0.0 || rh <= 0.0) { + return false; + } + + double rx1 = rx; + double ry1 = ry; + double rx2 = rx + rw; + double ry2 = ry + rh; + + return contains(rx1, ry1) && contains(rx2, ry1) && contains(rx2, ry2) && contains(rx1, ry2); + } + + public PathIterator getPathIterator(AffineTransform at) { + return new Iterator(this, at); + } + +} diff --git a/awt/java/awt/geom/package.html b/awt/java/awt/geom/package.html new file mode 100644 index 0000000..e3a236e --- /dev/null +++ b/awt/java/awt/geom/package.html @@ -0,0 +1,8 @@ +<html> + <body> + <p> + This package contains classes and interfaces related to Java2D shapes and geometry. + </p> + @since Android 1.0 + </body> +</html> diff --git a/awt/java/awt/im/InputContext.java b/awt/java/awt/im/InputContext.java new file mode 100644 index 0000000..cce5148 --- /dev/null +++ b/awt/java/awt/im/InputContext.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.im; + +import java.awt.AWTEvent; +//???AWT: import java.awt.Component; +import java.util.Locale; + +import org.apache.harmony.awt.im.InputMethodContext; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class InputContext { + protected InputContext() { + } + + public static InputContext getInstance() { + return new InputMethodContext(); + } + + public void dispatchEvent(AWTEvent event) { + } + + public void dispose() { + } + + public void endComposition() { + } + + public Object getInputMethodControlObject() { + return null; + } + + public Locale getLocale() { + return null; + } + + public boolean isCompositionEnabled() { + return false; + } + + public void reconvert() { + } + + //???AWT + /* + public void removeNotify(Component client) { + } + */ + + public boolean selectInputMethod(Locale locale) { + return false; + } + + public void setCharacterSubsets(Character.Subset[] subsets) { + } + + public void setCompositionEnabled(boolean enable) { + } +} + diff --git a/awt/java/awt/im/InputMethodHighlight.java b/awt/java/awt/im/InputMethodHighlight.java new file mode 100644 index 0000000..865d47c --- /dev/null +++ b/awt/java/awt/im/InputMethodHighlight.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev + * @version $Revision$ + */ +package java.awt.im; + +import java.util.Map; +import java.awt.font.TextAttribute; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class InputMethodHighlight { + + public static final int RAW_TEXT = 0; + + public static final int CONVERTED_TEXT = 1; + + public static final InputMethodHighlight + UNSELECTED_RAW_TEXT_HIGHLIGHT = new InputMethodHighlight(false, RAW_TEXT); + + public static final InputMethodHighlight + SELECTED_RAW_TEXT_HIGHLIGHT = new InputMethodHighlight(true, RAW_TEXT); + + public static final InputMethodHighlight + UNSELECTED_CONVERTED_TEXT_HIGHLIGHT = + new InputMethodHighlight(false, CONVERTED_TEXT); + + public static final InputMethodHighlight + SELECTED_CONVERTED_TEXT_HIGHLIGHT = + new InputMethodHighlight(true, CONVERTED_TEXT); + + private boolean selected; + private int state; + private int variation; + private Map<TextAttribute,?> style; + + public InputMethodHighlight(boolean selected, int state, int variation) { + this(selected, state, variation, null); + } + + public InputMethodHighlight(boolean selected, int state, + int variation, Map<java.awt.font.TextAttribute, ?> style) { + if ((state != RAW_TEXT) && (state != CONVERTED_TEXT)) { + // awt.20B=unknown input method highlight state + throw new IllegalArgumentException(Messages.getString("awt.20B")); //$NON-NLS-1$ + } + this.selected = selected; + this.state = state; + this.variation = variation; + this.style = style; + } + + public InputMethodHighlight(boolean selected, int state) { + this(selected, state, 0, null); + } + + public int getState() { + return state; + } + + public Map<java.awt.font.TextAttribute, ?> getStyle() { + return style; + } + + public int getVariation() { + return variation; + } + + public boolean isSelected() { + return selected; + } +} + diff --git a/awt/java/awt/im/InputMethodRequests.java b/awt/java/awt/im/InputMethodRequests.java new file mode 100644 index 0000000..b12d397 --- /dev/null +++ b/awt/java/awt/im/InputMethodRequests.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.im; + +import java.awt.Rectangle; +import java.awt.font.TextHitInfo; +import java.text.AttributedCharacterIterator; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface InputMethodRequests { + + public AttributedCharacterIterator cancelLatestCommittedText(AttributedCharacterIterator.Attribute[] attributes); + + public AttributedCharacterIterator getCommittedText(int beginIndex, int endIndex, AttributedCharacterIterator.Attribute[] attributes); + + public int getCommittedTextLength(); + + public int getInsertPositionOffset(); + + public TextHitInfo getLocationOffset(int x, int y); + + public AttributedCharacterIterator getSelectedText(AttributedCharacterIterator.Attribute[] attributes); + + public Rectangle getTextLocation(TextHitInfo offset); +} + diff --git a/awt/java/awt/im/InputSubset.java b/awt/java/awt/im/InputSubset.java new file mode 100644 index 0000000..708881e --- /dev/null +++ b/awt/java/awt/im/InputSubset.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev + * @version $Revision$ + */ +package java.awt.im; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public final class InputSubset extends Character.Subset { + + public static final InputSubset LATIN = new InputSubset("LATIN"); //$NON-NLS-1$ + + public static final InputSubset + LATIN_DIGITS = new InputSubset("LATIN_DIGITS"); //$NON-NLS-1$ + + public static final InputSubset + TRADITIONAL_HANZI = new InputSubset("TRADITIONAL_HANZI"); //$NON-NLS-1$ + + public static final InputSubset + SIMPLIFIED_HANZI = new InputSubset("SIMPLIFIED_HANZI"); //$NON-NLS-1$ + + public static final InputSubset KANJI = new InputSubset("KANJI"); //$NON-NLS-1$ + + public static final InputSubset HANJA = new InputSubset("HANJA"); //$NON-NLS-1$ + + public static final InputSubset + HALFWIDTH_KATAKANA = new InputSubset("HALFWIDTH_KATAKANA"); //$NON-NLS-1$ + + public static final InputSubset + FULLWIDTH_LATIN = new InputSubset("FULLWIDTH_LATIN"); //$NON-NLS-1$ + + public static final InputSubset + FULLWIDTH_DIGITS = new InputSubset("FULLWIDTH_DIGITS"); //$NON-NLS-1$ + + private InputSubset(String name) { + super(name); + } +} + diff --git a/awt/java/awt/im/spi/InputMethod.java b/awt/java/awt/im/spi/InputMethod.java new file mode 100644 index 0000000..67a8834 --- /dev/null +++ b/awt/java/awt/im/spi/InputMethod.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.im.spi; + +import java.awt.AWTEvent; +import java.awt.Rectangle; +import java.util.Locale; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface InputMethod { + + public void activate(); + + public void deactivate(boolean isTemporary); + + public void dispatchEvent(AWTEvent event); + + public void dispose(); + + public void endComposition(); + + public Object getControlObject(); + + public Locale getLocale(); + + public void hideWindows(); + + public boolean isCompositionEnabled(); + + public void notifyClientWindowChange(Rectangle bounds); + + public void reconvert(); + + public void removeNotify(); + + public void setCharacterSubsets(Character.Subset[] subsets); + + public void setCompositionEnabled(boolean enable); + + public void setInputMethodContext(InputMethodContext context); + + public boolean setLocale(Locale locale); +} + diff --git a/awt/java/awt/im/spi/InputMethodContext.java b/awt/java/awt/im/spi/InputMethodContext.java new file mode 100644 index 0000000..bfc773c --- /dev/null +++ b/awt/java/awt/im/spi/InputMethodContext.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.im.spi; + +//???AWT: import java.awt.Window; +import java.awt.font.TextHitInfo; +import java.awt.im.InputMethodRequests; +import java.text.AttributedCharacterIterator; +//???AWT: import javax.swing.JFrame; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface InputMethodContext extends InputMethodRequests { + +// ???AWT: public JFrame createInputMethodJFrame(String title, boolean attachToInputContext); + +// ???AWT: public Window createInputMethodWindow(String title, boolean attachToInputContext); + + public void dispatchInputMethodEvent(int id, AttributedCharacterIterator text, int committedCharacterCount, TextHitInfo caret, TextHitInfo visiblePosition); + + public void enableClientWindowNotification(InputMethod inputMethod, boolean enable); + +} + diff --git a/awt/java/awt/im/spi/InputMethodDescriptor.java b/awt/java/awt/im/spi/InputMethodDescriptor.java new file mode 100644 index 0000000..c800bc1 --- /dev/null +++ b/awt/java/awt/im/spi/InputMethodDescriptor.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.im.spi; + +import java.awt.AWTException; +import java.awt.Image; +import java.util.Locale; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface InputMethodDescriptor { + + public Locale[] getAvailableLocales() throws AWTException; + + public InputMethod createInputMethod() throws Exception; + + public String getInputMethodDisplayName(Locale inputLocale, Locale displayLanguage); + + public Image getInputMethodIcon(Locale inputLocale); + + public boolean hasDynamicLocaleList(); + +} + diff --git a/awt/java/awt/image/AffineTransformOp.java b/awt/java/awt/image/AffineTransformOp.java new file mode 100644 index 0000000..db25e1a --- /dev/null +++ b/awt/java/awt/image/AffineTransformOp.java @@ -0,0 +1,618 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky, Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.geom.Point2D; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.*; +import java.util.Arrays; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The AffineTransform class translates coordinates from 2D coordinates in the + * source image or Raster to 2D coordinates in the destination image or Raster + * using affine transformation. The number of bands in the source Raster should + * equal to the number of bands in the destination Raster. + * + * @since Android 1.0 + */ +public class AffineTransformOp implements BufferedImageOp, RasterOp { + + /** + * The Constant TYPE_NEAREST_NEIGHBOR indicates nearest-neighbor + * interpolation type. + */ + public static final int TYPE_NEAREST_NEIGHBOR = 1; + + /** + * The Constant TYPE_BILINEAR indicates bilinear interpolation type. + */ + public static final int TYPE_BILINEAR = 2; + + /** + * The Constant TYPE_BICUBIC indicates bi-cubic interpolation type. + */ + public static final int TYPE_BICUBIC = 3; + + /** + * The i type. + */ + private int iType; // interpolation type + + /** + * The at. + */ + private AffineTransform at; + + /** + * The hints. + */ + private RenderingHints hints; + + static { + // TODO - uncomment + // System.loadLibrary("imageops"); + } + + /** + * Instantiates a new AffineTransformOp with the specified AffineTransform + * and RenderingHints object which defines the interpolation type. + * + * @param xform + * the AffineTransform. + * @param hints + * the RenderingHints object which defines the interpolation + * type. + */ + public AffineTransformOp(AffineTransform xform, RenderingHints hints) { + this(xform, TYPE_NEAREST_NEIGHBOR); + this.hints = hints; + + if (hints != null) { + Object hint = hints.get(RenderingHints.KEY_INTERPOLATION); + if (hint != null) { + // Nearest neighbor is default + if (hint == RenderingHints.VALUE_INTERPOLATION_BILINEAR) { + this.iType = TYPE_BILINEAR; + } else if (hint == RenderingHints.VALUE_INTERPOLATION_BICUBIC) { + this.iType = TYPE_BICUBIC; + } + } else { + hint = hints.get(RenderingHints.KEY_RENDERING); + // Determine from rendering quality + if (hint == RenderingHints.VALUE_RENDER_QUALITY) { + this.iType = TYPE_BILINEAR; + // For speed use nearest neighbor + } + } + } + } + + /** + * Instantiates a new AffineTransformOp with the specified AffineTransform + * and a specified interpolation type from the list of predefined + * interpolation types. + * + * @param xform + * the AffineTransform. + * @param interp + * the one of predefined interpolation types: + * TYPE_NEAREST_NEIGHBOR, TYPE_BILINEAR, or TYPE_BICUBIC. + */ + public AffineTransformOp(AffineTransform xform, int interp) { + if (Math.abs(xform.getDeterminant()) <= Double.MIN_VALUE) { + // awt.24F=Unable to invert transform {0} + throw new ImagingOpException(Messages.getString("awt.24F", xform)); //$NON-NLS-1$ + } + + this.at = (AffineTransform)xform.clone(); + + if (interp != TYPE_NEAREST_NEIGHBOR && interp != TYPE_BILINEAR && interp != TYPE_BICUBIC) { + // awt.250=Unknown interpolation type: {0} + throw new IllegalArgumentException(Messages.getString("awt.250", interp)); //$NON-NLS-1$ + } + + this.iType = interp; + } + + /** + * Gets the interpolation type. + * + * @return the interpolation type. + */ + public final int getInterpolationType() { + return iType; + } + + public final RenderingHints getRenderingHints() { + if (hints == null) { + Object value = null; + + switch (iType) { + case TYPE_NEAREST_NEIGHBOR: + value = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR; + break; + case TYPE_BILINEAR: + value = RenderingHints.VALUE_INTERPOLATION_BILINEAR; + break; + case TYPE_BICUBIC: + value = RenderingHints.VALUE_INTERPOLATION_BICUBIC; + break; + default: + value = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR; + } + + hints = new RenderingHints(RenderingHints.KEY_INTERPOLATION, value); + } + + return hints; + } + + /** + * Gets the affine transform associated with this AffineTransformOp. + * + * @return the AffineTransform. + */ + public final AffineTransform getTransform() { + return (AffineTransform)at.clone(); + } + + public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { + return at.transform(srcPt, dstPt); + } + + public final Rectangle2D getBounds2D(BufferedImage src) { + return getBounds2D(src.getRaster()); + } + + public final Rectangle2D getBounds2D(Raster src) { + // We position source raster to (0,0) even if it is translated child + // raster. + // This means that we need only width and height of the src + int width = src.getWidth(); + int height = src.getHeight(); + + float[] corners = { + 0, 0, width, 0, width, height, 0, height + }; + + at.transform(corners, 0, corners, 0, 4); + + Rectangle2D.Float bounds = new Rectangle2D.Float(corners[0], corners[1], 0, 0); + bounds.add(corners[2], corners[3]); + bounds.add(corners[4], corners[5]); + bounds.add(corners[6], corners[7]); + + return bounds; + } + + public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) { + Rectangle2D newBounds = getBounds2D(src); + + // Destination image should include (0,0) + positive part + // of the area bounded by newBounds (in source coordinate system). + double dstWidth = newBounds.getX() + newBounds.getWidth(); + double dstHeight = newBounds.getY() + newBounds.getHeight(); + + if (dstWidth <= 0 || dstHeight <= 0) { + // awt.251=Transformed width ({0}) and height ({1}) should be + // greater than 0 + throw new RasterFormatException(Messages.getString("awt.251", dstWidth, dstHeight)); //$NON-NLS-1$ + } + + if (destCM != null) { + return new BufferedImage(destCM, destCM.createCompatibleWritableRaster((int)dstWidth, + (int)dstHeight), destCM.isAlphaPremultiplied(), null); + } + + ColorModel cm = src.getColorModel(); + + // Interpolation other than NN doesn't make any sense for index color + if (iType != TYPE_NEAREST_NEIGHBOR && cm instanceof IndexColorModel) { + return new BufferedImage((int)dstWidth, (int)dstHeight, BufferedImage.TYPE_INT_ARGB); + } + + // OK, we can get source color model + return new BufferedImage(cm, src.getRaster().createCompatibleWritableRaster((int)dstWidth, + (int)dstHeight), cm.isAlphaPremultiplied(), null); + } + + public WritableRaster createCompatibleDestRaster(Raster src) { + // Here approach is other then in createCompatibleDestImage - + // destination should include only + // transformed image, but not (0,0) in source coordinate system + + Rectangle2D newBounds = getBounds2D(src); + return src.createCompatibleWritableRaster((int)newBounds.getX(), (int)newBounds.getY(), + (int)newBounds.getWidth(), (int)newBounds.getHeight()); + } + + public final BufferedImage filter(BufferedImage src, BufferedImage dst) { + if (src == dst) { + // awt.252=Source can't be same as the destination + throw new IllegalArgumentException(Messages.getString("awt.252")); //$NON-NLS-1$ + } + + ColorModel srcCM = src.getColorModel(); + BufferedImage finalDst = null; + + if (srcCM instanceof IndexColorModel + && (iType != TYPE_NEAREST_NEIGHBOR || srcCM.getPixelSize() % 8 != 0)) { + src = ((IndexColorModel)srcCM).convertToIntDiscrete(src.getRaster(), true); + srcCM = src.getColorModel(); + } + + if (dst == null) { + dst = createCompatibleDestImage(src, srcCM); + } else { + if (!srcCM.equals(dst.getColorModel())) { + // Treat BufferedImage.TYPE_INT_RGB and + // BufferedImage.TYPE_INT_ARGB as same + if (!((src.getType() == BufferedImage.TYPE_INT_RGB || src.getType() == BufferedImage.TYPE_INT_ARGB) && (dst + .getType() == BufferedImage.TYPE_INT_RGB || dst.getType() == BufferedImage.TYPE_INT_ARGB))) { + finalDst = dst; + dst = createCompatibleDestImage(src, srcCM); + } + } + } + + // Skip alpha channel for TYPE_INT_RGB images + if (slowFilter(src.getRaster(), dst.getRaster()) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + // TODO - uncomment + // if (ippFilter(src.getRaster(), dst.getRaster(), src.getType()) != + // 0) + // throw new ImagingOpException ("Unable to transform source"); + } + + if (finalDst != null) { + Graphics2D g = finalDst.createGraphics(); + g.setComposite(AlphaComposite.Src); + g.drawImage(dst, 0, 0, null); + } else { + finalDst = dst; + } + + return finalDst; + } + + public final WritableRaster filter(Raster src, WritableRaster dst) { + if (src == dst) { + // awt.252=Source can't be same as the destination + throw new IllegalArgumentException(Messages.getString("awt.252")); //$NON-NLS-1$ + } + + if (dst == null) { + dst = createCompatibleDestRaster(src); + } else if (src.getNumBands() != dst.getNumBands()) { + // awt.253=Different number of bands in source and destination + throw new IllegalArgumentException(Messages.getString("awt.253")); //$NON-NLS-1$ + } + + if (slowFilter(src, dst) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + // TODO - uncomment + // if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM) != 0) + // throw new ImagingOpException("Unable to transform source"); + } + + return dst; + } + + // TODO remove when method is used + /** + * Ipp filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @param imageType + * the image type. + * @return the int. + */ + @SuppressWarnings("unused") + private int ippFilter(Raster src, WritableRaster dst, int imageType) { + int srcStride, dstStride; + boolean skipChannel = false; + int channels; + int offsets[] = null; + + switch (imageType) { + case BufferedImage.TYPE_INT_RGB: + case BufferedImage.TYPE_INT_BGR: { + channels = 4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; + skipChannel = true; + break; + } + + case BufferedImage.TYPE_INT_ARGB: + case BufferedImage.TYPE_INT_ARGB_PRE: + case BufferedImage.TYPE_4BYTE_ABGR: + case BufferedImage.TYPE_4BYTE_ABGR_PRE: { + channels = 4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; + break; + } + + case BufferedImage.TYPE_BYTE_GRAY: + case BufferedImage.TYPE_BYTE_INDEXED: { + channels = 1; + srcStride = src.getWidth(); + dstStride = dst.getWidth(); + break; + } + + case BufferedImage.TYPE_3BYTE_BGR: { + channels = 3; + srcStride = src.getWidth() * 3; + dstStride = dst.getWidth() * 3; + break; + } + + case BufferedImage.TYPE_USHORT_GRAY: // TODO - could be done in + // native code? + case BufferedImage.TYPE_USHORT_565_RGB: + case BufferedImage.TYPE_USHORT_555_RGB: + case BufferedImage.TYPE_BYTE_BINARY: { + return slowFilter(src, dst); + } + + default: { + SampleModel srcSM = src.getSampleModel(); + SampleModel dstSM = dst.getSampleModel(); + + if (srcSM instanceof PixelInterleavedSampleModel + && dstSM instanceof PixelInterleavedSampleModel) { + // Check PixelInterleavedSampleModel + if (srcSM.getDataType() != DataBuffer.TYPE_BYTE + || dstSM.getDataType() != DataBuffer.TYPE_BYTE) { + return slowFilter(src, dst); + } + + channels = srcSM.getNumBands(); // Have IPP functions for 1, + // 3 and 4 channels + if (channels != 1 && channels != 3 && channels != 4) { + return slowFilter(src, dst); + } + + int dataTypeSize = DataBuffer.getDataTypeSize(srcSM.getDataType()) / 8; + + srcStride = ((ComponentSampleModel)srcSM).getScanlineStride() * dataTypeSize; + dstStride = ((ComponentSampleModel)dstSM).getScanlineStride() * dataTypeSize; + } else if (srcSM instanceof SinglePixelPackedSampleModel + && dstSM instanceof SinglePixelPackedSampleModel) { + // Check SinglePixelPackedSampleModel + SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)srcSM; + SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel)dstSM; + + // No IPP function for this type + if (sppsm1.getDataType() == DataBuffer.TYPE_USHORT) { + return slowFilter(src, dst); + } + + channels = sppsm1.getNumBands(); + // Have IPP functions for 1, 3 and 4 channels + if (channels != 1 && channels != 3 && channels != 4) { + return slowFilter(src, dst); + } + + // Check compatibility of sample models + if (sppsm1.getDataType() != sppsm2.getDataType() + || !Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) + || !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())) { + return slowFilter(src, dst); + } + + for (int i = 0; i < channels; i++) { + if (sppsm1.getSampleSize(i) != 8) { + return slowFilter(src, dst); + } + } + + if (channels == 3) { + channels = 4; + } + + int dataTypeSize = DataBuffer.getDataTypeSize(sppsm1.getDataType()) / 8; + + srcStride = sppsm1.getScanlineStride() * dataTypeSize; + dstStride = sppsm2.getScanlineStride() * dataTypeSize; + } else { + return slowFilter(src, dst); + } + + // Fill offsets if there's a child raster + if (src.getParent() != null || dst.getParent() != null) { + if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0 + || dst.getSampleModelTranslateX() != 0 + || dst.getSampleModelTranslateY() != 0) { + offsets = new int[4]; + offsets[0] = -src.getSampleModelTranslateX() + src.getMinX(); + offsets[1] = -src.getSampleModelTranslateY() + src.getMinY(); + offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX(); + offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY(); + } + } + } + } + + double m00 = at.getScaleX(); + double m01 = at.getShearX(); + double m02 = at.getTranslateX(); + double m10 = at.getShearY(); + double m11 = at.getScaleY(); + double m12 = at.getTranslateY(); + + Object srcData, dstData; + AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance(); + try { + srcData = dbAccess.getData(src.getDataBuffer()); + dstData = dbAccess.getData(dst.getDataBuffer()); + } catch (IllegalArgumentException e) { + return -1; // Unknown data buffer type + } + + return ippAffineTransform(m00, m01, m02, m10, m11, m12, srcData, src.getWidth(), src + .getHeight(), srcStride, dstData, dst.getWidth(), dst.getHeight(), dstStride, + iType, channels, skipChannel, offsets); + } + + /** + * Slow filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @return the int. + */ + private int slowFilter(Raster src, WritableRaster dst) { + // TODO: make correct interpolation + // TODO: what if there are different data types? + + Rectangle srcBounds = src.getBounds(); + Rectangle dstBounds = dst.getBounds(); + Rectangle normDstBounds = new Rectangle(0, 0, dstBounds.width, dstBounds.height); + Rectangle bounds = getBounds2D(src).getBounds().intersection(normDstBounds); + + AffineTransform inv = null; + try { + inv = at.createInverse(); + } catch (NoninvertibleTransformException e) { + return -1; + } + + double[] m = new double[6]; + inv.getMatrix(m); + + int minSrcX = srcBounds.x; + int minSrcY = srcBounds.y; + int maxSrcX = srcBounds.x + srcBounds.width; + int maxSrcY = srcBounds.y + srcBounds.height; + + int minX = bounds.x + dstBounds.x; + int minY = bounds.y + dstBounds.y; + int maxX = minX + bounds.width; + int maxY = minY + bounds.height; + + int hx = (int)(m[0] * 256); + int hy = (int)(m[1] * 256); + int vx = (int)(m[2] * 256); + int vy = (int)(m[3] * 256); + int sx = (int)(m[4] * 256) + hx * bounds.x + vx * bounds.y + (srcBounds.x) * 256; + int sy = (int)(m[5] * 256) + hy * bounds.x + vy * bounds.y + (srcBounds.y) * 256; + + vx -= hx * bounds.width; + vy -= hy * bounds.width; + + if (src.getTransferType() == dst.getTransferType()) { + for (int y = minY; y < maxY; y++) { + for (int x = minX; x < maxX; x++) { + int px = sx >> 8; + int py = sy >> 8; + if (px >= minSrcX && py >= minSrcY && px < maxSrcX && py < maxSrcY) { + Object val = src.getDataElements(px, py, null); + dst.setDataElements(x, y, val); + } + sx += hx; + sy += hy; + } + sx += vx; + sy += vy; + } + } else { + float pixel[] = null; + for (int y = minY; y < maxY; y++) { + for (int x = minX; x < maxX; x++) { + int px = sx >> 8; + int py = sy >> 8; + if (px >= minSrcX && py >= minSrcY && px < maxSrcX && py < maxSrcY) { + pixel = src.getPixel(px, py, pixel); + dst.setPixel(x, y, pixel); + } + sx += hx; + sy += hy; + } + sx += vx; + sy += vy; + } + } + + return 0; + } + + /** + * Ipp affine transform. + * + * @param m00 + * the m00. + * @param m01 + * the m01. + * @param m02 + * the m02. + * @param m10 + * the m10. + * @param m11 + * the m11. + * @param m12 + * the m12. + * @param src + * the src. + * @param srcWidth + * the src width. + * @param srcHeight + * the src height. + * @param srcStride + * the src stride. + * @param dst + * the dst. + * @param dstWidth + * the dst width. + * @param dstHeight + * the dst height. + * @param dstStride + * the dst stride. + * @param iType + * the i type. + * @param channels + * the channels. + * @param skipChannel + * the skip channel. + * @param offsets + * the offsets. + * @return the int. + */ + private native int ippAffineTransform(double m00, double m01, double m02, double m10, + double m11, double m12, Object src, int srcWidth, int srcHeight, int srcStride, + Object dst, int dstWidth, int dstHeight, int dstStride, int iType, int channels, + boolean skipChannel, int offsets[]); +}
\ No newline at end of file diff --git a/awt/java/awt/image/AreaAveragingScaleFilter.java b/awt/java/awt/image/AreaAveragingScaleFilter.java new file mode 100644 index 0000000..7fb138e --- /dev/null +++ b/awt/java/awt/image/AreaAveragingScaleFilter.java @@ -0,0 +1,288 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.util.Arrays; + +/** + * The AreaAveragingScaleFilter class scales the source image using area + * averaging algorithm. This algorithm provides a source image with a new image + * containing the resampled image. + * + * @since Android 1.0 + */ +public class AreaAveragingScaleFilter extends ReplicateScaleFilter { + + /** + * The Constant rgbCM. + */ + private static final ColorModel rgbCM = ColorModel.getRGBdefault(); + + /** + * The Constant averagingFlags. + */ + private static final int averagingFlags = (ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES); + + /** + * The reset. + */ + private boolean reset = true; // Flag for used superclass filter + + /** + * The inited. + */ + private boolean inited = false; // All data inited + + /** + * The sum_r. + */ + private int sum_r[]; // Array for average Red samples + + /** + * The sum_g. + */ + private int sum_g[]; // Array for average Green samples + + /** + * The sum_b. + */ + private int sum_b[]; // Array for average Blue samples + + /** + * The sum_a. + */ + private int sum_a[]; // Array for average Alpha samples + + /** + * The buff. + */ + private int buff[]; // Stride buffer + + /** + * The avg factor. + */ + private int avgFactor; // Global averaging factor + + /** + * The cached dy. + */ + private int cachedDY; // Cached number of the destination scanline + + /** + * The cached dv rest. + */ + private int cachedDVRest; // Cached value of rest src scanlines for sum + + // pixel samples + // Because data if transferring by whole scanlines + // we are caching only Y coordinate values + + /** + * Instantiates a new AreaAveragingScaleFilter object which scales a source + * image with the specified width and height. + * + * @param width + * the scaled width of the image. + * @param height + * the scaled height of the image. + */ + public AreaAveragingScaleFilter(int width, int height) { + super(width, height); + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize) { + if (reset) { + super.setPixels(x, y, w, h, model, pixels, off, scansize); + } else { + setFilteredPixels(x, y, w, h, model, pixels, off, scansize); + } + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize) { + if (reset) { + super.setPixels(x, y, w, h, model, pixels, off, scansize); + } else { + setFilteredPixels(x, y, w, h, model, pixels, off, scansize); + } + } + + @Override + public void setHints(int hints) { + super.setHints(hints); + reset = ((hints & averagingFlags) != averagingFlags); + } + + /** + * This method implements the Area Averaging Scale filter. The description + * of algorithm is presented in Java API Specification. Arrays sum_r, sum_g, + * sum_b, sum_a have length equals width of destination image. In each + * array's element is accumulating pixel's component values, proportional to + * the area which source pixels will occupy in destination image. Then that + * values will divide by Global averaging factor (area of the destination + * image) for receiving average values of destination pixels. + * + * @param x + * the source pixels X coordinate. + * @param y + * the source pixels Y coordinate. + * @param w + * the width of the area of the source pixels. + * @param h + * the height of the area of the source pixels. + * @param model + * the color model of the source pixels. + * @param pixels + * the array of source pixels. + * @param off + * the offset into the source pixels array. + * @param scansize + * the length of scanline in the pixels array. + */ + private void setFilteredPixels(int x, int y, int w, int h, ColorModel model, Object pixels, + int off, int scansize) { + if (!inited) { + initialize(); + } + + int srcX, srcY, dx, dy; + int svRest, dvRest, shRest, dhRest, vDif, hDif; + + if (y == 0) { + dy = 0; + dvRest = srcHeight; + } else { + dy = cachedDY; + dvRest = cachedDVRest; + } + + srcY = y; + svRest = destHeight; + + int srcOff = off; + while (srcY < y + h) { + if (svRest < dvRest) { + vDif = svRest; + } else { + vDif = dvRest; + } + + srcX = 0; + dx = 0; + shRest = destWidth; + dhRest = srcWidth; + while (srcX < w) { + if (shRest < dhRest) { + hDif = shRest; + } else { + hDif = dhRest; + } + int avg = hDif * vDif; // calculation of contribution factor + + int rgb, pix; + if (pixels instanceof int[]) { + pix = ((int[])pixels)[srcOff + srcX]; + } else { + pix = ((byte[])pixels)[srcOff + srcX] & 0xff; + } + + rgb = model.getRGB(pix); + int a = rgb >>> 24; + int r = (rgb >> 16) & 0xff; + int g = (rgb >> 8) & 0xff; + int b = rgb & 0xff; + + // accumulating pixel's component values + sum_a[dx] += a * avg; + sum_r[dx] += r * avg; + sum_g[dx] += g * avg; + sum_b[dx] += b * avg; + + shRest -= hDif; + dhRest -= hDif; + + if (shRest == 0) { + srcX++; + shRest = destWidth; + } + + if (dhRest == 0) { + dx++; + dhRest = srcWidth; + } + } + + svRest -= vDif; + dvRest -= vDif; + + if (svRest == 0) { + svRest = destHeight; + srcY++; + srcOff += scansize; + } + + if (dvRest == 0) { + // averaging destination pixel's values + for (int i = 0; i < destWidth; i++) { + int a = (sum_a[i] / avgFactor) & 0xff; + int r = (sum_r[i] / avgFactor) & 0xff; + int g = (sum_g[i] / avgFactor) & 0xff; + int b = (sum_b[i] / avgFactor) & 0xff; + int frgb = (a << 24) | (r << 16) | (g << 8) | b; + buff[i] = frgb; + } + consumer.setPixels(0, dy, destWidth, 1, rgbCM, buff, 0, destWidth); + dy++; + dvRest = srcHeight; + Arrays.fill(sum_a, 0); + Arrays.fill(sum_r, 0); + Arrays.fill(sum_g, 0); + Arrays.fill(sum_b, 0); + } + + } + + cachedDY = dy; + cachedDVRest = dvRest; + + } + + /** + * Initialization of the auxiliary data. + */ + private void initialize() { + + sum_a = new int[destWidth]; + sum_r = new int[destWidth]; + sum_g = new int[destWidth]; + sum_b = new int[destWidth]; + + buff = new int[destWidth]; + outpixbuf = buff; + avgFactor = srcWidth * srcHeight; + + inited = true; + } +} diff --git a/awt/java/awt/image/AwtImageBackdoorAccessorImpl.java b/awt/java/awt/image/AwtImageBackdoorAccessorImpl.java new file mode 100644 index 0000000..6dffee8 --- /dev/null +++ b/awt/java/awt/image/AwtImageBackdoorAccessorImpl.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + * Created on 23.11.2005 + * + */ + +package java.awt.image; + +import java.awt.Image; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferDouble; +import java.awt.image.DataBufferFloat; +import java.awt.image.DataBufferInt; +import java.awt.image.DataBufferShort; +import java.awt.image.DataBufferUShort; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.gl.GLVolatileImage; +import org.apache.harmony.awt.gl.Surface; +import org.apache.harmony.awt.gl.image.DataBufferListener; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * This class not part of public API. It useful for receiving package private + * data from other packages. + * + * @since Android 1.0 + */ +class AwtImageBackdoorAccessorImpl extends AwtImageBackdoorAccessor { + + static void init() { + inst = new AwtImageBackdoorAccessorImpl(); + } + + @Override + public Surface getImageSurface(Image image) { + if (image instanceof BufferedImage) { + return ((BufferedImage)image).getImageSurface(); + } else if (image instanceof GLVolatileImage) { + return ((GLVolatileImage)image).getImageSurface(); + } + return null; + } + + @Override + public boolean isGrayPallete(IndexColorModel icm) { + return icm.isGrayPallete(); + } + + @Override + public Object getData(DataBuffer db) { + if (db instanceof DataBufferByte) { + return ((DataBufferByte)db).getData(); + } else if (db instanceof DataBufferUShort) { + return ((DataBufferUShort)db).getData(); + } else if (db instanceof DataBufferShort) { + return ((DataBufferShort)db).getData(); + } else if (db instanceof DataBufferInt) { + return ((DataBufferInt)db).getData(); + } else if (db instanceof DataBufferFloat) { + return ((DataBufferFloat)db).getData(); + } else if (db instanceof DataBufferDouble) { + return ((DataBufferDouble)db).getData(); + } else { + // awt.235=Wrong Data Buffer type : {0} + throw new IllegalArgumentException(Messages.getString("awt.235", //$NON-NLS-1$ + db.getClass())); + } + } + + @Override + public int[] getDataInt(DataBuffer db) { + if (db instanceof DataBufferInt) { + return ((DataBufferInt)db).getData(); + } + return null; + } + + @Override + public byte[] getDataByte(DataBuffer db) { + if (db instanceof DataBufferByte) { + return ((DataBufferByte)db).getData(); + } + return null; + } + + @Override + public short[] getDataShort(DataBuffer db) { + if (db instanceof DataBufferShort) { + return ((DataBufferShort)db).getData(); + } + return null; + } + + @Override + public short[] getDataUShort(DataBuffer db) { + if (db instanceof DataBufferUShort) { + return ((DataBufferUShort)db).getData(); + } + return null; + } + + @Override + public double[] getDataDouble(DataBuffer db) { + if (db instanceof DataBufferDouble) { + return ((DataBufferDouble)db).getData(); + } + return null; + } + + @Override + public float[] getDataFloat(DataBuffer db) { + if (db instanceof DataBufferFloat) { + return ((DataBufferFloat)db).getData(); + } + return null; + } + + @Override + public void addDataBufferListener(DataBuffer db, DataBufferListener listener) { + db.addDataBufferListener(listener); + } + + @Override + public void removeDataBufferListener(DataBuffer db) { + db.removeDataBufferListener(); + } + + @Override + public void validate(DataBuffer db) { + db.validate(); + } + + @Override + public void releaseData(DataBuffer db) { + db.releaseData(); + } +} diff --git a/awt/java/awt/image/BandCombineOp.java b/awt/java/awt/image/BandCombineOp.java new file mode 100644 index 0000000..da2cc89 --- /dev/null +++ b/awt/java/awt/image/BandCombineOp.java @@ -0,0 +1,658 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Sep 20, 2005 + */ + +package java.awt.image; + +import java.awt.*; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.Arrays; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The BandCombineOp class translates coordinates from coordinates in the source + * Raster to coordinates in the destination Raster by an arbitrary linear + * combination of the bands in a source Raster, using a specified matrix. The + * number of bands in the matrix should equal to the number of bands in the + * source Raster plus 1. + * + * @since Android 1.0 + */ +public class BandCombineOp implements RasterOp { + + /** + * The Constant offsets3c. + */ + static final int offsets3c[] = { + 16, 8, 0 + }; + + /** + * The Constant offsets4ac. + */ + static final int offsets4ac[] = { + 16, 8, 0, 24 + }; + + /** + * The Constant masks3c. + */ + static final int masks3c[] = { + 0xFF0000, 0xFF00, 0xFF + }; + + /** + * The Constant masks4ac. + */ + static final int masks4ac[] = { + 0xFF0000, 0xFF00, 0xFF, 0xFF000000 + }; + + /** + * The Constant piOffsets. + */ + private static final int piOffsets[] = { + 0, 1, 2 + }; + + /** + * The Constant piInvOffsets. + */ + private static final int piInvOffsets[] = { + 2, 1, 0 + }; + + /** + * The Constant TYPE_BYTE3C. + */ + private static final int TYPE_BYTE3C = 0; + + /** + * The Constant TYPE_BYTE4AC. + */ + private static final int TYPE_BYTE4AC = 1; + + /** + * The Constant TYPE_USHORT3C. + */ + private static final int TYPE_USHORT3C = 2; + + /** + * The Constant TYPE_SHORT3C. + */ + private static final int TYPE_SHORT3C = 3; + + /** + * The mx width. + */ + private int mxWidth; + + /** + * The mx height. + */ + private int mxHeight; + + /** + * The matrix. + */ + private float matrix[][]; + + /** + * The r hints. + */ + private RenderingHints rHints; + + static { + // XXX - todo + // System.loadLibrary("imageops"); + } + + /** + * Instantiates a new BandCombineOp object with the specified matrix. + * + * @param matrix + * the specified matrix for band combining. + * @param hints + * the RenderingHints. + */ + public BandCombineOp(float matrix[][], RenderingHints hints) { + this.mxHeight = matrix.length; + this.mxWidth = matrix[0].length; + this.matrix = new float[mxHeight][mxWidth]; + + for (int i = 0; i < mxHeight; i++) { + System.arraycopy(matrix[i], 0, this.matrix[i], 0, mxWidth); + } + + this.rHints = hints; + } + + public final RenderingHints getRenderingHints() { + return this.rHints; + } + + /** + * Gets the matrix associated with this BandCombineOp object. + * + * @return the matrix associated with this BandCombineOp object. + */ + public final float[][] getMatrix() { + float res[][] = new float[mxHeight][mxWidth]; + + for (int i = 0; i < mxHeight; i++) { + System.arraycopy(matrix[i], 0, res[i], 0, mxWidth); + } + + return res; + } + + public final Point2D getPoint2D(Point2D srcPoint, Point2D dstPoint) { + if (dstPoint == null) { + dstPoint = new Point2D.Float(); + } + + dstPoint.setLocation(srcPoint); + return dstPoint; + } + + public final Rectangle2D getBounds2D(Raster src) { + return src.getBounds(); + } + + public WritableRaster createCompatibleDestRaster(Raster src) { + int numBands = src.getNumBands(); + if (mxWidth != numBands && mxWidth != (numBands + 1) || numBands != mxHeight) { + // awt.254=Number of bands in the source raster ({0}) is + // incompatible with the matrix [{1}x{2}] + throw new IllegalArgumentException(Messages.getString("awt.254", //$NON-NLS-1$ + new Object[] { + numBands, mxWidth, mxHeight + })); + } + + return src.createCompatibleWritableRaster(src.getWidth(), src.getHeight()); + } + + public WritableRaster filter(Raster src, WritableRaster dst) { + int numBands = src.getNumBands(); + + if (mxWidth != numBands && mxWidth != (numBands + 1)) { + // awt.254=Number of bands in the source raster ({0}) is + // incompatible with the matrix [{1}x{2}] + throw new IllegalArgumentException(Messages.getString("awt.254", //$NON-NLS-1$ + new Object[] { + numBands, mxWidth, mxHeight + })); + } + + if (dst == null) { + dst = createCompatibleDestRaster(src); + } else if (dst.getNumBands() != mxHeight) { + // awt.255=Number of bands in the destination raster ({0}) is + // incompatible with the matrix [{1}x{2}] + throw new IllegalArgumentException(Messages.getString("awt.255", //$NON-NLS-1$ + new Object[] { + dst.getNumBands(), mxWidth, mxHeight + })); + } + + // XXX - todo + // if (ippFilter(src, dst) != 0) + if (verySlowFilter(src, dst) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + } + + return dst; + } + + /** + * The Class SampleModelInfo. + */ + private static final class SampleModelInfo { + + /** + * The channels. + */ + int channels; + + /** + * The channels order. + */ + int channelsOrder[]; + + /** + * The stride. + */ + int stride; + } + + /** + * Check sample model. + * + * @param sm + * the sm. + * @return the sample model info. + */ + private final SampleModelInfo checkSampleModel(SampleModel sm) { + SampleModelInfo ret = new SampleModelInfo(); + + if (sm instanceof PixelInterleavedSampleModel) { + // Check PixelInterleavedSampleModel + if (sm.getDataType() != DataBuffer.TYPE_BYTE) { + return null; + } + + ret.channels = sm.getNumBands(); + ret.stride = ((ComponentSampleModel)sm).getScanlineStride(); + ret.channelsOrder = ((ComponentSampleModel)sm).getBandOffsets(); + + } else if (sm instanceof SinglePixelPackedSampleModel) { + // Check SinglePixelPackedSampleModel + SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)sm; + + ret.channels = sppsm1.getNumBands(); + if (sppsm1.getDataType() != DataBuffer.TYPE_INT) { + return null; + } + + // Check sample models + for (int i = 0; i < ret.channels; i++) { + if (sppsm1.getSampleSize(i) != 8) { + return null; + } + } + + ret.channelsOrder = new int[ret.channels]; + int bitOffsets[] = sppsm1.getBitOffsets(); + for (int i = 0; i < ret.channels; i++) { + if (bitOffsets[i] % 8 != 0) { + return null; + } + + ret.channelsOrder[i] = bitOffsets[i] / 8; + } + + ret.channels = 4; + ret.stride = sppsm1.getScanlineStride() * 4; + } else { + return null; + } + + return ret; + } + + /** + * Slow filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @return the int. + */ + private final int slowFilter(Raster src, WritableRaster dst) { + int res = 0; + + SampleModelInfo srcInfo, dstInfo; + int offsets[] = null; + + srcInfo = checkSampleModel(src.getSampleModel()); + dstInfo = checkSampleModel(dst.getSampleModel()); + if (srcInfo == null || dstInfo == null) { + return verySlowFilter(src, dst); + } + + // Fill offsets if there's a child raster + if (src.getParent() != null || dst.getParent() != null) { + if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0 + || dst.getSampleModelTranslateX() != 0 || dst.getSampleModelTranslateY() != 0) { + offsets = new int[4]; + offsets[0] = -src.getSampleModelTranslateX() + src.getMinX(); + offsets[1] = -src.getSampleModelTranslateY() + src.getMinY(); + offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX(); + offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY(); + } + } + + int rmxWidth = (srcInfo.channels + 1); // width of the reordered matrix + float reorderedMatrix[] = new float[rmxWidth * dstInfo.channels]; + for (int j = 0; j < dstInfo.channels; j++) { + if (j >= dstInfo.channelsOrder.length) { + continue; + } + + for (int i = 0; i < srcInfo.channels; i++) { + if (i >= srcInfo.channelsOrder.length) { + break; + } + + reorderedMatrix[dstInfo.channelsOrder[j] * rmxWidth + srcInfo.channelsOrder[i]] = matrix[j][i]; + } + if (mxWidth == rmxWidth) { + reorderedMatrix[(dstInfo.channelsOrder[j] + 1) * rmxWidth - 1] = matrix[j][mxWidth - 1]; + } + } + + Object srcData, dstData; + AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance(); + try { + srcData = dbAccess.getData(src.getDataBuffer()); + dstData = dbAccess.getData(dst.getDataBuffer()); + } catch (IllegalArgumentException e) { + return -1; // Unknown data buffer type + } + + simpleCombineBands(srcData, src.getWidth(), src.getHeight(), srcInfo.stride, + srcInfo.channels, dstData, dstInfo.stride, dstInfo.channels, reorderedMatrix, + offsets); + + return res; + } + + /** + * Very slow filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @return the int. + */ + private int verySlowFilter(Raster src, WritableRaster dst) { + int numBands = src.getNumBands(); + + int srcMinX = src.getMinX(); + int srcY = src.getMinY(); + + int dstMinX = dst.getMinX(); + int dstY = dst.getMinY(); + + int dX = src.getWidth();// < dst.getWidth() ? src.getWidth() : + // dst.getWidth(); + int dY = src.getHeight();// < dst.getHeight() ? src.getHeight() : + // dst.getHeight(); + + float sample; + int srcPixels[] = new int[numBands * dX * dY]; + int dstPixels[] = new int[mxHeight * dX * dY]; + + srcPixels = src.getPixels(srcMinX, srcY, dX, dY, srcPixels); + + if (numBands == mxWidth) { + for (int i = 0, j = 0; i < srcPixels.length; i += numBands) { + for (int dstB = 0; dstB < mxHeight; dstB++) { + sample = 0f; + for (int srcB = 0; srcB < numBands; srcB++) { + sample += matrix[dstB][srcB] * srcPixels[i + srcB]; + } + dstPixels[j++] = (int)sample; + } + } + } else { + for (int i = 0, j = 0; i < srcPixels.length; i += numBands) { + for (int dstB = 0; dstB < mxHeight; dstB++) { + sample = 0f; + for (int srcB = 0; srcB < numBands; srcB++) { + sample += matrix[dstB][srcB] * srcPixels[i + srcB]; + } + dstPixels[j++] = (int)(sample + matrix[dstB][numBands]); + } + } + } + + dst.setPixels(dstMinX, dstY, dX, dY, dstPixels); + + return 0; + } + + // TODO remove when method is used + /** + * Ipp filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @return the int. + */ + @SuppressWarnings("unused") + private int ippFilter(Raster src, WritableRaster dst) { + boolean invertChannels; + boolean inPlace = (src == dst); + int type; + int srcStride, dstStride; + int offsets[] = null; + + int srcBands = src.getNumBands(); + int dstBands = dst.getNumBands(); + + if (dstBands != 3 + || (srcBands != 3 && !(srcBands == 4 && matrix[0][3] == 0 && matrix[1][3] == 0 && matrix[2][3] == 0))) { + return slowFilter(src, dst); + } + + SampleModel srcSM = src.getSampleModel(); + SampleModel dstSM = dst.getSampleModel(); + + if (srcSM instanceof SinglePixelPackedSampleModel + && dstSM instanceof SinglePixelPackedSampleModel) { + // Check SinglePixelPackedSampleModel + SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)srcSM; + SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel)dstSM; + + if (sppsm1.getDataType() != DataBuffer.TYPE_INT + || sppsm2.getDataType() != DataBuffer.TYPE_INT) { + return slowFilter(src, dst); + } + + // Check sample models + if (!Arrays.equals(sppsm2.getBitOffsets(), offsets3c) + || !Arrays.equals(sppsm2.getBitMasks(), masks3c)) { + return slowFilter(src, dst); + } + + if (srcBands == 3) { + if (!Arrays.equals(sppsm1.getBitOffsets(), offsets3c) + || !Arrays.equals(sppsm1.getBitMasks(), masks3c)) { + return slowFilter(src, dst); + } + } else if (srcBands == 4) { + if (!Arrays.equals(sppsm1.getBitOffsets(), offsets4ac) + || !Arrays.equals(sppsm1.getBitMasks(), masks4ac)) { + return slowFilter(src, dst); + } + } + + type = TYPE_BYTE4AC; + invertChannels = true; + + srcStride = sppsm1.getScanlineStride() * 4; + dstStride = sppsm2.getScanlineStride() * 4; + } else if (srcSM instanceof PixelInterleavedSampleModel + && dstSM instanceof PixelInterleavedSampleModel) { + if (srcBands != 3) { + return slowFilter(src, dst); + } + + int srcDataType = srcSM.getDataType(); + + switch (srcDataType) { + case DataBuffer.TYPE_BYTE: + type = TYPE_BYTE3C; + break; + case DataBuffer.TYPE_USHORT: + type = TYPE_USHORT3C; + break; + case DataBuffer.TYPE_SHORT: + type = TYPE_SHORT3C; + break; + default: + return slowFilter(src, dst); + } + + // Check PixelInterleavedSampleModel + PixelInterleavedSampleModel pism1 = (PixelInterleavedSampleModel)srcSM; + PixelInterleavedSampleModel pism2 = (PixelInterleavedSampleModel)dstSM; + + if (srcDataType != pism2.getDataType() || pism1.getPixelStride() != 3 + || pism2.getPixelStride() != 3 + || !Arrays.equals(pism1.getBandOffsets(), pism2.getBandOffsets())) { + return slowFilter(src, dst); + } + + if (Arrays.equals(pism1.getBandOffsets(), piInvOffsets)) { + invertChannels = true; + } else if (Arrays.equals(pism1.getBandOffsets(), piOffsets)) { + invertChannels = false; + } else { + return slowFilter(src, dst); + } + + int dataTypeSize = DataBuffer.getDataTypeSize(srcDataType) / 8; + + srcStride = pism1.getScanlineStride() * dataTypeSize; + dstStride = pism2.getScanlineStride() * dataTypeSize; + } else { // XXX - todo - IPP allows support for planar data also + return slowFilter(src, dst); + } + + // Fill offsets if there's a child raster + if (src.getParent() != null || dst.getParent() != null) { + if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0 + || dst.getSampleModelTranslateX() != 0 || dst.getSampleModelTranslateY() != 0) { + offsets = new int[4]; + offsets[0] = -src.getSampleModelTranslateX() + src.getMinX(); + offsets[1] = -src.getSampleModelTranslateY() + src.getMinY(); + offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX(); + offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY(); + } + } + + Object srcData, dstData; + AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance(); + try { + srcData = dbAccess.getData(src.getDataBuffer()); + dstData = dbAccess.getData(dst.getDataBuffer()); + } catch (IllegalArgumentException e) { + return -1; // Unknown data buffer type + } + + float ippMatrix[] = new float[12]; + + if (invertChannels) { + // IPP treats big endian integers like BGR, so we have to + // swap columns 1 and 3 and rows 1 and 3 + for (int i = 0; i < mxHeight; i++) { + ippMatrix[i * 4] = matrix[2 - i][2]; + ippMatrix[i * 4 + 1] = matrix[2 - i][1]; + ippMatrix[i * 4 + 2] = matrix[2 - i][0]; + + if (mxWidth == 4) { + ippMatrix[i * 4 + 3] = matrix[2 - i][3]; + } else if (mxWidth == 5) { + ippMatrix[i * 4 + 3] = matrix[2 - i][4]; + } + } + } else { + for (int i = 0; i < mxHeight; i++) { + ippMatrix[i * 4] = matrix[i][0]; + ippMatrix[i * 4 + 1] = matrix[i][1]; + ippMatrix[i * 4 + 2] = matrix[i][2]; + + if (mxWidth == 4) { + ippMatrix[i * 4 + 3] = matrix[i][3]; + } else if (mxWidth == 5) { + ippMatrix[i * 4 + 3] = matrix[i][4]; + } + } + } + + return ippColorTwist(srcData, src.getWidth(), src.getHeight(), srcStride, dstData, dst + .getWidth(), dst.getHeight(), dstStride, ippMatrix, type, offsets, inPlace); + } + + /** + * Ipp color twist. + * + * @param srcData + * the src data. + * @param srcWidth + * the src width. + * @param srcHeight + * the src height. + * @param srcStride + * the src stride. + * @param dstData + * the dst data. + * @param dstWidth + * the dst width. + * @param dstHeight + * the dst height. + * @param dstStride + * the dst stride. + * @param ippMatrix + * the ipp matrix. + * @param type + * the type. + * @param offsets + * the offsets. + * @param inPlace + * the in place. + * @return the int. + */ + private final native int ippColorTwist(Object srcData, int srcWidth, int srcHeight, + int srcStride, Object dstData, int dstWidth, int dstHeight, int dstStride, + float ippMatrix[], int type, int offsets[], boolean inPlace); + + /** + * Simple combine bands. + * + * @param srcData + * the src data. + * @param srcWidth + * the src width. + * @param srcHeight + * the src height. + * @param srcStride + * the src stride. + * @param srcChannels + * the src channels. + * @param dstData + * the dst data. + * @param dstStride + * the dst stride. + * @param dstChannels + * the dst channels. + * @param m + * the m. + * @param offsets + * the offsets. + * @return the int. + */ + private final native int simpleCombineBands(Object srcData, int srcWidth, int srcHeight, + int srcStride, int srcChannels, Object dstData, int dstStride, int dstChannels, + float m[], int offsets[]); +} diff --git a/awt/java/awt/image/BandedSampleModel.java b/awt/java/awt/image/BandedSampleModel.java new file mode 100644 index 0000000..0aa30d7 --- /dev/null +++ b/awt/java/awt/image/BandedSampleModel.java @@ -0,0 +1,425 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The BandedSampleModel class provides samples of pixels in an image which is + * stored in a band interleaved method. Each pixel's sample takes one data + * element of the DataBuffer. The pixel stride for a BandedSampleModel is one. + * + * @since Android 1.0 + */ +public final class BandedSampleModel extends ComponentSampleModel { + + /** + * Creates the indices. + * + * @param numBands + * the num bands. + * @return the int[]. + */ + private static int[] createIndices(int numBands) { + int indices[] = new int[numBands]; + for (int i = 0; i < numBands; i++) { + indices[i] = i; + } + return indices; + } + + /** + * Creates the offsets. + * + * @param numBands + * the num bands. + * @return the int[]. + */ + private static int[] createOffsets(int numBands) { + int offsets[] = new int[numBands]; + for (int i = 0; i < numBands; i++) { + offsets[i] = 0; + } + return offsets; + } + + /** + * Instantiates a new BandedSampleModel object with the specified data type + * of samples, the width, height and bands number of image data. + * + * @param dataType + * the data type of samples. + * @param w + * the width of image data. + * @param h + * the height of image data. + * @param numBands + * the number of bands. + */ + public BandedSampleModel(int dataType, int w, int h, int numBands) { + this(dataType, w, h, w, BandedSampleModel.createIndices(numBands), BandedSampleModel + .createOffsets(numBands)); + } + + /** + * Instantiates a new BandedSampleModel object with the specified data type + * of samples, the width, height and bands number of image data. + * + * @param dataType + * the data type of samples. + * @param w + * the width of image data. + * @param h + * the height of image data. + * @param scanlineStride + * the scanline stride of the of the image data. + * @param bankIndices + * the array of the bank indices. + * @param bandOffsets + * the array of the band offsets. + */ + public BandedSampleModel(int dataType, int w, int h, int scanlineStride, int bankIndices[], + int bandOffsets[]) { + super(dataType, w, h, 1, scanlineStride, bankIndices, bandOffsets); + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + return new BandedSampleModel(dataType, w, h, w, bankIndices, bandOffsets); + } + + @Override + public DataBuffer createDataBuffer() { + DataBuffer data = null; + int size = scanlineStride * height; + + switch (dataType) { + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(size, numBanks); + break; + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + data = new DataBufferShort(size, numBanks); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(size, numBanks); + break; + case DataBuffer.TYPE_FLOAT: + data = new DataBufferFloat(size, numBanks); + break; + case DataBuffer.TYPE_DOUBLE: + data = new DataBufferDouble(size, numBanks); + break; + } + + return data; + + } + + @Override + public SampleModel createSubsetSampleModel(int[] bands) { + if (bands.length > numBands) { + // awt.64=The number of the bands in the subset is greater than the + // number of bands in the sample model + throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$ + } + + int indices[] = new int[bands.length]; + int offsets[] = new int[bands.length]; + + for (int i = 0; i < bands.length; i++) { + indices[i] = bankIndices[bands[i]]; + offsets[i] = bandOffsets[bands[i]]; + } + + return new BandedSampleModel(dataType, width, height, scanlineStride, indices, offsets); + } + + @Override + public Object getDataElements(int x, int y, Object obj, DataBuffer data) { + switch (dataType) { + case DataBuffer.TYPE_BYTE: { + byte bdata[]; + + if (obj == null) { + bdata = new byte[numBands]; + } else { + bdata = (byte[])obj; + } + + for (int i = 0; i < numBands; i++) { + bdata[i] = (byte)getSample(x, y, i, data); + } + + obj = bdata; + break; + } + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: { + short sdata[]; + + if (obj == null) { + sdata = new short[numBands]; + } else { + sdata = (short[])obj; + } + + for (int i = 0; i < numBands; i++) { + sdata[i] = (short)getSample(x, y, i, data); + } + + obj = sdata; + break; + } + case DataBuffer.TYPE_INT: { + int idata[]; + + if (obj == null) { + idata = new int[numBands]; + } else { + idata = (int[])obj; + } + + for (int i = 0; i < numBands; i++) { + idata[i] = getSample(x, y, i, data); + } + + obj = idata; + break; + } + case DataBuffer.TYPE_FLOAT: { + float fdata[]; + + if (obj == null) { + fdata = new float[numBands]; + } else { + fdata = (float[])obj; + } + + for (int i = 0; i < numBands; i++) { + fdata[i] = getSampleFloat(x, y, i, data); + } + + obj = fdata; + break; + } + case DataBuffer.TYPE_DOUBLE: { + double ddata[]; + + if (obj == null) { + ddata = new double[numBands]; + } else { + ddata = (double[])obj; + } + + for (int i = 0; i < numBands; i++) { + ddata[i] = getSampleDouble(x, y, i, data); + } + + obj = ddata; + break; + } + } + + return obj; + } + + @Override + public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { + int pixel[]; + if (iArray == null) { + pixel = new int[numBands]; + } else { + pixel = iArray; + } + + for (int i = 0; i < numBands; i++) { + pixel[i] = getSample(x, y, i, data); + } + + return pixel; + } + + @Override + public int getSample(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + return data.getElem(bankIndices[b], y * scanlineStride + x + bandOffsets[b]); + } + + @Override + public double getSampleDouble(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + return data.getElemDouble(bankIndices[b], y * scanlineStride + x + bandOffsets[b]); + } + + @Override + public float getSampleFloat(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + return data.getElemFloat(bankIndices[b], y * scanlineStride + x + bandOffsets[b]); + } + + @Override + public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { + int samples[]; + int idx = 0; + + if (iArray == null) { + samples = new int[w * h]; + } else { + samples = iArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + samples[idx++] = getSample(j, i, b, data); + } + } + + return samples; + } + + @Override + public int hashCode() { + int hash = super.hashCode(); + int tmp = hash >>> 8; + hash <<= 8; + hash |= tmp; + + return hash ^ 0x55; + } + + @Override + public void setDataElements(int x, int y, Object obj, DataBuffer data) { + switch (dataType) { + case DataBuffer.TYPE_BYTE: + byte bdata[] = (byte[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, bdata[i] & 0xff, data); + } + break; + + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short sdata[] = (short[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, sdata[i] & 0xffff, data); + } + break; + + case DataBuffer.TYPE_INT: + int idata[] = (int[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, idata[i], data); + } + break; + + case DataBuffer.TYPE_FLOAT: + float fdata[] = (float[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, fdata[i], data); + } + break; + + case DataBuffer.TYPE_DOUBLE: + double ddata[] = (double[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, ddata[i], data); + } + break; + } + } + + @Override + public void setPixel(int x, int y, int iArray[], DataBuffer data) { + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, iArray[i], data); + } + } + + @Override + public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { + int idx = 0; + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + setSample(j, i, n, iArray[idx++], data); + } + } + } + } + + @Override + public void setSample(int x, int y, int b, double s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + data.setElemDouble(bankIndices[b], y * scanlineStride + x + bandOffsets[b], s); + } + + @Override + public void setSample(int x, int y, int b, float s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + data.setElemFloat(bankIndices[b], y * scanlineStride + x + bandOffsets[b], s); + } + + @Override + public void setSample(int x, int y, int b, int s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + data.setElem(bankIndices[b], y * scanlineStride + x + bandOffsets[b], s); + } + + @Override + public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { + int idx = 0; + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + setSample(j, i, b, iArray[idx++], data); + } + } + + } + +} diff --git a/awt/java/awt/image/BufferStrategy.java b/awt/java/awt/image/BufferStrategy.java new file mode 100644 index 0000000..3c8779d --- /dev/null +++ b/awt/java/awt/image/BufferStrategy.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.BufferCapabilities; +import java.awt.Graphics; + +/** + * The BufferStrategy abstract class provides an opportunity to organize the + * buffers for a Canvas or Window. The BufferStrategy implementation depends on + * hardware and software limitations. These limitations are detectable through + * the capabilities object which can be obtained by the GraphicsConfiguration of + * the Canvas or Window. + * + * @since Android 1.0 + */ +public abstract class BufferStrategy { + + /** + * Returns true if the drawing buffer was lost since the last call of + * getDrawGraphics. + * + * @return true if the drawing buffer was lost since the last call of + * getDrawGraphics, false otherwise. + */ + public abstract boolean contentsLost(); + + /** + * Returns true if the drawing buffer is restored from a lost state. + * + * @return true if the drawing buffer is restored from a lost state, false + * otherwise. + */ + public abstract boolean contentsRestored(); + + /** + * Gets the BufferCapabilities of BufferStrategy. + * + * @return the BufferCapabilities of BufferStrategy. + */ + public abstract BufferCapabilities getCapabilities(); + + /** + * Gets the Graphics object to use to draw to the buffer. + * + * @return the Graphics object to use to draw to the buffer. + */ + public abstract Graphics getDrawGraphics(); + + /** + * Shows the next available buffer. + */ + public abstract void show(); + +} diff --git a/awt/java/awt/image/BufferedImage.java b/awt/java/awt/image/BufferedImage.java new file mode 100644 index 0000000..c9d58d9 --- /dev/null +++ b/awt/java/awt/image/BufferedImage.java @@ -0,0 +1,952 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import com.android.internal.awt.AndroidGraphics2D; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.apache.harmony.awt.gl.ImageSurface; +import org.apache.harmony.awt.gl.Surface; +import org.apache.harmony.awt.gl.image.BufferedImageSource; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The BufferedImage class describes an Image which contains a buffer of image + * data and includes a ColorModel and a Raster for this data. This class + * provides methods for obtaining and setting the Raster and for manipulating + * the ColorModel parameters. + * + * @since Android 1.0 + */ +public class BufferedImage extends Image implements WritableRenderedImage, Transparency { + + /** + * The Constant TYPE_CUSTOM indicates that Image type is unknown. + */ + public static final int TYPE_CUSTOM = 0; + + /** + * The Constant TYPE_INT_RGB indicates an image with 8 bit RGB color + * components, it has a DirectColorModel without alpha. + */ + public static final int TYPE_INT_RGB = 1; + + /** + * The Constant TYPE_INT_ARGB indicates an image with 8 bit RGBA color + * components, it has a DirectColorModel with alpha. + */ + public static final int TYPE_INT_ARGB = 2; + + /** + * The Constant TYPE_INT_ARGB_PRE indicates an image with 8 bit RGBA color + * components, it has a DirectColorModel with alpha, and image data is + * pre-multiplied by alpha. + */ + public static final int TYPE_INT_ARGB_PRE = 3; + + /** + * The Constant TYPE_INT_BGR indicates an image with 8 bit RGB color + * components, BGR color model (with the colors Blue, Green, and Red). There + * is no alpha. The image has a DirectColorModel. + */ + public static final int TYPE_INT_BGR = 4; + + /** + * The Constant TYPE_3BYTE_BGR indicates an image with 8 bit RGB color + * components, BGR color model (with the colors Blue, Green, and Red stored + * in 3 bytes). There is no alpha. The image has a ComponentColorModel. + */ + public static final int TYPE_3BYTE_BGR = 5; + + /** + * The Constant TYPE_4BYTE_ABGR indicates an image with 8 bit RGBA color + * components stored in 3 bytes and 1 byte of alpha. It has a + * ComponentColorModel with alpha. + */ + public static final int TYPE_4BYTE_ABGR = 6; + + /** + * The Constant TYPE_4BYTE_ABGR_PRE indicates an image with 8 bit RGBA color + * components stored in 3 bytes and 1 byte for alpha. The image has a + * ComponentColorModel with alpha. The color data is pre-multiplied with + * alpha. + */ + public static final int TYPE_4BYTE_ABGR_PRE = 7; + + /** + * The Constant TYPE_USHORT_565_RGB indicates an image with 565 RGB color + * components (5-bits red, 6-bits green, 5-bits blue) with no alpha. This + * image has a DirectColorModel. + */ + public static final int TYPE_USHORT_565_RGB = 8; + + /** + * The Constant TYPE_USHORT_555_RGB indicates an image with 555 RGB color + * components (5-bits red, 5-bits green, 5-bits blue) with no alpha. This + * image has a DirectColorModel. + */ + public static final int TYPE_USHORT_555_RGB = 9; + + /** + * The Constant TYPE_BYTE_GRAY indicates a unsigned byte image. This image + * has a ComponentColorModel with a CS_GRAY ColorSpace. + */ + public static final int TYPE_BYTE_GRAY = 10; + + /** + * The Constant TYPE_USHORT_GRAY indicates an unsigned short image. This + * image has a ComponentColorModel with a CS_GRAY ColorSpace. + */ + public static final int TYPE_USHORT_GRAY = 11; + + /** + * The Constant TYPE_BYTE_BINARY indicates an opaque byte-packed 1, 2 or 4 + * bit image. The image has an IndexColorModel without alpha. + */ + public static final int TYPE_BYTE_BINARY = 12; + + /** + * The Constant TYPE_BYTE_INDEXED indicates an indexed byte image. + */ + public static final int TYPE_BYTE_INDEXED = 13; + + /** + * The Constant ALPHA_MASK. + */ + private static final int ALPHA_MASK = 0xff000000; + + /** + * The Constant RED_MASK. + */ + private static final int RED_MASK = 0x00ff0000; + + /** + * The Constant GREEN_MASK. + */ + private static final int GREEN_MASK = 0x0000ff00; + + /** + * The Constant BLUE_MASK. + */ + private static final int BLUE_MASK = 0x000000ff; + + /** + * The Constant RED_BGR_MASK. + */ + private static final int RED_BGR_MASK = 0x000000ff; + + /** + * The Constant GREEN_BGR_MASK. + */ + private static final int GREEN_BGR_MASK = 0x0000ff00; + + /** + * The Constant BLUE_BGR_MASK. + */ + private static final int BLUE_BGR_MASK = 0x00ff0000; + + /** + * The Constant RED_565_MASK. + */ + private static final int RED_565_MASK = 0xf800; + + /** + * The Constant GREEN_565_MASK. + */ + private static final int GREEN_565_MASK = 0x07e0; + + /** + * The Constant BLUE_565_MASK. + */ + private static final int BLUE_565_MASK = 0x001f; + + /** + * The Constant RED_555_MASK. + */ + private static final int RED_555_MASK = 0x7c00; + + /** + * The Constant GREEN_555_MASK. + */ + private static final int GREEN_555_MASK = 0x03e0; + + /** + * The Constant BLUE_555_MASK. + */ + private static final int BLUE_555_MASK = 0x001f; + + /** + * The cm. + */ + private ColorModel cm; + + /** + * The raster. + */ + private final WritableRaster raster; + + /** + * The image type. + */ + private final int imageType; + + /** + * The properties. + */ + private Hashtable<?, ?> properties; + + // Surface of the Buffered Image - used for blitting one Buffered Image + // on the other one or on the Component + /** + * The image surf. + */ + private final ImageSurface imageSurf; + + /** + * Instantiates a new BufferedImage with the specified ColorModel, and + * WritableRaster objects. The Raster data can be be divided or multiplied + * by alpha. It depends on the alphaPremultiplied state in the ColorModel. + * + * @param cm + * the ColorModel of the new image. + * @param raster + * the WritableRaster of the new image. + * @param isRasterPremultiplied + * if true the data of the specified Raster is pre-multiplied by + * alpha. + * @param properties + * the properties of new Image. + */ + public BufferedImage(ColorModel cm, WritableRaster raster, boolean isRasterPremultiplied, + Hashtable<?, ?> properties) { + if (!cm.isCompatibleRaster(raster)) { + // awt.4D=The raster is incompatible with this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$ + } + + if (raster.getMinX() != 0 || raster.getMinY() != 0) { + // awt.228=minX or minY of this raster not equal to zero + throw new IllegalArgumentException(Messages.getString("awt.228")); //$NON-NLS-1$ + } + + this.cm = cm; + this.raster = raster; + this.properties = properties; + + coerceData(isRasterPremultiplied); + + imageType = Surface.getType(cm, raster); + + imageSurf = createImageSurface(imageType); + } + + /** + * Instantiates a new BufferedImage with the specified width, height + * predefined image type (TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED) and the + * specified IndexColorModel. + * + * @param width + * the width of new image. + * @param height + * the height of new image. + * @param imageType + * the predefined image type. + * @param cm + * the specified IndexColorModel. + */ + public BufferedImage(int width, int height, int imageType, IndexColorModel cm) { + switch (imageType) { + case TYPE_BYTE_BINARY: + if (cm.hasAlpha()) { + // awt.227=This image type can't have alpha + throw new IllegalArgumentException(Messages.getString("awt.227")); //$NON-NLS-1$ + } + int pixel_bits = 0; + int mapSize = cm.getMapSize(); + if (mapSize <= 2) { + pixel_bits = 1; + } else if (mapSize <= 4) { + pixel_bits = 2; + } else if (mapSize <= 16) { + pixel_bits = 4; + } else { + // awt.221=The imageType is TYPE_BYTE_BINARY and the color + // map has more than 16 entries + throw new IllegalArgumentException(Messages.getString("awt.221")); //$NON-NLS-1$ + } + + raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width, height, 1, + pixel_bits, null); + break; + + case TYPE_BYTE_INDEXED: + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 1, + null); + break; + + default: + // awt.222=The imageType is not TYPE_BYTE_BINARY or + // TYPE_BYTE_INDEXED + throw new IllegalArgumentException(Messages.getString("awt.222")); //$NON-NLS-1$ + + } + + if (!cm.isCompatibleRaster(raster)) { + // awt.223=The imageType is not compatible with ColorModel + throw new IllegalArgumentException(Messages.getString("awt.223")); //$NON-NLS-1$ + } + + this.cm = cm; + this.imageType = imageType; + imageSurf = createImageSurface(imageType); + + } + + /** + * Instantiates a new BufferedImage with the specified width, height and + * predefined image type. + * + * @param width + * the width of new image. + * @param height + * the height of new image. + * @param imageType + * the predefined image type. + */ + public BufferedImage(int width, int height, int imageType) { + + switch (imageType) { + case TYPE_INT_RGB: + cm = new DirectColorModel(24, RED_MASK, GREEN_MASK, BLUE_MASK); + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_INT_ARGB: + cm = ColorModel.getRGBdefault(); + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_INT_ARGB_PRE: + cm = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 32, RED_MASK, + GREEN_MASK, BLUE_MASK, ALPHA_MASK, true, DataBuffer.TYPE_INT); + + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_INT_BGR: + cm = new DirectColorModel(24, RED_BGR_MASK, GREEN_BGR_MASK, BLUE_BGR_MASK); + + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_3BYTE_BGR: { + int bits[] = { + 8, 8, 8 + }; + int bandOffsets[] = { + 2, 1, 0 + }; + cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits, + false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); + + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, + width * 3, 3, bandOffsets, null); + } + break; + + case TYPE_4BYTE_ABGR: { + int bits[] = { + 8, 8, 8, 8 + }; + int bandOffsets[] = { + 3, 2, 1, 0 + }; + cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits, + true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE); + + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, + width * 4, 4, bandOffsets, null); + } + break; + + case TYPE_4BYTE_ABGR_PRE: { + int bits[] = { + 8, 8, 8, 8 + }; + int bandOffsets[] = { + 3, 2, 1, 0 + }; + cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits, + true, true, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE); + + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, + width * 4, 4, bandOffsets, null); + } + break; + + case TYPE_USHORT_565_RGB: + cm = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 16, + RED_565_MASK, GREEN_565_MASK, BLUE_565_MASK, 0, false, + DataBuffer.TYPE_USHORT); + + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_USHORT_555_RGB: + cm = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 15, + RED_555_MASK, GREEN_555_MASK, BLUE_555_MASK, 0, false, + DataBuffer.TYPE_USHORT); + + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_BYTE_GRAY: { + int bits[] = { + 8 + }; + cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), bits, + false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); + + raster = cm.createCompatibleWritableRaster(width, height); + } + break; + + case TYPE_USHORT_GRAY: { + int bits[] = { + 16 + }; + cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), bits, + false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT); + raster = cm.createCompatibleWritableRaster(width, height); + } + break; + + case TYPE_BYTE_BINARY: { + int colorMap[] = { + 0, 0xffffff + }; + cm = new IndexColorModel(1, 2, colorMap, 0, false, -1, DataBuffer.TYPE_BYTE); + + raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width, height, 1, 1, null); + } + break; + + case TYPE_BYTE_INDEXED: { + int colorMap[] = new int[256]; + int i = 0; + for (int r = 0; r < 256; r += 51) { + for (int g = 0; g < 256; g += 51) { + for (int b = 0; b < 256; b += 51) { + colorMap[i] = (r << 16) | (g << 8) | b; + i++; + } + } + } + + int gray = 0x12; + for (; i < 256; i++, gray += 6) { + colorMap[i] = (gray << 16) | (gray << 8) | gray; + } + cm = new IndexColorModel(8, 256, colorMap, 0, false, -1, DataBuffer.TYPE_BYTE); + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 1, + null); + + } + break; + default: + // awt.224=Unknown image type + throw new IllegalArgumentException(Messages.getString("awt.224")); //$NON-NLS-1$ + } + this.imageType = imageType; + imageSurf = createImageSurface(imageType); + } + + @Override + public Object getProperty(String name, ImageObserver observer) { + return getProperty(name); + } + + public Object getProperty(String name) { + if (name == null) { + // awt.225=Property name is null + throw new NullPointerException(Messages.getString("awt.225")); //$NON-NLS-1$ + } + if (properties == null) { + return Image.UndefinedProperty; + } + Object property = properties.get(name); + if (property == null) { + property = Image.UndefinedProperty; + } + return property; + } + + public WritableRaster copyData(WritableRaster outRaster) { + if (outRaster == null) { + outRaster = Raster.createWritableRaster(raster.getSampleModel(), new Point(raster + .getSampleModelTranslateX(), raster.getSampleModelTranslateY())); + } + + int w = outRaster.getWidth(); + int h = outRaster.getHeight(); + int minX = outRaster.getMinX(); + int minY = outRaster.getMinY(); + + Object data = null; + + data = raster.getDataElements(minX, minY, w, h, data); + outRaster.setDataElements(minX, minY, w, h, data); + + return outRaster; + } + + public Raster getData(Rectangle rect) { + int minX = rect.x; + int minY = rect.y; + int w = rect.width; + int h = rect.height; + + SampleModel sm = raster.getSampleModel(); + SampleModel nsm = sm.createCompatibleSampleModel(w, h); + WritableRaster outr = Raster.createWritableRaster(nsm, rect.getLocation()); + Object data = null; + + data = raster.getDataElements(minX, minY, w, h, data); + outr.setDataElements(minX, minY, w, h, data); + return outr; + } + + public Vector<RenderedImage> getSources() { + return null; + } + + public String[] getPropertyNames() { + if (properties == null) { + return null; + } + Vector<String> v = new Vector<String>(); + for (Enumeration<?> e = properties.keys(); e.hasMoreElements();) { + try { + v.add((String)e.nextElement()); + } catch (ClassCastException ex) { + } + } + int size = v.size(); + if (size > 0) { + String names[] = new String[size]; + for (int i = 0; i < size; i++) { + names[i] = v.elementAt(i); + } + return names; + } + return null; + } + + /** + * Returns the string representation of this BufferedImage object. + * + * @return the string representation of this BufferedImage object. + */ + @Override + public String toString() { + return "BufferedImage@" + Integer.toHexString(hashCode()) + //$NON-NLS-1$ + ": type = " + imageType + " " + cm + " " + raster; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + public WritableRaster getWritableTile(int tileX, int tileY) { + return raster; + } + + /** + * Gets the WritableRaster of this BufferedImage. + * + * @return the WritableRaster of this BufferedImage. + */ + public WritableRaster getRaster() { + return raster; + } + + /** + * Gets a WritableRaster object which contains the alpha channel of + * BufferedImage object with ColorModel objects that supports a separate + * alpha channel such as ComponentColorModel or DirectColorModel. + * + * @return the WritableRaster object which contains the alpha channel of + * this BufferedImage. + */ + public WritableRaster getAlphaRaster() { + return cm.getAlphaRaster(raster); + } + + public void removeTileObserver(TileObserver to) { + } + + public void addTileObserver(TileObserver to) { + } + + public SampleModel getSampleModel() { + return raster.getSampleModel(); + } + + public void setData(Raster r) { + + Rectangle from = r.getBounds(); + Rectangle to = raster.getBounds(); + Rectangle intersection = to.intersection(from); + + int minX = intersection.x; + int minY = intersection.y; + int w = intersection.width; + int h = intersection.height; + + Object data = null; + + data = r.getDataElements(minX, minY, w, h, data); + raster.setDataElements(minX, minY, w, h, data); + } + + public Raster getTile(int tileX, int tileY) { + if (tileX == 0 && tileY == 0) { + return raster; + } + // awt.226=Both tileX and tileY are not equal to 0 + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.226")); //$NON-NLS-1$ + } + + public Raster getData() { + int w = raster.getWidth(); + int h = raster.getHeight(); + int minX = raster.getMinX(); + int minY = raster.getMinY(); + + WritableRaster outr = Raster.createWritableRaster(raster.getSampleModel(), new Point(raster + .getSampleModelTranslateX(), raster.getSampleModelTranslateY())); + + Object data = null; + + data = raster.getDataElements(minX, minY, w, h, data); + outr.setDataElements(minX, minY, w, h, data); + + return outr; + } + + @Override + public ImageProducer getSource() { + return new BufferedImageSource(this, properties); + } + + @Override + public int getWidth(ImageObserver observer) { + return raster.getWidth(); + } + + @Override + public int getHeight(ImageObserver observer) { + return raster.getHeight(); + } + + public ColorModel getColorModel() { + return cm; + } + + /** + * Gets the rectangular area of this BufferedImage as a subimage. + * + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @param w + * the width of the subimage. + * @param h + * the height of the subimage. + * @return the BufferedImage. + */ + public BufferedImage getSubimage(int x, int y, int w, int h) { + WritableRaster wr = raster.createWritableChild(x, y, w, h, 0, 0, null); + return new BufferedImage(cm, wr, cm.isAlphaPremultiplied(), properties); + } + + public Point[] getWritableTileIndices() { + Point points[] = new Point[1]; + points[0] = new Point(0, 0); + return points; + } + + /** + * Creates the Graphics2D object which allows to draw into this + * BufferedImage. + * + * @return the graphics2D object. + */ + public Graphics2D createGraphics() { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + // return ge.createGraphics(this); + // ???AWT hack, FIXME + // return AndroidGraphics2D.getInstance(); + // throw new RuntimeException("Not implemented!"); + return null; + } + + @Override + public Graphics getGraphics() { + return createGraphics(); + } + + /** + * Coerces the data to achieve the state which is specified by the + * isAlphaPremultiplied variable. + * + * @param isAlphaPremultiplied + * the is alpha pre-multiplied state. + */ + public void coerceData(boolean isAlphaPremultiplied) { + if (cm.hasAlpha() && cm.isAlphaPremultiplied() != isAlphaPremultiplied) { + cm = cm.coerceData(raster, isAlphaPremultiplied); + } + } + + /** + * Gets an array of colors in the TYPE_INT_ARGB color model and default sRGB + * color space of the specified area of this BufferedImage. The result array + * is composed by the following algorithm: + * <p> + * pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)] + * </p> + * + * @param startX + * the start X area coordinate. + * @param startY + * the start Y area coordinate. + * @param w + * the width of the area. + * @param h + * the height of the area. + * @param rgbArray + * the result array will be stored to this array. + * @param offset + * the offset of the rgbArray array. + * @param scansize + * the scanline stride for the rgbArray. + * @return an array of colors for the specified area. + */ + public int[] getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, + int scansize) { + if (rgbArray == null) { + rgbArray = new int[offset + h * scansize]; + } + + int off = offset; + for (int y = startY; y < startY + h; y++, off += scansize) { + int i = off; + for (int x = startX; x < startX + w; x++, i++) { + rgbArray[i] = cm.getRGB(raster.getDataElements(x, y, null)); + } + } + return rgbArray; + } + + /** + * Sets RGB values from the specified array to the specified BufferedImage + * area. The pixels are in the default RGB color model (TYPE_INT_ARGB) and + * default sRGB color space. + * + * @param startX + * the start X coordinate. + * @param startY + * the start Y coordinate. + * @param w + * the width of the BufferedImage area. + * @param h + * the height of the BufferedImage area. + * @param rgbArray + * the array of RGB values. + * @param offset + * the offset of the rgbArray array. + * @param scansize + * the scanline stride for the rgbArray. + */ + public void setRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, + int scansize) { + int off = offset; + for (int y = startY; y < startY + h; y++, off += scansize) { + int i = off; + for (int x = startX; x < startX + w; x++, i++) { + raster.setDataElements(x, y, cm.getDataElements(rgbArray[i], null)); + } + } + } + + /** + * Sets a the specified RGB value to the specified pixel of this + * BufferedImage. The pixel should be in the default RGB color model + * (TYPE_INT_ARGB) and default sRGB color space. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param rgb + * the RGB value to be set. + */ + public synchronized void setRGB(int x, int y, int rgb) { + raster.setDataElements(x, y, cm.getDataElements(rgb, null)); + } + + public boolean isTileWritable(int tileX, int tileY) { + if (tileX == 0 && tileY == 0) { + return true; + } + // awt.226=Both tileX and tileY are not equal to 0 + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.226")); //$NON-NLS-1$ + } + + public void releaseWritableTile(int tileX, int tileY) { + } + + /** + * Gets a color in the TYPE_INT_ARGB color model and default sRGB color + * space of the specified pixel. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @return the color of the specified pixel in the TYPE_INT_ARGB color model + * and default sRGB color space. + */ + public int getRGB(int x, int y) { + return cm.getRGB(raster.getDataElements(x, y, null)); + } + + /** + * Returns true if alpha is pre-multiplied, false if alpha is not + * pre-multiplied or there is no alpha. + * + * @return true if alpha is pre-multiplied, false if alpha is not + * pre-multiplied or there is no alpha. + */ + public boolean isAlphaPremultiplied() { + return cm.isAlphaPremultiplied(); + } + + public boolean hasTileWriters() { + return true; + } + + @Override + public void flush() { + imageSurf.dispose(); + } + + public int getWidth() { + return raster.getWidth(); + } + + /** + * Gets the image type. + * + * @return the image type. + */ + public int getType() { + return imageType; + } + + public int getTileWidth() { + return raster.getWidth(); + } + + public int getTileHeight() { + return raster.getHeight(); + } + + public int getTileGridYOffset() { + return raster.getSampleModelTranslateY(); + } + + public int getTileGridXOffset() { + return raster.getSampleModelTranslateX(); + } + + public int getNumYTiles() { + return 1; + } + + public int getNumXTiles() { + return 1; + } + + public int getMinY() { + return raster.getMinY(); + } + + public int getMinX() { + return raster.getMinX(); + } + + public int getMinTileY() { + return 0; + } + + public int getMinTileX() { + return 0; + } + + public int getHeight() { + return raster.getHeight(); + } + + /** + * Creates the image surface. + * + * @param type + * the type. + * @return the image surface. + */ + private ImageSurface createImageSurface(int type) { + return new ImageSurface(getColorModel(), getRaster(), type); + } + + /** + * Gets the image surface. + * + * @return the image surface. + */ + ImageSurface getImageSurface() { + return imageSurf; + } + + public int getTransparency() { + return cm.getTransparency(); + } +} diff --git a/awt/java/awt/image/BufferedImageFilter.java b/awt/java/awt/image/BufferedImageFilter.java new file mode 100644 index 0000000..8b6fcf0 --- /dev/null +++ b/awt/java/awt/image/BufferedImageFilter.java @@ -0,0 +1,397 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt.image; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The BufferedImageFilter class provides filtering operations to the + * BufferedImage objects using operators which implement BufferedImageOp + * interface. + * + * @since Android 1.0 + */ +public class BufferedImageFilter extends ImageFilter implements Cloneable { + + /** + * The Constant accessor. + */ + private static final AwtImageBackdoorAccessor accessor = AwtImageBackdoorAccessor.getInstance(); + + /** + * The op. + */ + private BufferedImageOp op; + + /** + * The raster. + */ + private WritableRaster raster; + + /** + * The i data. + */ + private int iData[]; + + /** + * The b data. + */ + private byte bData[]; + + /** + * The width. + */ + private int width; + + /** + * The height. + */ + private int height; + + /** + * The cm. + */ + private ColorModel cm; + + /** + * The forced rgb. + */ + private boolean forcedRGB = false; + + /** + * The transfer type. + */ + private int transferType = DataBuffer.TYPE_UNDEFINED; + + /** + * Instantiates a new BufferedImageFilter with the specified BufferedImageOp + * operator. + * + * @param op + * the specified BufferedImageOp operator. + * @throws NullPointerException + * if BufferedImageOp is null. + */ + public BufferedImageFilter(BufferedImageOp op) { + if (op == null) { + throw new NullPointerException(Messages.getString("awt.05")); //$NON-NLS-1$ + } + this.op = op; + } + + /** + * Gets the BufferedImageOp operator associated with this + * BufferedImageFilter object. + * + * @return the BufferedImageOp associated with this BufferedImageFilter + * object. + */ + public BufferedImageOp getBufferedImageOp() { + return op; + } + + @Override + public void setDimensions(int width, int height) { + this.width = width; + this.height = height; + // Stop image consuming if no pixels expected. + if (width <= 0 || height <= 0) { + consumer.imageComplete(ImageConsumer.STATICIMAGEDONE); + reset(); + } + } + + @Override + public void setColorModel(ColorModel model) { + if (this.cm != null && this.cm != model && raster != null) { + forceRGB(); + } else { + this.cm = model; + } + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize) { + setPixels(x, y, w, h, model, pixels, off, scansize, true); + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize) { + setPixels(x, y, w, h, model, pixels, off, scansize, false); + } + + @Override + public void imageComplete(int status) { + if (status == STATICIMAGEDONE || status == SINGLEFRAMEDONE) { + BufferedImage bim = new BufferedImage(cm, raster, cm.isAlphaPremultiplied, null); + bim = op.filter(bim, null); + DataBuffer dstDb = bim.getRaster().getDataBuffer(); + ColorModel dstCm = bim.getColorModel(); + int dstW = bim.getWidth(); + int dstH = bim.getHeight(); + + consumer.setDimensions(dstW, dstH); + + if (dstDb.getDataType() == DataBuffer.TYPE_INT) { + consumer.setColorModel(dstCm); + consumer.setPixels(0, 0, dstW, dstH, dstCm, accessor.getDataInt(dstDb), 0, dstW); + } else if (dstDb.getDataType() == DataBuffer.TYPE_BYTE) { + consumer.setColorModel(dstCm); + consumer.setPixels(0, 0, dstW, dstH, dstCm, accessor.getDataByte(dstDb), 0, dstW); + } else { + int dstData[] = bim.getRGB(0, 0, dstW, dstH, null, 0, dstW); + dstCm = ColorModel.getRGBdefault(); + consumer.setColorModel(dstCm); + consumer.setPixels(0, 0, dstW, dstH, dstCm, dstData, 0, dstW); + } + } else if (status == IMAGEERROR || status == IMAGEABORTED) { + reset(); + } + + consumer.imageComplete(status); + } + + /** + * Sets the pixels. + * + * @param x + * the x. + * @param y + * the y. + * @param w + * the w. + * @param h + * the h. + * @param model + * the model. + * @param pixels + * the pixels. + * @param off + * the off. + * @param scansize + * the scansize. + * @param isByteData + * the is byte data. + */ + private void setPixels(int x, int y, int w, int h, ColorModel model, Object pixels, int off, + int scansize, boolean isByteData) { + // Check bounds + // Need to copy only the pixels that will fit into the destination area + if (x < 0) { + w -= x; + off += x; + x = 0; + } + + if (y < 0) { + h -= y; + off += y * scansize; + y = 0; + } + + if (x + w > width) { + w = width - x; + } + + if (y + h > height) { + h = height - y; + } + + if (w <= 0 || h <= 0) { + return; + } + + // Check model + if (this.cm == null) { + setColorModel(model); + } else if (model == null) { + model = this.cm; + } else if (!model.equals(this.cm)) { + forceRGB(); + } + + boolean canArraycopy; + // Process pixels + switch (transferType) { + case DataBuffer.TYPE_UNDEFINED: { + if (isByteData) { + transferType = DataBuffer.TYPE_BYTE; + createRaster(transferType); + // bData = new byte[width*height]; + canArraycopy = !forcedRGB; + break; + } + transferType = DataBuffer.TYPE_INT; + createRaster(transferType); + // iData = new int[width*height]; + canArraycopy = !forcedRGB || model.equals(ColorModel.getRGBdefault()); + break; + } // And proceed to copy the pixels + case DataBuffer.TYPE_INT: { + if (isByteData) { // There are int data already but the new data + // are bytes + forceRGB(); + canArraycopy = false; + break; + } else if (!forcedRGB || model.equals(ColorModel.getRGBdefault())) { + canArraycopy = true; + break; + } // Else fallback to the RGB conversion + } + case DataBuffer.TYPE_BYTE: { + if (isByteData && !forcedRGB) { + canArraycopy = true; + break; + } + + // RGB conversion + canArraycopy = false; + break; + } + default: { + throw new IllegalStateException(Messages.getString("awt.06")); //$NON-NLS-1$ + } + } + + off += x; + int maxOffset = off + h * scansize; + int dstOffset = x + y * width; + + if (canArraycopy) { + Object dstArray = isByteData ? (Object)bData : (Object)iData; + for (; off < maxOffset; off += scansize, dstOffset += width) { + System.arraycopy(pixels, off, dstArray, dstOffset, w); + } + } else { + // RGB conversion + for (; off < maxOffset; off += scansize, dstOffset += width) { + int srcPos = off; + int dstPos = dstOffset; + int maxDstPos = dstOffset + w; + for (; dstPos < maxDstPos; dstPos++, srcPos++) { + iData[dstPos] = model.getRGB(isByteData ? ((byte[])pixels)[srcPos] + : ((int[])pixels)[srcPos]); + } + } + } + } + + /** + * Force rgb. + */ + private void forceRGB() { + if (!forcedRGB) { + forcedRGB = true; + int size = width * height; + int rgbData[] = new int[size]; + + if (bData != null) { + for (int i = 0; i < size; i++) { + rgbData[i] = cm.getRGB(bData[i]); + } + } else if (iData != null) { + for (int i = 0; i < size; i++) { + rgbData[i] = cm.getRGB(iData[i]); + } + } + + cm = ColorModel.getRGBdefault(); + DataBufferInt db = new DataBufferInt(rgbData, size); + int masks[] = new int[] { + 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 + }; + raster = Raster.createPackedRaster(db, width, height, width, masks, null); + iData = accessor.getDataInt(db); + bData = null; + transferType = DataBuffer.TYPE_INT; + } + } + + /** + * Reset. + */ + private void reset() { + width = 0; + height = 0; + forcedRGB = false; + cm = null; + iData = null; + bData = null; + transferType = DataBuffer.TYPE_UNDEFINED; + raster = null; + } + + /** + * Creates the raster. + * + * @param dataType + * the data type. + */ + private void createRaster(int dataType) { + boolean createdValidBuffer = false; + try { + raster = cm.createCompatibleWritableRaster(width, height); + int rasterType = raster.getDataBuffer().getDataType(); + if (rasterType == dataType) { + switch (rasterType) { + case DataBuffer.TYPE_INT: { + iData = accessor.getDataInt(raster.getDataBuffer()); + if (iData != null) { + createdValidBuffer = true; + } + break; + } + case DataBuffer.TYPE_BYTE: { + bData = accessor.getDataByte(raster.getDataBuffer()); + if (bData != null) { + createdValidBuffer = true; + } + break; + } + default: + createdValidBuffer = false; + } + + if (cm == ColorModel.getRGBdefault()) { + forcedRGB = true; + } + } else { + createdValidBuffer = false; + } + } catch (Exception e) { + createdValidBuffer = false; + } + + if (createdValidBuffer == false) { + cm = ColorModel.getRGBdefault(); + raster = cm.createCompatibleWritableRaster(width, height); + iData = accessor.getDataInt(raster.getDataBuffer()); + bData = null; + forcedRGB = true; + } + } +} diff --git a/awt/java/awt/image/BufferedImageOp.java b/awt/java/awt/image/BufferedImageOp.java new file mode 100644 index 0000000..883a39d --- /dev/null +++ b/awt/java/awt/image/BufferedImageOp.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.RenderingHints; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * The BufferedImageOp interface provides methods for performing transformations + * from source data to destination data for BufferedImage objects. An object + * implementing this interface can be passed into a BufferedImageFilter to + * operate on a BufferedImage. + * + * @since Android 1.0 + */ +public interface BufferedImageOp { + + /** + * Creates a destination image with the specified BufferedImage and + * ColorModel; this destination image is empty and has the correct size and + * number of bands. + * + * @param src + * the source BufferedImage. + * @param destCM + * the destination ColorModel. + * @return the BufferedImage. + */ + public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM); + + /** + * Performs a filter operation on the source BufferedImage and stores the + * resulting BufferedImage to the destination BufferedImage. If the + * destination BufferedImage is null, a BufferedImage with an appropriate + * ColorModel is created. + * + * @param src + * the source BufferedImage. + * @param dest + * the destination BufferedImage, where the result is stored. + * @return the filtered BufferedImage. + */ + public BufferedImage filter(BufferedImage src, BufferedImage dest); + + /** + * Gets the bounds of filtered image. + * + * @param src + * the source BufferedImage to be filtered. + * @return the rectangle bounds of filtered image. + */ + public Rectangle2D getBounds2D(BufferedImage src); + + /** + * Gets the point of the destination image which corresponds to the + * specified point in the source image. + * + * @param srcPt + * the point of the source image. + * @param dstPt + * the point where the result will be stored. + * @return the destination point. + */ + public Point2D getPoint2D(Point2D srcPt, Point2D dstPt); + + /** + * Gets the RenderingHints of the BufferedImageOp. + * + * @return the RenderingHints of the BufferedImageOp. + */ + public RenderingHints getRenderingHints(); +} diff --git a/awt/java/awt/image/ByteLookupTable.java b/awt/java/awt/image/ByteLookupTable.java new file mode 100644 index 0000000..27cee30 --- /dev/null +++ b/awt/java/awt/image/ByteLookupTable.java @@ -0,0 +1,140 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Oct 14, 2005 + */ + +package java.awt.image; + +/** + * The ByteLookupTable class provides functionality for lookup operations, and + * is defined by an input byte array for bands or components of image and an + * offset value. The offset value will be subtracted from the input values + * before indexing the input arrays. The output of a lookup operation is + * represented as an array of unsigned bytes. + * + * @since Android 1.0 + */ +public class ByteLookupTable extends LookupTable { + + /** + * The data. + */ + private byte data[][]; + + /** + * Instantiates a new ByteLookupTable with the specified offset value and + * the specified byte array which represents the lookup table for all bands. + * + * @param offset + * the offset value. + * @param data + * the data array of bytes. + */ + public ByteLookupTable(int offset, byte[] data) { + super(offset, 1); + if (data.length < 1) + throw new IllegalArgumentException("Length of data should not be less then one"); + this.data = new byte[1][data.length]; + // The data array stored as a reference + this.data[0] = data; + } + + /** + * Instantiates a new ByteLookupTable with the specified offset value and + * the specified byte array of arrays which represents the lookup table for + * each band. + * + * @param offset + * the offset value. + * @param data + * the data array of bytes array for each band. + */ + public ByteLookupTable(int offset, byte[][] data) { + super(offset, data.length); + this.data = new byte[data.length][data[0].length]; + for (int i = 0; i < data.length; i++) { + // The data array for each band stored as a reference + this.data[i] = data[i]; + } + } + + /** + * Gets the lookup table of this ByteLookupTable object. If this + * ByteLookupTable object has one byte array for all bands, the returned + * array length is one. + * + * @return the lookup table of this ByteLookupTable object. + */ + public final byte[][] getTable() { + // Returns data by reference + return data; + } + + @Override + public int[] lookupPixel(int[] src, int[] dst) { + if (dst == null) { + dst = new int[src.length]; + } + + int offset = getOffset(); + if (getNumComponents() == 1) { + for (int i = 0; i < src.length; i++) { + dst[i] = data[0][src[i] - offset]; + } + } else { + for (int i = 0; i < getNumComponents(); i++) { + dst[i] = data[i][src[i] - offset]; + } + } + + return dst; + } + + /** + * Returns a byte array which contains samples of the specified pixel which + * is translated with the lookup table of this ByteLookupTable object. The + * resulted array is stored to the dst array. + * + * @param src + * the source array. + * @param dst + * the destination array where the result can be stored. + * @return the byte array of translated samples of a pixel. + */ + public byte[] lookupPixel(byte[] src, byte[] dst) { + if (dst == null) { + dst = new byte[src.length]; + } + + int offset = getOffset(); + if (getNumComponents() == 1) { + for (int i = 0; i < src.length; i++) { + dst[i] = data[0][src[i] - offset]; + } + } else { + for (int i = 0; i < getNumComponents(); i++) { + dst[i] = data[i][src[i] - offset]; + } + } + + return dst; + } +} diff --git a/awt/java/awt/image/ColorConvertOp.java b/awt/java/awt/image/ColorConvertOp.java new file mode 100644 index 0000000..1a1700b --- /dev/null +++ b/awt/java/awt/image/ColorConvertOp.java @@ -0,0 +1,710 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.RenderingHints; +import java.awt.color.ColorSpace; +import java.awt.color.ICC_ColorSpace; +import java.awt.color.ICC_Profile; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.ArrayList; + +import org.apache.harmony.awt.gl.color.ColorConverter; +import org.apache.harmony.awt.gl.color.ColorScaler; +import org.apache.harmony.awt.gl.color.ICC_Transform; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The ColorConvertOp class converts the pixels of the data in the source image + * with the specified ColorSpace objects or an array of ICC_Profile objects. The + * result pixels are scaled to the precision of the destination image. + * + * @since Android 1.0 + */ +public class ColorConvertOp implements BufferedImageOp, RasterOp { + // Unused but required by interfaces + /** + * The rendering hints. + */ + RenderingHints renderingHints; + + // Sequence consisting of ColorSpace and ICC_Profile elements + /** + * The conversion sequence. + */ + Object conversionSequence[] = new ICC_Profile[0]; // To eliminate checks for + + // null + + // Not null if ColorConvertOp is constructed from the array of ICC profiles + /** + * The mid profiles. + */ + private ICC_Profile midProfiles[]; + + /** + * The cc. + */ + private final ColorConverter cc = new ColorConverter(); + + /** + * The t creator. + */ + private final ICC_TransfomCreator tCreator = new ICC_TransfomCreator(); + + /** + * The is icc. + */ + private boolean isICC = true; + + // Cached ICC_Transform + /** + * The Class ICC_TransfomCreator. + */ + private class ICC_TransfomCreator { + + /** + * The transform. + */ + private ICC_Transform transform; + + /** + * The max components. + */ + private int maxComponents; + + /** + * For the full ICC case. + * + * @param src + * the src. + * @param dst + * the dst. + * @param convSeq + * the conv seq. + * @return the transform. + */ + public ICC_Transform getTransform(ICC_Profile src, ICC_Profile dst, ICC_Profile convSeq[]) { + if (transform != null && src == transform.getSrc() && dst == transform.getDst()) { + return transform; + } + + int length = convSeq.length; + int srcFlg = 0, dstFlg = 0; + + if (length == 0 || src != convSeq[0]) { + if (src != null) { + srcFlg = 1; // need src profile + } + } + if (length == 0 || dst != convSeq[length - 1]) { + if (dst != null) { + dstFlg = 1; // need dst profile + } + } + + ICC_Profile profiles[]; + int nProfiles = length + srcFlg + dstFlg; + if (nProfiles == length) { + profiles = convSeq; + } else { + profiles = new ICC_Profile[nProfiles]; + int pos = 0; + if (srcFlg != 0) { + profiles[pos++] = src; + } + for (int i = 0; i < length; i++) { + profiles[pos++] = convSeq[i]; + } + if (dstFlg != 0) { + profiles[pos++] = dst; + } + } + + return transform = new ICC_Transform(profiles); + } + + /** + * Used only when there are non-ICC color spaces. Returns sequence of + * non-ICC color spaces and ICC transforms made from src, dst and + * conversionSequence. + * + * @param src + * the src. + * @param dst + * the dst. + * @return the sequence. + */ + public Object[] getSequence(Object src, Object dst) { + ArrayList<Object> profiles = new ArrayList<Object>(10); + ArrayList<Object> sequence = new ArrayList<Object>(10); + + // We need this profile anyway + ICC_Profile xyzProfile = ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ); + + Object conversionFirst = null, conversionLast = null; + int conversionLength = conversionSequence.length; + if (conversionLength > 0) { + conversionFirst = conversionSequence[0]; + conversionLast = conversionSequence[conversionLength - 1]; + } + + boolean iccSequenceStarted = false; + + if (src != conversionFirst && src != null) { + if (src instanceof ICC_Profile) { + profiles.add(src); + iccSequenceStarted = true; + } else { + profiles.add(xyzProfile); + sequence.add(src); // Add non-ICC color space to the + // sequence + } + } else { + profiles.add(xyzProfile); + } + + for (int i = 0; i < conversionLength; i++) { + if (conversionSequence[i] instanceof ICC_Profile) { + profiles.add(conversionSequence[i]); + iccSequenceStarted = true; + } else if (iccSequenceStarted) { + profiles.add(xyzProfile); + + // Eliminate same profiles if there are any + // (e.g. xyzProfile may occur several times) + Object prev = profiles.get(0); + for (int k = 1; k < profiles.size(); k++) { + if (prev == profiles.get(k)) { + k--; + profiles.remove(k); + } + prev = profiles.get(k); + } + + // If only one profile left we skip the transform - + // it can be only CIEXYZ + if (profiles.size() > 1) { + sequence.add(new ICC_Transform(profiles.toArray(new ICC_Profile[0]))); + + // Add non-ICC color space to the sequence + sequence.add(conversionSequence[i]); + } + + profiles.clear(); + profiles.add(xyzProfile); + iccSequenceStarted = false; // Sequence of ICC profiles is + // processed + } else { // Add non-ICC color space to the sequence + sequence.add(conversionSequence[i]); + } + } + + if (dst != conversionLast && dst != null) { // Add last profile if + // needed + if (dst instanceof ICC_Profile) { + profiles.add(dst); + iccSequenceStarted = true; + } else if (iccSequenceStarted) { + profiles.add(xyzProfile); + } else { + sequence.add(dst); // Add last non-ICC color space to the + // sequence + } + } + + if (iccSequenceStarted) { // Make last transform if needed + sequence.add(new ICC_Transform(profiles.toArray(new ICC_Profile[0]))); + if (dst != null && !(dst instanceof ICC_Profile)) { + sequence.add(dst); // Add last non-ICC color space to the + // sequence + } + } + + // Calculate max number of components + // This number will be used for memory allocation + maxComponents = 0; + Object o; + for (int i = 0, size = sequence.size(); i < size; i++) { + o = sequence.get(i); + if (o instanceof ICC_Transform) { + ICC_Transform t = (ICC_Transform)o; + maxComponents = (maxComponents > t.getNumInputChannels() + 1) ? maxComponents + : t.getNumInputChannels() + 1; + maxComponents = (maxComponents > t.getNumOutputChannels() + 1) ? maxComponents + : t.getNumOutputChannels() + 1; + } else { + ColorSpace cs = (ColorSpace)o; + maxComponents = (maxComponents > cs.getNumComponents() + 1) ? maxComponents + : cs.getNumComponents() + 1; + } + } + + return sequence.toArray(); + } + } + + /** + * Instantiates a new ColorConvertOp object using two specified ColorSpace + * objects. + * + * @param srcCS + * the source ColorSpace. + * @param dstCS + * the destination ColorSpace. + * @param hints + * the RenderingHints object used for the color conversion, or + * null. + */ + public ColorConvertOp(ColorSpace srcCS, ColorSpace dstCS, RenderingHints hints) { + if (srcCS == null || dstCS == null) { + throw new NullPointerException(Messages.getString("awt.25B")); //$NON-NLS-1$ + } + + renderingHints = hints; + + boolean srcICC = srcCS instanceof ICC_ColorSpace; + boolean dstICC = dstCS instanceof ICC_ColorSpace; + + if (srcICC && dstICC) { + conversionSequence = new ICC_Profile[2]; + } else { + conversionSequence = new Object[2]; + isICC = false; + } + + if (srcICC) { + conversionSequence[0] = ((ICC_ColorSpace)srcCS).getProfile(); + } else { + conversionSequence[0] = srcCS; + } + + if (dstICC) { + conversionSequence[1] = ((ICC_ColorSpace)dstCS).getProfile(); + } else { + conversionSequence[1] = dstCS; + } + } + + /** + * Instantiates a new ColorConvertOp object from the specified ICC_Profile + * objects. + * + * @param profiles + * the array of ICC_Profile objects. + * @param hints + * the RenderingHints object used for the color conversion, or + * null. + */ + public ColorConvertOp(ICC_Profile profiles[], RenderingHints hints) { + if (profiles == null) { + throw new NullPointerException(Messages.getString("awt.25C")); //$NON-NLS-1$ + } + + renderingHints = hints; + + // This array is not used in the program logic, so don't need to copy it + // Store it only to return back + midProfiles = profiles; + + conversionSequence = new ICC_Profile[midProfiles.length]; + + // Add profiles to the conversion sequence + for (int i = 0, length = midProfiles.length; i < length; i++) { + conversionSequence[i] = midProfiles[i]; + } + } + + /** + * Instantiates a new ColorConvertOp object using the specified ColorSpace + * object. + * + * @param cs + * the destination ColorSpace or an intermediate ColorSpace. + * @param hints + * the RenderingHints object used for the color conversion, or + * null. + */ + public ColorConvertOp(ColorSpace cs, RenderingHints hints) { + if (cs == null) { + throw new NullPointerException(Messages.getString("awt.25B")); //$NON-NLS-1$ + } + + renderingHints = hints; + + if (cs instanceof ICC_ColorSpace) { + conversionSequence = new ICC_Profile[1]; + conversionSequence[0] = ((ICC_ColorSpace)cs).getProfile(); + } else { + conversionSequence = new Object[1]; + conversionSequence[0] = cs; + isICC = false; + } + } + + /** + * Instantiates a new ColorConvertOp object which converts from a source + * color space to a destination color space. + * + * @param hints + * the RenderingHints object used for the color conversion, or + * null. + */ + public ColorConvertOp(RenderingHints hints) { + renderingHints = hints; + } + + public final WritableRaster filter(Raster src, WritableRaster dst) { + if (conversionSequence.length < 2) { + throw new IllegalArgumentException(Messages.getString("awt.25D")); //$NON-NLS-1$ + } + + ICC_Profile srcPf = null, dstPf = null; // unused if isICC is false + int nSrcColorComps, nDstColorComps; + Object first = conversionSequence[0]; + Object last = conversionSequence[conversionSequence.length - 1]; + + // Get the number of input/output color components + if (isICC) { + srcPf = (ICC_Profile)first; + dstPf = (ICC_Profile)last; + nSrcColorComps = srcPf.getNumComponents(); + nDstColorComps = dstPf.getNumComponents(); + } else { + if (first instanceof ICC_Profile) { + srcPf = (ICC_Profile)first; + nSrcColorComps = srcPf.getNumComponents(); + } else { + nSrcColorComps = ((ColorSpace)first).getNumComponents(); + } + + if (last instanceof ICC_Profile) { + dstPf = (ICC_Profile)last; + nDstColorComps = dstPf.getNumComponents(); + } else { + nDstColorComps = ((ColorSpace)last).getNumComponents(); + } + } + + // Check that source and destination rasters are compatible with + // transforms and with each other + if (src.getNumBands() != nSrcColorComps) { + // awt.25E=Incorrect number of source raster bands. Should be equal + // to the number of color components of source colorspace. + throw new IllegalArgumentException(Messages.getString("awt.25E")); //$NON-NLS-1$ + } + + if (dst != null) { // Check destination raster + if (dst.getNumBands() != nDstColorComps) { + // awt.25F=Incorrect number of destination raster bands. Should + // be equal to the number of color components of destination + // colorspace. + throw new IllegalArgumentException(Messages.getString("awt.25F")); //$NON-NLS-1$ + } + + if (src.getWidth() != dst.getWidth() || src.getHeight() != dst.getHeight()) { + throw new IllegalArgumentException(Messages.getString("awt.260")); //$NON-NLS-1$ + } + + } else { + dst = createCompatibleDestRaster(src); + } + + if (isICC) { + // Create transform + ICC_Transform t = tCreator + .getTransform(srcPf, dstPf, (ICC_Profile[])conversionSequence); + cc.translateColor(t, src, dst); + } else { + Object[] sequence = tCreator.getSequence(null, null); + + // Get data from the source raster + ColorScaler scaler = new ColorScaler(); + scaler.loadScalingData(src, null); + float tmpData[][] = scaler.scaleNormalize(src); + + // Get source and destination color spaces + ColorSpace srcCS = (srcPf == null) ? (ColorSpace)first : new ICC_ColorSpace(srcPf); + ColorSpace dstCS = (dstPf == null) ? (ColorSpace)last : new ICC_ColorSpace(dstPf); + + applySequence(sequence, tmpData, srcCS, dstCS); + + scaler.loadScalingData(dst, null); + scaler.unscaleNormalized(dst, tmpData); + } + + return dst; + } + + public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) { + // If destination color model is passed only one line needed + if (destCM != null) { + return new BufferedImage(destCM, destCM.createCompatibleWritableRaster(src.getWidth(), + src.getHeight()), destCM.isAlphaPremultiplied(), null); + } + + int nSpaces = conversionSequence.length; + + if (nSpaces < 1) { + throw new IllegalArgumentException(Messages.getString("awt.261")); //$NON-NLS-1$ + } + + // Get destination color space + Object destination = conversionSequence[nSpaces - 1]; + ColorSpace dstCS = (destination instanceof ColorSpace) ? (ColorSpace)destination + : new ICC_ColorSpace((ICC_Profile)destination); + + ColorModel srcCM = src.getColorModel(); + ColorModel dstCM = new ComponentColorModel(dstCS, srcCM.hasAlpha(), srcCM + .isAlphaPremultiplied(), srcCM.getTransparency(), srcCM.getTransferType()); + + return new BufferedImage(dstCM, destCM.createCompatibleWritableRaster(src.getWidth(), src + .getHeight()), destCM.isAlphaPremultiplied(), null); + } + + public final BufferedImage filter(BufferedImage src, BufferedImage dst) { + if (dst == null && conversionSequence.length < 1) { + throw new IllegalArgumentException(Messages.getString("awt.262")); //$NON-NLS-1$ + } + + ColorModel srcCM = src.getColorModel(); + // First handle index color model + if (srcCM instanceof IndexColorModel) { + src = ((IndexColorModel)srcCM).convertToIntDiscrete(src.getRaster(), false); + } + ColorSpace srcCS = srcCM.getColorSpace(); + + BufferedImage res; + boolean isDstIndex = false; + if (dst != null) { + + if (src.getWidth() != dst.getWidth() || src.getHeight() != dst.getHeight()) { + throw new IllegalArgumentException(Messages.getString("awt.263")); //$NON-NLS-1$ + } + + if (dst.getColorModel() instanceof IndexColorModel) { + isDstIndex = true; + res = createCompatibleDestImage(src, null); + } else { + res = dst; + } + } else { + res = createCompatibleDestImage(src, null); + } + ColorModel dstCM = res.getColorModel(); + ColorSpace dstCS = dstCM.getColorSpace(); + + ICC_Profile srcPf = null, dstPf = null; + if (srcCS instanceof ICC_ColorSpace) { + srcPf = ((ICC_ColorSpace)srcCS).getProfile(); + } + if (dstCS instanceof ICC_ColorSpace) { + dstPf = ((ICC_ColorSpace)dstCS).getProfile(); + } + + boolean isFullICC = isICC && srcPf != null && dstPf != null; + + if (isFullICC) { + ICC_Transform t = tCreator + .getTransform(srcPf, dstPf, (ICC_Profile[])conversionSequence); + cc.translateColor(t, src, res); + } else { // Perform non-ICC transform + Object sequence[] = tCreator.getSequence(srcPf == null ? (Object)srcCS : srcPf, + dstPf == null ? (Object)dstCS : dstPf); + + int srcW = src.getWidth(); + int srcH = src.getHeight(); + int numPixels = srcW * srcH; + + // Load all pixel data into array tmpData + float tmpData[][] = new float[numPixels][tCreator.maxComponents]; + for (int row = 0, dataPos = 0; row < srcW; row++) { + for (int col = 0; col < srcH; col++) { + tmpData[dataPos] = srcCM.getNormalizedComponents(src.getRaster() + .getDataElements(row, col, null), tmpData[dataPos], 0); + dataPos++; + } + } + + // Copy alpha channel if needed + float alpha[] = null; + int alphaIdx = srcCM.numComponents - 1; + if (srcCM.hasAlpha() && dstCM.hasAlpha()) { + alpha = new float[numPixels]; + for (int i = 0; i < numPixels; i++) { + alpha[i] = tmpData[i][alphaIdx]; + } + } + + // Translate colors + applySequence(sequence, tmpData, srcCS, dstCS); + + // Copy alpha if needed + if (dstCM.hasAlpha()) { + alphaIdx = dstCM.numComponents - 1; + if (alpha != null) { + for (int i = 0; i < numPixels; i++) { + tmpData[i][alphaIdx] = alpha[i]; + } + } else { + for (int i = 0; i < numPixels; i++) { + tmpData[i][alphaIdx] = 1f; + } + } + } + + // Store data back to the image + for (int row = 0, dataPos = 0; row < srcW; row++) { + for (int col = 0; col < srcH; col++) { + res.getRaster().setDataElements(row, col, + dstCM.getDataElements(tmpData[dataPos++], 0, null)); + } + } + } + + if (isDstIndex) { // Convert image into indexed color + Graphics2D g2d = dst.createGraphics(); + g2d.drawImage(res, 0, 0, null); + g2d.dispose(); + return dst; + } + + return res; + } + + /** + * Apply sequence. + * + * @param sequence + * the sequence. + * @param tmpData + * the tmp data. + * @param srcCS + * the src cs. + * @param dstCS + * the dst cs. + */ + private void applySequence(Object sequence[], float tmpData[][], ColorSpace srcCS, + ColorSpace dstCS) { + ColorSpace xyzCS = ColorSpace.getInstance(ColorSpace.CS_CIEXYZ); + + int numPixels = tmpData.length; + + // First transform... + if (sequence[0] instanceof ICC_Transform) { // ICC + ICC_Transform t = (ICC_Transform)sequence[0]; + cc.translateColor(t, tmpData, srcCS, xyzCS, numPixels); + } else { // non ICC + for (int k = 0; k < numPixels; k++) { + tmpData[k] = srcCS.toCIEXYZ(tmpData[k]); + } + cc.loadScalingData(xyzCS); // prepare for scaling XYZ + } + + for (Object element : sequence) { + if (element instanceof ICC_Transform) { + ICC_Transform t = (ICC_Transform)element; + cc.translateColor(t, tmpData, null, null, numPixels); + } else { + ColorSpace cs = (ColorSpace)element; + for (int k = 0; k < numPixels; k++) { + tmpData[k] = cs.fromCIEXYZ(tmpData[k]); + tmpData[k] = cs.toCIEXYZ(tmpData[k]); + } + } + } + + // Last transform... + if (sequence[sequence.length - 1] instanceof ICC_Transform) { // ICC + ICC_Transform t = (ICC_Transform)sequence[sequence.length - 1]; + cc.translateColor(t, tmpData, xyzCS, dstCS, numPixels); + } else { // non ICC + for (int k = 0; k < numPixels; k++) { + tmpData[k] = dstCS.fromCIEXYZ(tmpData[k]); + } + } + } + + public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { + if (dstPt != null) { + dstPt.setLocation(srcPt); + return dstPt; + } + return new Point2D.Float((float)srcPt.getX(), (float)srcPt.getY()); + } + + public WritableRaster createCompatibleDestRaster(Raster src) { + int nComps = 0; + int nSpaces = conversionSequence.length; + + if (nSpaces < 2) { + throw new IllegalArgumentException(Messages.getString("awt.261")); //$NON-NLS-1$ + } + + Object lastCS = conversionSequence[nSpaces - 1]; + if (lastCS instanceof ColorSpace) { + nComps = ((ColorSpace)lastCS).getNumComponents(); + } else { + nComps = ((ICC_Profile)lastCS).getNumComponents(); + } + + // Calculate correct data type + int dstDataType = src.getDataBuffer().getDataType(); + if (dstDataType != DataBuffer.TYPE_BYTE && dstDataType != DataBuffer.TYPE_SHORT) { + dstDataType = DataBuffer.TYPE_SHORT; + } + + return Raster.createInterleavedRaster(dstDataType, src.getWidth(), src.getHeight(), nComps, + new Point(src.getMinX(), src.getMinY())); + } + + public final Rectangle2D getBounds2D(Raster src) { + return src.getBounds(); + } + + public final Rectangle2D getBounds2D(BufferedImage src) { + return src.getRaster().getBounds(); + } + + /** + * Gets an array of ICC_Profiles objects which constructs this + * ColorConvertOp object or returns null if this ColorConvertOp is not + * constructed from array of ICC_Profiles. + * + * @return an array of ICC_Profiles objects which constructs this + * ColorConvertOp object or returns null if this ColorConvertOp is + * not constructed from array of ICC_Profiles. + */ + public final ICC_Profile[] getICC_Profiles() { + if (midProfiles != null) { + return midProfiles; + } + return null; + } + + public final RenderingHints getRenderingHints() { + return renderingHints; + } +} diff --git a/awt/java/awt/image/ColorModel.java b/awt/java/awt/image/ColorModel.java new file mode 100644 index 0000000..1b084e1 --- /dev/null +++ b/awt/java/awt/image/ColorModel.java @@ -0,0 +1,964 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.util.Arrays; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The class ColorModel. + * + * @since Android 1.0 + */ +public abstract class ColorModel implements Transparency { + + /** + * The pixel_bits. + */ + protected int pixel_bits; // Pixel length in bits + + /** + * The transfer type. + */ + protected int transferType; + + /** + * The cs. + */ + ColorSpace cs; + + /** + * The has alpha. + */ + boolean hasAlpha; + + /** + * The is alpha premultiplied. + */ + boolean isAlphaPremultiplied; + + /** + * The transparency. + */ + int transparency; + + /** + * The num color components. + */ + int numColorComponents; + + /** + * The num components. + */ + int numComponents; + + /** + * The bits. + */ + int[] bits; // Array of components masks + + /** + * The max values. + */ + int[] maxValues = null; // Max values that may be represent by color + + // components + + /** + * The max bit length. + */ + int maxBitLength; // Max length color components in bits + + /** + * The RG bdefault. + */ + private static ColorModel RGBdefault; + + /** + * Instantiates a new color model with the specified values. + * + * @param pixel_bits + * the pixel length in bits. + * @param bits + * the array of component masks. + * @param cspace + * the color space. + * @param hasAlpha + * whether the color model has alpha. + * @param isAlphaPremultiplied + * whether the alpha is pre-multiplied. + * @param transparency + * the transparency strategy, @see java.awt.Transparency. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + */ + protected ColorModel(int pixel_bits, int[] bits, ColorSpace cspace, boolean hasAlpha, + boolean isAlphaPremultiplied, int transparency, int transferType) { + + if (pixel_bits < 1) { + // awt.26B=The number of bits in the pixel values is less than 1 + throw new IllegalArgumentException(Messages.getString("awt.26B")); //$NON-NLS-1$ + } + + if (bits == null) { + // awt.26C=bits is null + throw new NullPointerException(Messages.getString("awt.26C")); //$NON-NLS-1$ + } + + int sum = 0; + for (int element : bits) { + if (element < 0) { + // awt.26D=The elements in bits is less than 0 + throw new IllegalArgumentException(Messages.getString("awt.26D")); //$NON-NLS-1$ + } + sum += element; + } + + if (sum < 1) { + // awt.26E=The sum of the number of bits in bits is less than 1 + throw new NullPointerException(Messages.getString("awt.26E")); //$NON-NLS-1$ + } + + if (cspace == null) { + // awt.26F=The cspace is null + throw new IllegalArgumentException(Messages.getString("awt.26F")); //$NON-NLS-1$ + } + + if (transparency < Transparency.OPAQUE || transparency > Transparency.TRANSLUCENT) { + // awt.270=The transparency is not a valid value + throw new IllegalArgumentException(Messages.getString("awt.270")); //$NON-NLS-1$ + } + + this.pixel_bits = pixel_bits; + this.bits = bits.clone(); + + maxValues = new int[bits.length]; + maxBitLength = 0; + for (int i = 0; i < maxValues.length; i++) { + maxValues[i] = (1 << bits[i]) - 1; + if (bits[i] > maxBitLength) { + maxBitLength = bits[i]; + } + } + + cs = cspace; + this.hasAlpha = hasAlpha; + this.isAlphaPremultiplied = isAlphaPremultiplied; + numColorComponents = cs.getNumComponents(); + + if (hasAlpha) { + numComponents = numColorComponents + 1; + } else { + numComponents = numColorComponents; + } + + this.transparency = transparency; + this.transferType = transferType; + + } + + /** + * Instantiates a new color model with the specified pixel bit depth. The + * transferType is chosen based on the pixel bits, and the other data fields + * are given default values. + * + * @param bits + * the array of component masks. + */ + public ColorModel(int bits) { + + if (bits < 1) { + // awt.271=The number of bits in bits is less than 1 + throw new IllegalArgumentException(Messages.getString("awt.271")); //$NON-NLS-1$ + } + + pixel_bits = bits; + transferType = getTransferType(bits); + cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + hasAlpha = true; + isAlphaPremultiplied = false; + transparency = Transparency.TRANSLUCENT; + + numColorComponents = 3; + numComponents = 4; + + this.bits = null; + } + + /** + * Gets the data elements from the specified component array, transforming + * them according to rules of the color model. + * + * @param components + * the components. + * @param offset + * the offset in the normComponents array. + * @param obj + * the array that the result is written to: an array of values + * whose length must be the number of components used by the + * color model and whose type depends on the transfer type (based + * on the pixel bit depth), or null to have the appropriate array + * created. + * @return the array of data elements. + */ + public Object getDataElements(int[] components, int offset, Object obj) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Gets the data elements from the specified array of normalized components. + * + * @param normComponents + * the array normalized components. + * @param normOffset + * the offset in the normComponents array. + * @param obj + * the array that the result is written to: an array of values + * whose length must be the number of components used by the + * color model and whose type depends on the transfer type (based + * on the pixel bit depth), or null to have the appropriate array + * created. + * @return the array of data elements. + */ + public Object getDataElements(float[] normComponents, int normOffset, Object obj) { + int unnormComponents[] = getUnnormalizedComponents(normComponents, normOffset, null, 0); + return getDataElements(unnormComponents, 0, obj); + } + + /** + * Gets the data elements corresponding to the pixel determined by the RGB + * data. + * + * @param rgb + * the RGB integer value that defines the pixel. + * @param pixel + * the array that the result is written to: an array of values + * whose length must be the number of components used by the + * color model and whose type depends on the transfer type (based + * on the pixel bit depth), or null to have the appropriate array + * created. + * @return the array of data elements. + */ + public Object getDataElements(int rgb, Object pixel) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Gets the child raster corresponding to the alpha channel of the specified + * writable raster, or null if alpha is not supported. + * + * @param raster + * the raster. + * @return the alpha raster. + */ + public WritableRaster getAlphaRaster(WritableRaster raster) { + return null; + } + + /** + * Creates a new color model by coercing the data in the writable raster in + * accordance with the alpha strategy of this color model. + * + * @param raster + * the raster. + * @param isAlphaPremultiplied + * whether the alpha is pre-multiplied in this color model + * @return the new color model. + */ + public ColorModel coerceData(WritableRaster raster, boolean isAlphaPremultiplied) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + @Override + public String toString() { + // The output format based on 1.5 release behavior. + // It could be reveled such way: + // ColorModel cm = new + // ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB, + // false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); + // System.out.println(cm.toString()); + return "ColorModel: Color Space = " + cs.toString() + "; has alpha = " //$NON-NLS-1$ //$NON-NLS-2$ + + hasAlpha + "; is alpha premultipied = " //$NON-NLS-1$ + + isAlphaPremultiplied + "; transparency = " + transparency //$NON-NLS-1$ + + "; number color components = " + numColorComponents //$NON-NLS-1$ + + "; pixel bits = " + pixel_bits + "; transfer type = " //$NON-NLS-1$ //$NON-NLS-2$ + + transferType; + } + + /** + * Gets the components of the pixel determined by the data array. + * + * @param pixel + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. + * @see ColorModel#getTransferType() + * @param components + * the the array where the resulting components are written (or + * null to prompt the method to create the return array). + * @param offset + * the offset that tells where the results should be written in + * the return array. + * @return the array of components. + */ + public int[] getComponents(Object pixel, int[] components, int offset) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Gets the normalized components of the pixel determined by the data array. + * + * @param pixel + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. + * @see ColorModel#getTransferType() + * @param normComponents + * the array where the resulting normalized components are + * written (or null to prompt the method to create the return + * array). + * @param normOffset + * the offset that tells where the results should be written in + * the return array. + * @return the array of normalized components. + */ + public float[] getNormalizedComponents(Object pixel, float[] normComponents, int normOffset) { + + if (pixel == null) { + // awt.294=pixel is null + throw new NullPointerException(Messages.getString("awt.294")); //$NON-NLS-1$ + } + + int unnormComponents[] = getComponents(pixel, null, 0); + return getNormalizedComponents(unnormComponents, 0, normComponents, normOffset); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ColorModel)) { + return false; + } + ColorModel cm = (ColorModel)obj; + + return (pixel_bits == cm.getPixelSize() && transferType == cm.getTransferType() + && cs.getType() == cm.getColorSpace().getType() && hasAlpha == cm.hasAlpha() + && isAlphaPremultiplied == cm.isAlphaPremultiplied() + && transparency == cm.getTransparency() + && numColorComponents == cm.getNumColorComponents() + && numComponents == cm.getNumComponents() && Arrays.equals(bits, cm + .getComponentSize())); + } + + /** + * Gets the red component of the pixel determined by the data array. + * + * @param inData + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. + * @see ColorModel#getTransferType() + * @return the red. + */ + public int getRed(Object inData) { + return getRed(constructPixel(inData)); + } + + /** + * Gets the RGB integer value corresponding to the pixel defined by the data + * array. + * + * @param inData + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. + * @see ColorModel#getTransferType() + * @return the integer value that gives the pixel's colors in RGB format. + */ + public int getRGB(Object inData) { + return (getAlpha(inData) << 24 | getRed(inData) << 16 | getGreen(inData) << 8 | getBlue(inData)); + } + + /** + * Gets the green component of the pixel defined by the data array. + * + * @param inData + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. + * @see ColorModel#getTransferType() + * @return the green. + */ + public int getGreen(Object inData) { + return getGreen(constructPixel(inData)); + } + + /** + * Gets the blue component of the pixel defined by the data array. + * + * @param inData + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. + * @see ColorModel#getTransferType() + * @return the blue. + */ + public int getBlue(Object inData) { + return getBlue(constructPixel(inData)); + } + + /** + * Gets the alpha component of the pixel defined by the data array. + * + * @param inData + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. + * @see ColorModel#getTransferType() + * @return the alpha. + */ + public int getAlpha(Object inData) { + return getAlpha(constructPixel(inData)); + } + + /** + * Creates a compatible writable raster. + * + * @param w + * the width of the desired writable raster. + * @param h + * the height of the desired writable raster. + * @return the writable raster. + */ + public WritableRaster createCompatibleWritableRaster(int w, int h) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Checks if the sample model is compatible with this color model. + * + * @param sm + * the sample model. + * @return true, if the sample model is compatible with this color model. + */ + public boolean isCompatibleSampleModel(SampleModel sm) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Creates the compatible sample model. + * + * @param w + * the width of the desired sample model. + * @param h + * the height of the desired sample model. + * @return the sample model. + */ + public SampleModel createCompatibleSampleModel(int w, int h) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Checks if the specified raster is compatible with this color model. + * + * @param raster + * the raster to inspect. + * @return true, if the raster is compatible with this color model. + */ + public boolean isCompatibleRaster(Raster raster) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Gets the color space of this color model. + * + * @return the color space. + */ + public final ColorSpace getColorSpace() { + return cs; + } + + /** + * Gets the normalized components corresponding to the specified + * unnormalized components. + * + * @param components + * the array of unnormalized components. + * @param offset + * the offset where the components should be read from the array + * of unnormalized components. + * @param normComponents + * the array where the resulting normalized components are + * written (or null to prompt the method to create the return + * array). + * @param normOffset + * the offset that tells where the results should be written in + * the return array. + * @return the normalized components. + */ + public float[] getNormalizedComponents(int[] components, int offset, float normComponents[], + int normOffset) { + if (bits == null) { + // awt.26C=bits is null + throw new UnsupportedOperationException(Messages.getString("awt.26C")); //$NON-NLS-1$ + } + + if (normComponents == null) { + normComponents = new float[numComponents + normOffset]; + } + + if (hasAlpha && isAlphaPremultiplied) { + float normAlpha = (float)components[offset + numColorComponents] + / maxValues[numColorComponents]; + if (normAlpha != 0.0f) { + for (int i = 0; i < numColorComponents; i++) { + normComponents[normOffset + i] = components[offset + i] + / (normAlpha * maxValues[i]); + } + normComponents[normOffset + numColorComponents] = normAlpha; + } else { + for (int i = 0; i < numComponents; i++) { + normComponents[normOffset + i] = 0.0f; + } + } + } else { + for (int i = 0; i < numComponents; i++) { + normComponents[normOffset + i] = (float)components[offset + i] / maxValues[i]; + } + } + + return normComponents; + } + + /** + * Gets the data element corresponding to the unnormalized components. + * + * @param components + * the components. + * @param offset + * the offset to start reading the components from the array of + * components. + * @return the data element. + */ + public int getDataElement(int[] components, int offset) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Gets the unnormalized components corresponding to the specified + * normalized components. + * + * @param normComponents + * the array of normalized components. + * @param normOffset + * the offset where the components should be read from the array + * of normalized components. + * @param components + * the array where the resulting unnormalized components are + * written (or null to prompt the method to create the return + * array). + * @param offset + * the offset that tells where the results should be written in + * the return array. + * @return the unnormalized components. + */ + public int[] getUnnormalizedComponents(float normComponents[], int normOffset, + int components[], int offset) { + + if (bits == null) { + // awt.26C=bits is null + throw new UnsupportedOperationException(Messages.getString("awt.26C")); //$NON-NLS-1$ + } + + if (normComponents.length - normOffset < numComponents) { + // awt.273=The length of normComponents minus normOffset is less + // than numComponents + throw new IllegalArgumentException(Messages.getString("awt.273")); //$NON-NLS-1$ + } + + if (components == null) { + components = new int[numComponents + offset]; + } else { + if (components.length - offset < numComponents) { + // awt.272=The length of components minus offset is less than + // numComponents + throw new IllegalArgumentException(Messages.getString("awt.272")); //$NON-NLS-1$ + } + } + + if (hasAlpha && isAlphaPremultiplied) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0; i < numColorComponents; i++) { + components[offset + i] = (int)(normComponents[normOffset + i] * maxValues[i] + * alpha + 0.5f); + } + components[offset + numColorComponents] = (int)(normComponents[normOffset + + numColorComponents] + * maxValues[numColorComponents] + 0.5f); + } else { + for (int i = 0; i < numComponents; i++) { + components[offset + i] = (int)(normComponents[normOffset + i] * maxValues[i] + 0.5f); + } + } + + return components; + } + + /** + * Gets the data element corresponding to the normalized components. + * + * @param normComponents + * the normalized components. + * @param normOffset + * the offset where the normalized components should be read from + * the normalized component array. + * @return the data element. + */ + public int getDataElement(float normComponents[], int normOffset) { + int unnormComponents[] = getUnnormalizedComponents(normComponents, normOffset, null, 0); + return getDataElement(unnormComponents, 0); + } + + /** + * Takes a pixel whose data is defined by an integer, and writes the + * corresponding components into the components array, starting from the + * index offset. + * + * @param pixel + * the pixel data. + * @param components + * the data array to write the components to (or null to have the + * method create the return array). + * @param offset + * the offset that determines where the results are written in + * the components array. + * @return the array of components corresponding to the pixel. + */ + public int[] getComponents(int pixel, int components[], int offset) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Gets the red component of the pixel determined by the pixel data. + * + * @param pixel + * the pixel. + * @return the red component of the given pixel. + */ + public abstract int getRed(int pixel); + + /** + * Takes the pixel data and returns the integer value corresponding to the + * pixel's color in RGB format. + * + * @param pixel + * the pixel data. + * @return the corresponding RGB integer value. + */ + public int getRGB(int pixel) { + return (getAlpha(pixel) << 24 | getRed(pixel) << 16 | getGreen(pixel) << 8 | getBlue(pixel)); + } + + /** + * Gets the green component of the pixel determined by the pixel data. + * + * @param pixel + * the pixel. + * @return the green component of the given pixel. + */ + public abstract int getGreen(int pixel); + + /** + * Gets the size of the desired component of this color model. + * + * @param componentIdx + * the index that determines which component size to get. + * @return the component size corresponding to the index. + * @throws NullPointerException + * if this color model doesn't support an array of separate + * components. + * @throws ArrayIndexOutOfBoundsException + * if the index is negative or greater than or equal to the + * number of components. + */ + public int getComponentSize(int componentIdx) { + if (bits == null) { + // awt.26C=bits is null + throw new NullPointerException(Messages.getString("awt.26C")); //$NON-NLS-1$ + } + + if (componentIdx < 0 || componentIdx >= bits.length) { + // awt.274=componentIdx is greater than the number of components or + // less than zero + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.274")); //$NON-NLS-1$ + } + + return bits[componentIdx]; + } + + /** + * Gets the blue component of the pixel determined by the pixel data. + * + * @param pixel + * the pixel. + * @return the blue component of the given pixel. + */ + public abstract int getBlue(int pixel); + + /** + * Gets the alpha component of the pixel determined by the pixel data. + * + * @param pixel + * the pixel. + * @return the alpha component of the given pixel. + */ + public abstract int getAlpha(int pixel); + + /** + * Gets the array of sizes of the different components. + * + * @return the array of sizes of the different components. + */ + public int[] getComponentSize() { + if (bits != null) { + return bits.clone(); + } + return null; + } + + /** + * Checks if the alpha component is pre-multiplied. + * + * @return true, if the alpha component is pre-multiplied. + */ + public final boolean isAlphaPremultiplied() { + return isAlphaPremultiplied; + } + + /** + * Checks whether this color model supports alpha. + * + * @return true, if this color model has alpha. + */ + public final boolean hasAlpha() { + return hasAlpha; + } + + @Override + public int hashCode() { + int hash = 0; + int tmp; + + if (hasAlpha) { + hash ^= 1; + hash <<= 8; + } + if (isAlphaPremultiplied) { + hash ^= 1; + hash <<= 8; + } + + tmp = hash >>> 24; + hash ^= numColorComponents; + hash <<= 8; + hash |= tmp; + + tmp = hash >>> 24; + hash ^= transparency; + hash <<= 8; + hash |= tmp; + + tmp = hash >>> 24; + hash ^= cs.getType(); + hash <<= 8; + hash |= tmp; + + tmp = hash >>> 24; + hash ^= pixel_bits; + hash <<= 8; + hash |= tmp; + + tmp = hash >>> 24; + hash ^= transferType; + hash <<= 8; + hash |= tmp; + + if (bits != null) { + + for (int element : bits) { + tmp = hash >>> 24; + hash ^= element; + hash <<= 8; + hash |= tmp; + } + + } + + return hash; + } + + public int getTransparency() { + return transparency; + } + + /** + * Gets the transfer type, which is the type of Java primitive value that + * corresponds to the bit length per pixel: either + * {@link DataBuffer#TYPE_BYTE}, {@link DataBuffer#TYPE_USHORT}, + * {@link DataBuffer#TYPE_INT}, or {@link DataBuffer#TYPE_UNDEFINED}. + * + * @return the transfer type. + */ + public final int getTransferType() { + return transferType; + } + + /** + * Gets the pixel size in bits. + * + * @return the pixel size. + */ + public int getPixelSize() { + return pixel_bits; + } + + /** + * Gets the number of components of this color model. + * + * @return the number of components. + */ + public int getNumComponents() { + return numComponents; + } + + /** + * Gets the number of color components of this color model. + * + * @return the number color components. + */ + public int getNumColorComponents() { + return numColorComponents; + } + + /** + * Gets the default RGB color model. + * + * @return the default RGB color model. + */ + public static ColorModel getRGBdefault() { + if (RGBdefault == null) { + RGBdefault = new DirectColorModel(32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); + } + return RGBdefault; + } + + /* + * Construct INT pixel representation from Object + * @param obj + * @return + */ + /** + * Construct pixel. + * + * @param obj + * the obj. + * @return the int. + */ + private int constructPixel(Object obj) { + int pixel = 0; + + switch (getTransferType()) { + + case DataBuffer.TYPE_BYTE: + byte[] bPixel = (byte[])obj; + if (bPixel.length > 1) { + // awt.275=This pixel representation is not suuported by tis + // Color Model + throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$ + } + pixel = bPixel[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short[] sPixel = (short[])obj; + if (sPixel.length > 1) { + // awt.275=This pixel representation is not suuported by tis + // Color Model + throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$ + } + pixel = sPixel[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int[] iPixel = (int[])obj; + if (iPixel.length > 1) { + // awt.275=This pixel representation is not suuported by tis + // Color Model + throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$ + } + pixel = iPixel[0]; + break; + + default: + // awt.22D=This transferType ( {0} ) is not supported by this + // color model + throw new UnsupportedOperationException(Messages.getString("awt.22D", //$NON-NLS-1$ + transferType)); + + } + return pixel; + } + + /** + * Gets the transfer type, which is the type of Java primitive value that + * corresponds to the bit length per pixel: either + * {@link DataBuffer#TYPE_BYTE}, {@link DataBuffer#TYPE_USHORT}, + * {@link DataBuffer#TYPE_INT}, or {@link DataBuffer#TYPE_UNDEFINED}. + * + * @param bits + * the array of component masks. + * @return the transfer type. + */ + static int getTransferType(int bits) { + if (bits <= 8) { + return DataBuffer.TYPE_BYTE; + } else if (bits <= 16) { + return DataBuffer.TYPE_USHORT; + } else if (bits <= 32) { + return DataBuffer.TYPE_INT; + } else { + return DataBuffer.TYPE_UNDEFINED; + } + } + + @Override + public void finalize() { + // This method is added for the API compatibility + // Don't need to call super since Object's finalize is always empty + } +} diff --git a/awt/java/awt/image/ComponentColorModel.java b/awt/java/awt/image/ComponentColorModel.java new file mode 100644 index 0000000..4328fd3 --- /dev/null +++ b/awt/java/awt/image/ComponentColorModel.java @@ -0,0 +1,1482 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.color.ColorSpace; + +import org.apache.harmony.awt.gl.color.LUTColorConverter; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class ComponentColorModel represents a color model that is defined in + * terms of its components. + * + * @since Android 1.0 + */ +public class ComponentColorModel extends ColorModel { + + /** + * The signed. + */ + private boolean signed; // Pixel samples are signed. + + // Samples with TransferType DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT - + // unsigned. Samples with others TransferType - + // signed. + + /** + * The integral. + */ + private boolean integral; // Pixel samples are integral. + + // Samples with TransferType DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT, DataBuffer.Short and + // DataBuffer.TYPE_INT - integral. + + /** + * The scale factors. + */ + private float scaleFactors[]; // Array of factors for reduction components + + // values into the form scaled from 0 to 255 + + /** + * The donot support unnormalized. + */ + private boolean donotSupportUnnormalized; // This Color Model don't support + + // unnormolized form + + /** + * The need alpha divide. + */ + private boolean needAlphaDivide; // hasAlpha && isAlphaPremultiplied + + /** + * The calc value. + */ + private boolean calcValue; // Value was culculated + + /** + * The need scale. + */ + private boolean needScale; // Normalized value need to scale + + /** + * The min vals. + */ + private float minVals[]; // Array of Min normalized values + + /** + * The ranges. + */ + private float ranges[]; // Array of range normalized values + + /** + * The alpha lut. + */ + private byte alphaLUT[]; // Lookup table for scale alpha value + + /** + * The color lu ts. + */ + private byte colorLUTs[][]; // Lookup tables for scale color values + + /** + * The from_ linea r_ rg b_ lut. + */ + private byte from_LINEAR_RGB_LUT[]; // Lookup table for conversion from + + // Linear RGB Color Space into sRGB + + /** + * The to_ linea r_8 rg b_ lut. + */ + private byte to_LINEAR_8RGB_LUT[]; // Lookup table for conversion from + + // sRGB Color Space into Linear RGB + // 8 bit + + /** + * The to_ linea r_16 rg b_ lut. + */ + private short to_LINEAR_16RGB_LUT[]; // Lookup table for conversion from + + // sRGB Color Space into Linear RGB + // 16 bit + + /** + * The LINEA r_ rg b_ length. + */ + private int LINEAR_RGB_Length; // Linear RGB bit length + + /** + * The factor. + */ + private float fFactor; // Scale factor + + /** + * The is_s rgb. + */ + private boolean is_sRGB; // ColorModel has sRGB ColorSpace + + /** + * The is_ linea r_ rgb. + */ + private boolean is_LINEAR_RGB; // Color Model has Linear RGB Color + + // Space + + /** + * Instantiates a new component color model. + * + * @param colorSpace + * the color space. + * @param bits + * the array of component masks. + * @param hasAlpha + * whether the color model has alpha. + * @param isAlphaPremultiplied + * whether the alpha is pre-multiplied. + * @param transparency + * the transparency strategy, @see java.awt.Transparency. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + */ + public ComponentColorModel(ColorSpace colorSpace, int bits[], boolean hasAlpha, + boolean isAlphaPremultiplied, int transparency, int transferType) { + super(createPixelBits(colorSpace, hasAlpha, transferType), validateBits(bits, colorSpace, + hasAlpha, transferType), colorSpace, hasAlpha, isAlphaPremultiplied, transparency, + transferType); + + needScale = false; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + signed = false; + integral = true; + donotSupportUnnormalized = false; + scaleFactors = new float[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + scaleFactors[i] = 1.0f / maxValues[i]; + if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) { + donotSupportUnnormalized = true; + } + } + if (hasAlpha) { + maxValues[numColorComponents] = (1 << bits[numColorComponents]) - 1; + scaleFactors[numColorComponents] = 1.0f / maxValues[numColorComponents]; + } + break; + case DataBuffer.TYPE_SHORT: + signed = true; + integral = true; + donotSupportUnnormalized = true; + scaleFactors = new float[numComponents]; + for (int i = 0; i < numComponents; i++) { + maxValues[i] = Short.MAX_VALUE; + scaleFactors[i] = 1.0f / maxValues[i]; + if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) { + needScale = true; + } + } + if (needScale) { + minVals = new float[numColorComponents]; + ranges = new float[numColorComponents]; + for (int i = 0; i < numColorComponents; i++) { + minVals[i] = cs.getMinValue(i); + ranges[i] = cs.getMaxValue(i) - minVals[i]; + } + } + break; + case DataBuffer.TYPE_FLOAT: + case DataBuffer.TYPE_DOUBLE: + signed = true; + integral = false; + donotSupportUnnormalized = true; + break; + default: + // awt.215=transferType is not one of DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, + // DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or + // DataBuffer.TYPE_DOUBLE + throw new IllegalArgumentException(Messages.getString("awt.215")); //$NON-NLS-1$ + } + + needAlphaDivide = hasAlpha && isAlphaPremultiplied; + initLUTs(); + } + + /** + * Instantiates a new component color model. + * + * @param colorSpace + * the color space. + * @param hasAlpha + * whether the color model has alpha. + * @param isAlphaPremultiplied + * whether the alpha is pre-multiplied. + * @param transparency + * the transparency strategy, @see java.awt.Transparency. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + */ + public ComponentColorModel(ColorSpace colorSpace, boolean hasAlpha, + boolean isAlphaPremultiplied, int transparency, int transferType) { + + this(colorSpace, createPixelBitsArray(colorSpace, hasAlpha, transferType), hasAlpha, + isAlphaPremultiplied, transparency, transferType); + } + + /** + * Validate bits. + * + * @param bits + * the bits. + * @param colorSpace + * the color space. + * @param hasAlpha + * the has alpha. + * @param transferType + * the transfer type. + * @return the int[]. + */ + private static int[] validateBits(int bits[], ColorSpace colorSpace, boolean hasAlpha, + int transferType) { + if (bits != null) { + return bits; + } + + int numComponents = colorSpace.getNumComponents(); + if (hasAlpha) { + numComponents++; + } + bits = new int[numComponents]; + + int componentLength = DataBuffer.getDataTypeSize(transferType); + + for (int i = 0; i < numComponents; i++) { + bits[i] = componentLength; + } + + return bits; + } + + /** + * Creates the pixel bits. + * + * @param colorSpace + * the color space. + * @param hasAlpha + * the has alpha. + * @param transferType + * the transfer type. + * @return the int. + */ + private static int createPixelBits(ColorSpace colorSpace, boolean hasAlpha, int transferType) { + int numComponents = colorSpace.getNumComponents(); + if (hasAlpha) { + numComponents++; + } + int componentLength = DataBuffer.getDataTypeSize(transferType); + return numComponents * componentLength; + } + + /** + * Creates the pixel bits array. + * + * @param colorSpace + * the color space. + * @param hasAlpha + * the has alpha. + * @param transferType + * the transfer type. + * @return the int[]. + */ + private static int[] createPixelBitsArray(ColorSpace colorSpace, boolean hasAlpha, + int transferType) { + + int numComponents = colorSpace.getNumComponents(); + if (hasAlpha) { + numComponents++; + } + + int bits[] = new int[numComponents]; + for (int i = 0; i < numComponents; i++) { + bits[i] = DataBuffer.getDataTypeSize(transferType); + } + return bits; + } + + @Override + public Object getDataElements(int components[], int offset, Object obj) { + if (donotSupportUnnormalized) { + // awt.213=This ComponentColorModel does not support the + // unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + + if (offset + numComponents > components.length) { + // awt.216=The components array is not large enough to hold all the + // color and alpha components + throw new IllegalArgumentException(Messages.getString("awt.216")); //$NON-NLS-1$ + } + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[]; + if (obj == null) { + ba = new byte[numComponents]; + } else { + ba = (byte[])obj; + } + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + ba[i] = (byte)components[idx]; + } + return ba; + case DataBuffer.TYPE_USHORT: + short sa[]; + if (obj == null) { + sa = new short[numComponents]; + } else { + sa = (short[])obj; + } + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + sa[i] = (short)components[idx]; + } + return sa; + case DataBuffer.TYPE_INT: + int ia[]; + if (obj == null) { + ia = new int[numComponents]; + } else { + ia = (int[])obj; + } + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + ia[i] = components[idx]; + } + return ia; + default: + // awt.217=The transfer type of this ComponentColorModel is not + // one + // of the following transfer types: DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT + throw new UnsupportedOperationException(Messages.getString("awt.217")); //$NON-NLS-1$ + } + } + + @Override + public Object getDataElements(float normComponents[], int normOffset, Object obj) { + if (needScale) { + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + normComponents[idx] = (normComponents[idx] - minVals[i]) / ranges[i]; + } + } + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[]; + if (obj == null) { + ba = new byte[numComponents]; + } else { + ba = (byte[])obj; + } + + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = normOffset; i < numColorComponents; i++, idx++) { + ba[i] = (byte)(normComponents[idx] * alpha * maxValues[i] + 0.5f); + } + ba[numColorComponents] = (byte)(normComponents[normOffset + numColorComponents] + * maxValues[numColorComponents] + 0.5f); + } else { + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + ba[idx] = (byte)(normComponents[idx] * maxValues[i] + 0.5f); + } + } + return ba; + + case DataBuffer.TYPE_USHORT: + short usa[]; + if (obj == null) { + usa = new short[numComponents]; + } else { + usa = (short[])obj; + } + + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + usa[i] = (short)(normComponents[idx] * alpha * maxValues[i] + 0.5f); + } + usa[numColorComponents] = (short)(alpha * maxValues[numColorComponents] + 0.5f); + } else { + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + usa[i] = (short)(normComponents[idx] * maxValues[i] + 0.5f); + } + } + return usa; + + case DataBuffer.TYPE_INT: + int ia[]; + if (obj == null) { + ia = new int[numComponents]; + } else { + ia = (int[])obj; + } + + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + ia[i] = (int)(normComponents[idx] * alpha * maxValues[i] + 0.5f); + } + ia[numColorComponents] = (int)(alpha * maxValues[numColorComponents] + 0.5f); + } else { + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + ia[i] = (int)(normComponents[idx] * maxValues[i] + 0.5f); + } + } + return ia; + + case DataBuffer.TYPE_SHORT: + short sa[]; + if (obj == null) { + sa = new short[numComponents]; + } else { + sa = (short[])obj; + } + + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + sa[i] = (short)(normComponents[idx] * alpha * maxValues[i] + 0.5f); + } + sa[numColorComponents] = (short)(alpha * maxValues[numColorComponents] + 0.5f); + } else { + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + sa[i] = (short)(normComponents[idx] * maxValues[i] + 0.5f); + } + } + return sa; + + case DataBuffer.TYPE_FLOAT: + float fa[]; + if (obj == null) { + fa = new float[numComponents]; + } else { + fa = (float[])obj; + } + + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + fa[i] = normComponents[idx] * alpha; + } + fa[numColorComponents] = alpha; + } else { + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + fa[i] = normComponents[idx]; + } + } + return fa; + + case DataBuffer.TYPE_DOUBLE: + double da[]; + if (obj == null) { + da = new double[numComponents]; + } else { + da = (double[])obj; + } + + if (needAlphaDivide) { + double alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + da[i] = normComponents[idx] * alpha; + } + da[numColorComponents] = alpha; + } else { + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + da[i] = normComponents[idx]; + } + } + return da; + + default: + // awt.213=This ComponentColorModel does not support the + // unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + } + + @Override + public Object getDataElements(int rgb, Object pixel) { + float normComp[]; + float comp[]; + + int red = (rgb >> 16) & 0xff; + int green = (rgb >> 8) & 0xff; + int blue = rgb & 0xff; + int alpha = (rgb >> 24) & 0xff; + + comp = new float[3]; + if (is_sRGB || is_LINEAR_RGB) { + if (is_LINEAR_RGB) { + if (LINEAR_RGB_Length == 8) { + red = to_LINEAR_8RGB_LUT[red] & 0xff; + green = to_LINEAR_8RGB_LUT[green] & 0xff; + blue = to_LINEAR_8RGB_LUT[blue] & 0xff; + } else { + red = to_LINEAR_16RGB_LUT[red] & 0xffff; + green = to_LINEAR_16RGB_LUT[green] & 0xffff; + blue = to_LINEAR_16RGB_LUT[blue] & 0xffff; + } + } + comp[0] = red / fFactor; + comp[1] = green / fFactor; + comp[2] = blue / fFactor; + if (!hasAlpha) { + normComp = comp; + } else { + float normAlpha = alpha / 255.0f; + normComp = new float[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + normComp[i] = comp[i]; + } + normComp[numColorComponents] = normAlpha; + } + } else { + comp[0] = red / fFactor; + comp[1] = green / fFactor; + comp[2] = blue / fFactor; + float[] defComp = cs.fromRGB(comp); + if (!hasAlpha) { + normComp = defComp; + } else { + float normAlpha = alpha / 255.0f; + normComp = new float[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + normComp[i] = defComp[i]; + } + normComp[numColorComponents] = normAlpha; + } + } + if (hasAlpha && isAlphaPremultiplied) { + normComp[0] *= normComp[numColorComponents]; + normComp[1] *= normComp[numColorComponents]; + normComp[2] *= normComp[numColorComponents]; + } + + return getDataElements(normComp, 0, pixel); + } + + @Override + public WritableRaster getAlphaRaster(WritableRaster raster) { + if (!hasAlpha) { + return null; + } + + int x = raster.getMinX(); + int y = raster.getMinY(); + int bandList[] = new int[1]; + bandList[0] = raster.getNumBands() - 1; + + return raster.createWritableChild(x, y, raster.getWidth(), raster.getHeight(), x, y, + bandList); + } + + @Override + public ColorModel coerceData(WritableRaster raster, boolean isAlphaPremultiplied) { + if (!hasAlpha || this.isAlphaPremultiplied == isAlphaPremultiplied) { + return this; + } + + int minX = raster.getMinX(); + int minY = raster.getMinY(); + int w = raster.getWidth(); + int h = raster.getHeight(); + + if (isAlphaPremultiplied) { + switch (transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + float alphaFactor = maxValues[numColorComponents]; + int iComponents[] = null; + int iTransparentComponents[] = new int[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + iComponents = raster.getPixel(x, minY, iComponents); + if (iComponents[numColorComponents] == 0) { + raster.setPixel(x, minY, iTransparentComponents); + } else { + float alpha = iComponents[numColorComponents] / alphaFactor; + for (int n = 0; n < numColorComponents; n++) { + iComponents[n] = (int)(alpha * iComponents[n] + 0.5f); + } + raster.setPixel(x, minY, iComponents); + } + } + + } + break; + + case DataBuffer.TYPE_SHORT: + float sAlphaFactor = maxValues[numColorComponents]; + short sComponents[] = null; + short sTransparentComponents[] = new short[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + sComponents = (short[])raster.getDataElements(x, minY, sComponents); + if (sComponents[numColorComponents] == 0) { + raster.setDataElements(x, minY, sTransparentComponents); + } else { + float alpha = sComponents[numColorComponents] / sAlphaFactor; + for (int n = 0; n < numColorComponents; n++) { + sComponents[n] = (byte)(alpha * sComponents[n] + 0.5f); + } + raster.setDataElements(x, minY, sComponents); + } + } + + } + break; + + case DataBuffer.TYPE_FLOAT: + float fComponents[] = null; + float fTransparentComponents[] = new float[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + fComponents = raster.getPixel(x, minY, fComponents); + if (fComponents[numColorComponents] == 0.0f) { + raster.setDataElements(x, minY, fTransparentComponents); + } else { + float alpha = fComponents[numColorComponents]; + for (int n = 0; n < numColorComponents; n++) { + fComponents[n] = fComponents[n] * alpha; + } + raster.setPixel(x, minY, fComponents); + } + } + + } + break; + + case DataBuffer.TYPE_DOUBLE: + double dComponents[] = null; + double dTransparentComponents[] = new double[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + dComponents = raster.getPixel(x, minY, dComponents); + if (dComponents[numColorComponents] == 0.0) { + raster.setPixel(x, minY, dTransparentComponents); + } else { + double alpha = dComponents[numColorComponents]; + for (int n = 0; n < numColorComponents; n++) { + dComponents[n] = dComponents[n] * alpha; + } + raster.setPixel(x, minY, dComponents); + } + } + + } + break; + + default: + // awt.219=This transferType is not supported by this color + // model + throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$ + } + } else { + switch (transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + float alphaFactor = maxValues[numColorComponents]; + int iComponents[] = null; + int iTransparentComponents[] = new int[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + iComponents = raster.getPixel(x, minY, iComponents); + if (iComponents[numColorComponents] == 0) { + raster.setPixel(x, minY, iTransparentComponents); + } else { + float alpha = iComponents[numColorComponents] / alphaFactor; + for (int n = 0; n < numColorComponents; n++) { + iComponents[n] = (int)(iComponents[n] / alpha + 0.5f); + } + raster.setPixel(x, minY, iComponents); + } + } + + } + break; + + case DataBuffer.TYPE_SHORT: + float sAlphaFactor = maxValues[numColorComponents]; + short sComponents[] = null; + short sTransparentComponents[] = new short[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + sComponents = (short[])raster.getDataElements(x, minY, sComponents); + if (sComponents[numColorComponents] == 0) { + raster.setDataElements(x, minY, sTransparentComponents); + } else { + float alpha = sComponents[numColorComponents] / sAlphaFactor; + for (int n = 0; n < numColorComponents; n++) { + sComponents[n] = (byte)(sComponents[n] / alpha + 0.5f); + } + raster.setDataElements(x, minY, sComponents); + } + } + + } + break; + + case DataBuffer.TYPE_FLOAT: + float fComponents[] = null; + float fTransparentComponents[] = new float[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + fComponents = raster.getPixel(x, minY, fComponents); + if (fComponents[numColorComponents] == 0.0f) { + raster.setDataElements(x, minY, fTransparentComponents); + } else { + float alpha = fComponents[numColorComponents]; + for (int n = 0; n < numColorComponents; n++) { + fComponents[n] = fComponents[n] / alpha; + } + raster.setPixel(x, minY, fComponents); + } + } + + } + break; + + case DataBuffer.TYPE_DOUBLE: + double dComponents[] = null; + double dTransparentComponents[] = new double[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + dComponents = raster.getPixel(x, minY, dComponents); + if (dComponents[numColorComponents] == 0.0) { + raster.setPixel(x, minY, dTransparentComponents); + } else { + double alpha = dComponents[numColorComponents]; + for (int n = 0; n < numColorComponents; n++) { + dComponents[n] = dComponents[n] / alpha; + } + raster.setPixel(x, minY, dComponents); + } + } + + } + break; + default: + // awt.219=This transferType is not supported by this color + // model + throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$ + } + } + + if (!signed) { + return new ComponentColorModel(cs, bits, hasAlpha, isAlphaPremultiplied, transparency, + transferType); + } + + return new ComponentColorModel(cs, null, hasAlpha, isAlphaPremultiplied, transparency, + transferType); + } + + @Override + public int[] getComponents(Object pixel, int[] components, int offset) { + if (donotSupportUnnormalized) { + // awt.213=This ComponentColorModel does not support the + // unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + + if (components == null) { + components = new int[offset + numComponents]; + } else if (offset + numComponents > components.length) { + // awt.218=The components array is not large enough to hold all the + // color and alpha components + throw new IllegalArgumentException(Messages.getString("awt.218")); //$NON-NLS-1$ + } + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])pixel; + + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + components[idx] = ba[i] & 0xff; + } + return components; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])pixel; + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + components[idx] = sa[i] & 0xffff; + } + return components; + + case DataBuffer.TYPE_INT: + int ia[] = (int[])pixel; + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + components[idx] = ia[i]; + } + return components; + + default: + // awt.217=The transfer type of this ComponentColorModel is not + // one + // of the following transfer types: DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT + throw new UnsupportedOperationException(Messages.getString("awt.217")); //$NON-NLS-1$ + } + + } + + @Override + public float[] getNormalizedComponents(Object pixel, float normComponents[], int normOffset) { + + if (normComponents == null) { + normComponents = new float[numComponents + normOffset]; + } + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = (ba[i] & 0xff) * scaleFactors[i]; + } + break; + + case DataBuffer.TYPE_USHORT: + short usa[] = (short[])pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = (usa[i] & 0xffff) * scaleFactors[i]; + } + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[])pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = ia[i] * scaleFactors[i]; + } + break; + + case DataBuffer.TYPE_SHORT: + short sa[] = (short[])pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = sa[i] * scaleFactors[i]; + } + break; + + case DataBuffer.TYPE_FLOAT: + float fa[] = (float[])pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = fa[i]; + } + break; + + case DataBuffer.TYPE_DOUBLE: + double da[] = (double[])pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = (float)da[i]; + } + break; + + default: + // awt.21A=This ComponentColorModel does not support this + // transferType + throw new IllegalArgumentException(Messages.getString("awt.21A")); //$NON-NLS-1$ + } + + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = normOffset; i < numColorComponents; i++, idx++) { + normComponents[idx] /= alpha; + } + } + + if (needScale) { + for (int i = 0, idx = normOffset; i < numColorComponents; i++, idx++) { + normComponents[idx] = minVals[i] + ranges[i] * normComponents[idx]; + } + } + return normComponents; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ComponentColorModel)) { + return false; + } + return super.equals(obj); + } + + @Override + public int getRed(Object inData) { + return getRGBComponent(inData, 0); + } + + @Override + public int getRGB(Object inData) { + int alpha = getAlpha(inData); + if (cs.getType() == ColorSpace.TYPE_GRAY) { + int gray = getRed(inData); + return (alpha << 24 | gray << 16 | gray << 8 | gray); + } + return (alpha << 24 | getRed(inData) << 16 | getGreen(inData) << 8 | getBlue(inData)); + } + + @Override + public int getGreen(Object inData) { + return getRGBComponent(inData, 1); + } + + @Override + public int getBlue(Object inData) { + return getRGBComponent(inData, 2); + } + + @Override + public int getAlpha(Object inData) { + if (!hasAlpha) { + return 255; + } + int alpha = 0; + + switch (transferType) { + case DataBuffer.TYPE_BYTE: { + byte ba[] = (byte[])inData; + alpha = ba[numColorComponents] & 0xff; + if (bits[numColorComponents] != 8) { + return alphaLUT[alpha] & 0xff; + } + return alpha; + } + case DataBuffer.TYPE_USHORT: { + short usa[] = (short[])inData; + alpha = usa[numColorComponents] & 0xffff; + if (bits[numColorComponents] != 8) { + return alphaLUT[alpha] & 0xff; + } + return alpha; + } + case DataBuffer.TYPE_INT: { + int ia[] = (int[])inData; + alpha = ia[numColorComponents]; + if (bits[numColorComponents] != 8) { + return alphaLUT[alpha] & 0xff; + } + return alpha; + } + case DataBuffer.TYPE_SHORT: { + short sa[] = (short[])inData; + alpha = sa[numColorComponents]; + if (bits[numColorComponents] != 8) { + return alphaLUT[alpha] & 0xff; + } + return alpha; + } + case DataBuffer.TYPE_FLOAT: { + float fa[] = (float[])inData; + return (int)(fa[numColorComponents] * 255.0f + 0.5f); + } + case DataBuffer.TYPE_DOUBLE: { + double da[] = (double[])inData; + return (int)(da[numColorComponents] * 255.0 + 0.5); + } + default: { + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + } + } + + @Override + public WritableRaster createCompatibleWritableRaster(int w, int h) { + SampleModel sm = createCompatibleSampleModel(w, h); + DataBuffer db = sm.createDataBuffer(); + return Raster.createWritableRaster(sm, db, null); + } + + @Override + public boolean isCompatibleSampleModel(SampleModel sm) { + if (!(sm instanceof ComponentSampleModel)) { + return false; + } + if (numComponents != sm.getNumBands()) { + return false; + } + if (transferType != sm.getTransferType()) { + return false; + } + return true; + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + int bandOffsets[] = new int[numComponents]; + for (int i = 0; i < numComponents; i++) { + bandOffsets[i] = i; + } + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + return new PixelInterleavedSampleModel(transferType, w, h, numComponents, w + * numComponents, bandOffsets); + + default: + return new ComponentSampleModel(transferType, w, h, numComponents, w + * numComponents, bandOffsets); + } + } + + @Override + public boolean isCompatibleRaster(Raster raster) { + SampleModel sm = raster.getSampleModel(); + if (!(sm instanceof ComponentSampleModel)) { + return false; + } + + if (sm.getNumBands() != numComponents) { + return false; + } + if (raster.getTransferType() != transferType) { + return false; + } + + int sampleSizes[] = sm.getSampleSize(); + for (int i = 0; i < numComponents; i++) { + if (bits[i] != sampleSizes[i]) { + return false; + } + } + return true; + } + + @Override + public float[] getNormalizedComponents(int components[], int offset, float normComponents[], + int normOffset) { + if (donotSupportUnnormalized) { + // awt.213=This ComponentColorModel does not support the + // unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + + return super.getNormalizedComponents(components, offset, normComponents, normOffset); + } + + @Override + public int getDataElement(int[] components, int offset) { + if (numComponents > 1) { + // awt.212=There is more than one component in this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$ + } + if (donotSupportUnnormalized) { + // awt.213=This ComponentColorModel does not support the + // unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + return components[offset]; + } + + @Override + public int[] getUnnormalizedComponents(float[] normComponents, int normOffset, + int[] components, int offset) { + + if (donotSupportUnnormalized) { + // awt.213=This ComponentColorModel does not support the + // unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + + if (normComponents.length - normOffset < numComponents) { + // awt.21B=The length of normComponents minus normOffset is less + // than numComponents + throw new IllegalArgumentException(Messages.getString("awt.21B")); //$NON-NLS-1$ + } + + return super.getUnnormalizedComponents(normComponents, normOffset, components, offset); + } + + @Override + public int getDataElement(float normComponents[], int normOffset) { + if (numComponents > 1) { + // awt.212=There is more than one component in this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$ + } + if (signed) { + // awt.210=The component value for this ColorModel is signed + throw new IllegalArgumentException(Messages.getString("awt.210")); //$NON-NLS-1$ + } + + Object pixel = getDataElements(normComponents, normOffset, null); + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])pixel; + return ba[0] & 0xff; + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])pixel; + return sa[0] & 0xffff; + case DataBuffer.TYPE_INT: + int ia[] = (int[])pixel; + return ia[0]; + default: + // awt.211=Pixel values for this ColorModel are not conveniently + // representable as a single int + throw new IllegalArgumentException(Messages.getString("awt.211")); //$NON-NLS-1$ + } + } + + @Override + public int[] getComponents(int pixel, int components[], int offset) { + if (numComponents > 1) { + // awt.212=There is more than one component in this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$ + } + if (donotSupportUnnormalized) { + // awt.213=This ComponentColorModel does not support the + // unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + + if (components == null) { + components = new int[offset + 1]; + } + + components[offset] = pixel & maxValues[0]; + return components; + } + + @Override + public int getRed(int pixel) { + float rgb[] = toRGB(pixel); + return (int)(rgb[0] * 255.0f + 0.5f); + } + + @Override + public int getRGB(int pixel) { + return (getAlpha(pixel) << 24) | (getRed(pixel) << 16) | (getGreen(pixel) << 8) + | getBlue(pixel); + } + + @Override + public int getGreen(int pixel) { + float rgb[] = toRGB(pixel); + return (int)(rgb[1] * 255.0f + 0.5f); + } + + @Override + public int getBlue(int pixel) { + float rgb[] = toRGB(pixel); + return (int)(rgb[2] * 255.0f + 0.5f); + } + + @Override + public int getAlpha(int pixel) { + + // This method throw IllegalArgumentException according to + // Java API Spacification + if (signed) { + // awt.210=The component value for this ColorModel is signed + throw new IllegalArgumentException(Messages.getString("awt.210")); //$NON-NLS-1$ + } + + if (numComponents > 1) { + // awt.212=There is more than one component in this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$ + } + + return 255; + } + + /** + * Initialization of Lookup tables. + */ + private void initLUTs() { + is_sRGB = cs.isCS_sRGB(); + is_LINEAR_RGB = (cs == LUTColorConverter.LINEAR_RGB_CS); + + if (hasAlpha && bits[numColorComponents] != 8 && integral) { + alphaLUT = new byte[maxValues[numColorComponents] + 1]; + for (int i = 0; i <= maxValues[numColorComponents]; i++) { + alphaLUT[i] = (byte)(scaleFactors[numColorComponents] * i + 0.5f); + } + } + + if (is_LINEAR_RGB) { + if (maxBitLength > 8) { + LINEAR_RGB_Length = 16; + from_LINEAR_RGB_LUT = LUTColorConverter.getFrom16lRGBtosRGB_LUT(); + to_LINEAR_16RGB_LUT = LUTColorConverter.getFromsRGBto16lRGB_LUT(); + } else { + LINEAR_RGB_Length = 8; + from_LINEAR_RGB_LUT = LUTColorConverter.getFrom8lRGBtosRGB_LUT(); + to_LINEAR_8RGB_LUT = LUTColorConverter.getFromsRGBto8lRGB_LUT(); + } + fFactor = ((1 << LINEAR_RGB_Length) - 1); + } else { + fFactor = 255.0f; + } + + if (!isAlphaPremultiplied && integral) { + colorLUTs = new byte[3][]; + + if (is_sRGB) { + for (int i = 0; i < numColorComponents; i++) { + if (bits[i] != 8) { + for (int j = 0; j < i; j++) { + if (bits[i] == bits[j]) { + colorLUTs[i] = colorLUTs[j]; + break; + } + } + colorLUTs[i] = new byte[maxValues[i] + 1]; + for (int j = 0; j <= maxValues[0]; j++) { + colorLUTs[i][j] = (byte)(scaleFactors[i] * j + 0.5f); + } + } + } + } + + if (is_LINEAR_RGB) { + + for (int i = 0; i < numColorComponents; i++) { + if (bits[i] != LINEAR_RGB_Length) { + for (int j = 0; j < i; j++) { + if (bits[i] == bits[j]) { + colorLUTs[i] = colorLUTs[j]; + break; + } + } + colorLUTs[i] = new byte[maxValues[i] + 1]; + for (int j = 0; j <= maxValues[0]; j++) { + int idx; + if (LINEAR_RGB_Length == 8) { + idx = (int)(scaleFactors[i] * j + 0.5f); + } else { + idx = (int)(scaleFactors[i] * j * 257.0f + 0.5f); + } + colorLUTs[i][j] = from_LINEAR_RGB_LUT[idx]; + } + } + } + } + + } + } + + /** + * To rgb. + * + * @param pixel + * the integer representation of the pixel. + * @return the array of normalized sRGB components. + */ + private float[] toRGB(int pixel) { + + // This method throw IllegalArgumentException according to + // Java API Spacification + if (signed) { + // awt.210=The component value for this ColorModel is signed + throw new IllegalArgumentException(Messages.getString("awt.210")); //$NON-NLS-1$ + } + + if (numComponents > 1) { + // awt.212=There is more than one component in this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$ + } + + Object obj = null; + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = new byte[1]; + ba[0] = (byte)pixel; + obj = ba; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = new short[1]; + sa[0] = (short)pixel; + obj = sa; + break; + + case DataBuffer.TYPE_INT: + int ia[] = new int[1]; + ia[0] = pixel; + obj = ia; + break; + + } + + return cs.toRGB(getNormalizedComponents(obj, null, 0)); + } + + /** + * Gets the RGB component. + * + * @param pixel + * the pixel. + * @param idx + * the index of component. + * @return the RGB value from 0 to 255 pixel's component. + */ + private int getRGBComponent(Object pixel, int idx) { + if (is_sRGB) { + int comp = getDefComponent(pixel, idx); + if (calcValue || bits[idx] == 8) { + return comp; + } + return colorLUTs[idx][comp] & 0xff; + } else if (is_LINEAR_RGB) { + int comp = getDefComponent(pixel, idx); + if (calcValue || bits[idx] == LINEAR_RGB_Length) { + return from_LINEAR_RGB_LUT[comp] & 0xff; + } + return colorLUTs[idx][comp] & 0xff; + } + + float normComp[] = getNormalizedComponents(pixel, null, 0); + float rgbComp[] = cs.toRGB(normComp); + return (int)(rgbComp[idx] * 255.0f + 0.5f); + } + + /** + * Gets the def component. + * + * @param pixel + * the pixel. + * @param idx + * the index of component. + * @return the tentative value of the pixel component. + */ + private int getDefComponent(Object pixel, int idx) { + int comp = 0; + calcValue = false; + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])pixel; + comp = ba[idx] & 0xff; + if (needAlphaDivide) { + int alpha = ba[numColorComponents] & 0xff; + if (alpha == 0) { + comp = 0; + } else { + float normAlpha = scaleFactors[numColorComponents] * alpha; + comp = (int)(comp * fFactor / normAlpha + 0.5f); + } + calcValue = true; + } + return comp; + + case DataBuffer.TYPE_USHORT: + short usa[] = (short[])pixel; + comp = usa[idx] & 0xffff; + if (needAlphaDivide) { + int alpha = usa[numColorComponents] & 0xffff; + if (alpha == 0) { + comp = 0; + } else { + float normAlpha = scaleFactors[numColorComponents] * alpha; + comp = (int)(comp * fFactor / normAlpha + 0.5f); + } + calcValue = true; + } + return comp; + + case DataBuffer.TYPE_INT: + int ia[] = (int[])pixel; + comp = ia[idx]; + if (needAlphaDivide) { + int alpha = ia[numColorComponents]; + if (alpha == 0) { + comp = 0; + } else { + float normAlpha = scaleFactors[numColorComponents] * alpha; + comp = (int)(comp * fFactor / normAlpha + 0.5f); + } + calcValue = true; + } + return comp; + + case DataBuffer.TYPE_SHORT: + short sa[] = (short[])pixel; + comp = sa[idx]; + if (needAlphaDivide) { + int alpha = sa[numColorComponents]; + if (alpha == 0) { + comp = 0; + } else { + float normAlpha = scaleFactors[numColorComponents] * alpha; + comp = (int)(comp * fFactor / normAlpha + 0.5f); + } + calcValue = true; + } + return comp; + + case DataBuffer.TYPE_FLOAT: + float fa[] = (float[])pixel; + if (needAlphaDivide) { + float alpha = fa[numColorComponents]; + if (fa[numColorComponents] == 0.0f) { + comp = 0; + } else { + comp = (int)(fa[idx] * fFactor / alpha + 0.5f); + } + } else { + comp = (int)(fa[idx] * fFactor + 0.5f); + } + calcValue = true; + return comp; + + case DataBuffer.TYPE_DOUBLE: + double da[] = (double[])pixel; + if (needAlphaDivide) { + if (da[numColorComponents] == 0.0) { + comp = 0; + } else { + comp = (int)(da[idx] * fFactor / da[numColorComponents] + 0.5); + } + } else { + comp = (int)(da[idx] * fFactor + 0.5); + } + calcValue = true; + return comp; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + } + +} diff --git a/awt/java/awt/image/ComponentSampleModel.java b/awt/java/awt/image/ComponentSampleModel.java new file mode 100644 index 0000000..7f81409 --- /dev/null +++ b/awt/java/awt/image/ComponentSampleModel.java @@ -0,0 +1,705 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.util.Arrays; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The ComponentSampleModel class represents a set of image data whose each + * element - the sample of a pixel - takes one data element of the DataBuffer. + * <p> + * The Bank indices denote the correspondence between the bank of data buffers + * and a band of image data. The Pixel stride is the number of data array + * elements between two samples for the same band on the same scanline. The + * pixel stride for a BandedSampleModel is one. The scanline stride represents + * the number of data array elements between a specified sample and the + * corresponding sample in the same column in the next scanline. The array of + * band offsets gives the starting offsets within each data banks of the in the + * DataBuffer. The bank indices represents the indices within each bank of the + * DataBuffer corresponding to a band of image data. + * + * @since Android 1.0 + */ +public class ComponentSampleModel extends SampleModel { + + /** + * The band offsets array of this ComponentSampleModel. + */ + protected int bandOffsets[]; + + /** + * The bank indices array of this ComponentSampleModel. + */ + protected int bankIndices[]; + + /** + * The number of bands in this ComponentSampleModel. + */ + protected int numBands; + + /** + * The number banks of this ComponentSampleModel. + */ + protected int numBanks; + + /** + * The scanline stride of this ComponentSampleModel. + */ + protected int scanlineStride; + + /** + * The pixel stride of this ComponentSampleModel. + */ + protected int pixelStride; + + /** + * Instantiates a new ComponentSampleModel with the specified properties. + * + * @param dataType + * the data type of samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param pixelStride + * the pixel stride of the image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param bankIndices + * the array of the bank indices. + * @param bandOffsets + * the array of the band offsets. + */ + public ComponentSampleModel(int dataType, int w, int h, int pixelStride, int scanlineStride, + int bankIndices[], int bandOffsets[]) { + + super(dataType, w, h, bandOffsets.length); + + if (pixelStride < 0) { + // awt.24B=Pixel stride must be >= 0 + throw new IllegalArgumentException(Messages.getString("awt.24B")); //$NON-NLS-1$ + } + + if (scanlineStride < 0) { + // awt.24C=Scanline stride must be >= 0 + throw new IllegalArgumentException(Messages.getString("awt.24C")); //$NON-NLS-1$ + } + + if (bankIndices.length != bandOffsets.length) { + // awt.24D=Bank Indices length must be equal Bank Offsets length + throw new IllegalArgumentException(Messages.getString("awt.24D")); //$NON-NLS-1$ + } + + this.pixelStride = pixelStride; + this.scanlineStride = scanlineStride; + this.bandOffsets = bandOffsets.clone(); + this.bankIndices = bankIndices.clone(); + this.numBands = bandOffsets.length; + + int maxBank = 0; + for (int i = 0; i < bankIndices.length; i++) { + if (bankIndices[i] < 0) { + // awt.24E=Index of {0} bank must be >= 0 + throw new IllegalArgumentException(Messages.getString("awt.24E", i)); //$NON-NLS-1$ + } + if (bankIndices[i] > maxBank) { + maxBank = bankIndices[i]; + } + } + this.numBanks = maxBank + 1; + + } + + /** + * Instantiates a new ComponentSampleModel with the specified properties. + * + * @param dataType + * the data type of the samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param pixelStride + * the pixel stride of the image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param bandOffsets + * the band offsets. + */ + public ComponentSampleModel(int dataType, int w, int h, int pixelStride, int scanlineStride, + int bandOffsets[]) { + + super(dataType, w, h, bandOffsets.length); + if (pixelStride < 0) { + // awt.24B=Pixel stride must be >= 0 + throw new IllegalArgumentException(Messages.getString("awt.24B")); //$NON-NLS-1$ + } + + if (scanlineStride < 0) { + // awt.24C=Scanline stride must be >= 0 + throw new IllegalArgumentException(Messages.getString("awt.24C")); //$NON-NLS-1$ + } + + this.pixelStride = pixelStride; + this.scanlineStride = scanlineStride; + this.bandOffsets = bandOffsets.clone(); + this.numBands = bandOffsets.length; + this.numBanks = 1; + + this.bankIndices = new int[numBands]; + for (int i = 0; i < numBands; i++) { + bankIndices[i] = 0; + } + } + + @Override + public Object getDataElements(int x, int y, Object obj, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + switch (dataType) { + case DataBuffer.TYPE_BYTE: + byte bdata[]; + if (obj == null) { + bdata = new byte[numBands]; + } else { + bdata = (byte[])obj; + } + + for (int i = 0; i < numBands; i++) { + bdata[i] = (byte)getSample(x, y, i, data); + } + + obj = bdata; + break; + + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short sdata[]; + if (obj == null) { + sdata = new short[numBands]; + } else { + sdata = (short[])obj; + } + + for (int i = 0; i < numBands; i++) { + sdata[i] = (short)getSample(x, y, i, data); + } + + obj = sdata; + break; + + case DataBuffer.TYPE_INT: + int idata[]; + if (obj == null) { + idata = new int[numBands]; + } else { + idata = (int[])obj; + } + + for (int i = 0; i < numBands; i++) { + idata[i] = getSample(x, y, i, data); + } + + obj = idata; + break; + + case DataBuffer.TYPE_FLOAT: + float fdata[]; + if (obj == null) { + fdata = new float[numBands]; + } else { + fdata = (float[])obj; + } + + for (int i = 0; i < numBands; i++) { + fdata[i] = getSampleFloat(x, y, i, data); + } + + obj = fdata; + break; + + case DataBuffer.TYPE_DOUBLE: + double ddata[]; + if (obj == null) { + ddata = new double[numBands]; + } else { + ddata = (double[])obj; + } + + for (int i = 0; i < numBands; i++) { + ddata[i] = getSampleDouble(x, y, i, data); + } + + obj = ddata; + break; + } + + return obj; + } + + @Override + public void setDataElements(int x, int y, Object obj, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + switch (dataType) { + case DataBuffer.TYPE_BYTE: + byte barr[] = (byte[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, barr[i] & 0xff, data); + } + break; + + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short sarr[] = (short[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, sarr[i] & 0xffff, data); + } + break; + + case DataBuffer.TYPE_INT: + int iarr[] = (int[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, iarr[i], data); + } + break; + + case DataBuffer.TYPE_FLOAT: + float farr[] = (float[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, farr[i], data); + } + break; + + case DataBuffer.TYPE_DOUBLE: + double darr[] = (double[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, darr[i], data); + } + break; + } + } + + /** + * Compares this ComponentSampleModel with the specified Object. + * + * @param o + * the Object. + * @return true, if the object is a ComponentSampleModel with identical data + * values to this ComponentSampleModel, false otherwise. + */ + @Override + public boolean equals(Object o) { + if ((o == null) || !(o instanceof ComponentSampleModel)) { + return false; + } + ComponentSampleModel model = (ComponentSampleModel)o; + return this.width == model.width && this.height == model.height + && this.numBands == model.numBands && this.dataType == model.dataType + && Arrays.equals(this.bandOffsets, model.bandOffsets) + && Arrays.equals(this.bankIndices, model.bankIndices) + && this.numBands == model.numBands && this.numBanks == model.numBanks + && this.scanlineStride == model.scanlineStride + && this.pixelStride == model.pixelStride; + } + + /** + * @see java.awt.image.SampleModel#createSubsetSampleModel(int[]) + */ + @Override + public SampleModel createSubsetSampleModel(int bands[]) { + if (bands.length > this.numBands) { + // awt.64=The number of the bands in the subset is greater than the + // number of bands in the sample model + throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$ + } + + int indices[] = new int[bands.length]; + int offsets[] = new int[bands.length]; + + for (int i = 0; i < bands.length; i++) { + indices[i] = bankIndices[bands[i]]; + offsets[i] = bandOffsets[bands[i]]; + } + + return new ComponentSampleModel(dataType, width, height, pixelStride, scanlineStride, + indices, offsets); + + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + return new ComponentSampleModel(dataType, w, h, pixelStride, pixelStride * w, bankIndices, + bandOffsets); + } + + @Override + public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { + int pixel[]; + + if (iArray == null) { + pixel = new int[numBands]; + } else { + pixel = iArray; + } + + for (int i = 0; i < numBands; i++) { + pixel[i] = getSample(x, y, i, data); + } + + return pixel; + } + + @Override + public void setPixel(int x, int y, int iArray[], DataBuffer data) { + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, iArray[i], data); + } + } + + @Override + public int getSample(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + return data.getElem(bankIndices[b], y * scanlineStride + x * pixelStride + bandOffsets[b]); + } + + @Override + public float getSampleFloat(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + return data.getElemFloat(bankIndices[b], y * scanlineStride + x * pixelStride + + bandOffsets[b]); + } + + @Override + public double getSampleDouble(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + return data.getElemDouble(bankIndices[b], y * scanlineStride + x * pixelStride + + bandOffsets[b]); + } + + @Override + public int[] getPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x > this.width || x + w > this.width || y > this.height + || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int pixels[] = null; + int idx = 0; + + if (iArray == null) { + pixels = new int[w * h * numBands]; + } else { + pixels = iArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + pixels[idx++] = getSample(j, i, n, data); + } + } + } + + return pixels; + } + + @Override + public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + setSample(j, i, n, iArray[idx++], data); + } + } + } + } + + @Override + public void setSample(int x, int y, int b, int s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + data.setElem(bankIndices[b], y * scanlineStride + x * pixelStride + bandOffsets[b], s); + } + + @Override + public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int samples[]; + int idx = 0; + + if (iArray == null) { + samples = new int[w * h]; + } else { + samples = iArray; + } + + if (data == null) { + // awt.295=data is null + throw new NullPointerException(Messages.getString("awt.295")); //$NON-NLS-1$ + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + samples[idx++] = getSample(j, i, b, data); + } + } + + return samples; + } + + @Override + public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + setSample(j, i, b, iArray[idx++], data); + } + } + } + + @Override + public void setSample(int x, int y, int b, float s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + data.setElemFloat(bankIndices[b], y * scanlineStride + x * pixelStride + bandOffsets[b], s); + } + + @Override + public void setSample(int x, int y, int b, double s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + data + .setElemDouble(bankIndices[b], y * scanlineStride + x * pixelStride + + bandOffsets[b], s); + } + + @Override + public DataBuffer createDataBuffer() { + DataBuffer data = null; + + int maxOffset = bandOffsets[0]; + for (int i = 1; i < bandOffsets.length; i++) { + if (bandOffsets[i] > maxOffset) { + maxOffset = bandOffsets[i]; + } + } + int size = (height - 1) * scanlineStride + (width - 1) * pixelStride + maxOffset + 1; + + switch (dataType) { + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(size, numBanks); + break; + case DataBuffer.TYPE_SHORT: + data = new DataBufferShort(size, numBanks); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(size, numBanks); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(size, numBanks); + break; + case DataBuffer.TYPE_FLOAT: + data = new DataBufferFloat(size, numBanks); + break; + case DataBuffer.TYPE_DOUBLE: + data = new DataBufferDouble(size, numBanks); + break; + } + + return data; + + } + + /** + * Gets the offset of the specified band of the specified pixel. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the band. + * @return the offset of the specified band of the specified pixel. + */ + public int getOffset(int x, int y, int b) { + return y * scanlineStride + x * pixelStride + bandOffsets[b]; + } + + /** + * Gets the offset of the first band of the specified pixel. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @return the offset of the first band of the specified pixel. + */ + public int getOffset(int x, int y) { + return y * scanlineStride + x * pixelStride + bandOffsets[0]; + } + + @Override + public final int getSampleSize(int band) { + return DataBuffer.getDataTypeSize(dataType); + } + + @Override + public final int[] getSampleSize() { + int sampleSizes[] = new int[numBands]; + int size = DataBuffer.getDataTypeSize(dataType); + + for (int i = 0; i < numBands; i++) { + sampleSizes[i] = size; + } + return sampleSizes; + } + + /** + * Gets an array of bank indices corresponding to this ComponentSampleModel. + * + * @return the array of bank indices. + */ + public final int[] getBankIndices() { + return bankIndices.clone(); + } + + /** + * Gets an array of the band offsets corresponding to this + * ComponentSampleModel. + * + * @return the array of band offsets. + */ + public final int[] getBandOffsets() { + return bandOffsets.clone(); + } + + /** + * Gets a hash code of this ComponentSampleModel object. + * + * @return a hash code of this ComponentSampleModel object. + */ + @Override + public int hashCode() { + int hash = 0; + int tmp = 0; + + hash = width; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= height; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= numBands; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= dataType; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + for (int element : bandOffsets) { + hash ^= element; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + } + for (int element : bankIndices) { + hash ^= element; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + } + hash ^= pixelStride; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + + hash ^= scanlineStride; + return hash; + } + + /** + * Gets the scanline stride of this ComponentSampleModel. + * + * @return the scanline stride of this ComponentSampleModel. + */ + public final int getScanlineStride() { + return scanlineStride; + } + + /** + * Gets the pixel stride. + * + * @return the pixel stride. + */ + public final int getPixelStride() { + return pixelStride; + } + + @Override + public final int getNumDataElements() { + return numBands; + } + +} diff --git a/awt/java/awt/image/ConvolveOp.java b/awt/java/awt/image/ConvolveOp.java new file mode 100644 index 0000000..6eb8909 --- /dev/null +++ b/awt/java/awt/image/ConvolveOp.java @@ -0,0 +1,545 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Sep 29, 2005 + */ + +package java.awt.image; + +import java.awt.*; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.Arrays; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The ConvolveOp class convolves from the source data to the destination using + * a convolution kernel. Each output pixel is represented as the result of + * multiplying the kernel and the surround of the input pixel. + * + * @since Android 1.0 + */ +public class ConvolveOp implements BufferedImageOp, RasterOp { + + /** + * The Constant EDGE_ZERO_FILL indicates that pixels at the edge of the + * destination image are set to zero. + */ + public static final int EDGE_ZERO_FILL = 0; + + /** + * The Constant EDGE_NO_OP indicates that pixels at the edge of the source + * image are converted to the edge pixels in the destination without + * modification. + */ + public static final int EDGE_NO_OP = 1; + + /** + * The kernel. + */ + private Kernel kernel; + + /** + * The edge cond. + */ + private int edgeCond; + + /** + * The rhs. + */ + private RenderingHints rhs = null; + + static { + // TODO + // System.loadLibrary("imageops"); + } + + /** + * Instantiates a new ConvolveOp object with the specified Kernel and + * specified edges condition. + * + * @param kernel + * the specified Kernel. + * @param edgeCondition + * the specified edge condition. + * @param hints + * the RenderingHints object, or null. + */ + public ConvolveOp(Kernel kernel, int edgeCondition, RenderingHints hints) { + this.kernel = kernel; + this.edgeCond = edgeCondition; + this.rhs = hints; + } + + /** + * Instantiates a new ConvolveOp object with the specified Kernel and + * EDGE_ZERO_FILL edge condition. + * + * @param kernel + * the specified Kernel. + */ + public ConvolveOp(Kernel kernel) { + this.kernel = kernel; + this.edgeCond = EDGE_ZERO_FILL; + } + + /** + * Gets the Kernel object of this ConvolveOp. + * + * @return the Kernel object of this ConvolveOp. + */ + public final Kernel getKernel() { + return (Kernel)kernel.clone(); + } + + public final RenderingHints getRenderingHints() { + return rhs; + } + + /** + * Gets the edge condition of this ConvolveOp. + * + * @return the edge condition: EDGE_NO_OP or EDGE_ZERO_FILL. + */ + public int getEdgeCondition() { + return edgeCond; + } + + public final Rectangle2D getBounds2D(Raster src) { + return src.getBounds(); + } + + public final Rectangle2D getBounds2D(BufferedImage src) { + return getBounds2D(src.getRaster()); + } + + public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { + if (dstPt == null) { + dstPt = new Point2D.Float(); + } + + dstPt.setLocation(srcPt); + return dstPt; + } + + public WritableRaster createCompatibleDestRaster(Raster src) { + return src.createCompatibleWritableRaster(); + } + + public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) { + if (dstCM == null) { + dstCM = src.getColorModel(); + } + + if (dstCM instanceof IndexColorModel) { + dstCM = ColorModel.getRGBdefault(); + } + + WritableRaster r = dstCM.isCompatibleSampleModel(src.getSampleModel()) ? src.getRaster() + .createCompatibleWritableRaster(src.getWidth(), src.getHeight()) : dstCM + .createCompatibleWritableRaster(src.getWidth(), src.getHeight()); + + return new BufferedImage(dstCM, r, dstCM.isAlphaPremultiplied(), null); + } + + public final WritableRaster filter(Raster src, WritableRaster dst) { + if (src == null) { // Should throw according to spec + // awt.256=Source raster is null + throw new NullPointerException(Messages.getString("awt.256")); //$NON-NLS-1$ + } + + if (src == dst) { + // awt.257=Source raster is equal to destination + throw new IllegalArgumentException(Messages.getString("awt.257")); //$NON-NLS-1$ + } + + if (dst == null) { + dst = createCompatibleDestRaster(src); + } else if (src.getNumBands() != dst.getNumBands()) { + // awt.258=Number of source bands ({0}) is not equal to number of + // destination bands ({1}) + throw new IllegalArgumentException(Messages.getString( + "awt.258", src.getNumBands(), dst.getNumBands())); //$NON-NLS-1$ + } + + // TODO + // if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM) != 0) + if (slowFilter(src, dst) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + } + + return dst; + } + + /** + * Slow filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @return the int. + */ + private int slowFilter(Raster src, WritableRaster dst) { + try { + SampleModel sm = src.getSampleModel(); + + int numBands = src.getNumBands(); + int srcHeight = src.getHeight(); + int srcWidth = src.getWidth(); + + int xOrigin = kernel.getXOrigin(); + int yOrigin = kernel.getYOrigin(); + int kWidth = kernel.getWidth(); + int kHeight = kernel.getHeight(); + float[] data = kernel.getKernelData(null); + + int srcMinX = src.getMinX(); + int srcMinY = src.getMinY(); + int dstMinX = dst.getMinX(); + int dstMinY = dst.getMinY(); + + int srcConvMaxX = srcWidth - (kWidth - xOrigin - 1); + int srcConvMaxY = srcHeight - (kHeight - yOrigin - 1); + + int[] maxValues = new int[numBands]; + int[] masks = new int[numBands]; + int[] sampleSizes = sm.getSampleSize(); + + for (int i = 0; i < numBands; i++) { + maxValues[i] = (1 << sampleSizes[i]) - 1; + masks[i] = ~(maxValues[i]); + } + + // Processing bounds + float[] pixels = null; + pixels = src.getPixels(srcMinX, srcMinY, srcWidth, srcHeight, pixels); + float[] newPixels = new float[pixels.length]; + int rowLength = srcWidth * numBands; + if (this.edgeCond == ConvolveOp.EDGE_NO_OP) { + // top + int start = 0; + int length = yOrigin * rowLength; + System.arraycopy(pixels, start, newPixels, start, length); + // bottom + start = (srcHeight - (kHeight - yOrigin - 1)) * rowLength; + length = (kHeight - yOrigin - 1) * rowLength; + System.arraycopy(pixels, start, newPixels, start, length); + // middle + length = xOrigin * numBands; + int length1 = (kWidth - xOrigin - 1) * numBands; + start = yOrigin * rowLength; + int start1 = (yOrigin + 1) * rowLength - length1; + for (int i = yOrigin; i < (srcHeight - (kHeight - yOrigin - 1)); i++) { + System.arraycopy(pixels, start, newPixels, start, length); + System.arraycopy(pixels, start1, newPixels, start1, length1); + start += rowLength; + start1 += rowLength; + } + + } + + // Cycle over pixels to be calculated + for (int i = yOrigin; i < srcConvMaxY; i++) { + for (int j = xOrigin; j < srcConvMaxX; j++) { + + // Take kernel data in backward direction, convolution + int kernelIdx = data.length - 1; + + int pixelIndex = i * rowLength + j * numBands; + for (int hIdx = 0, rasterHIdx = i - yOrigin; hIdx < kHeight; hIdx++, rasterHIdx++) { + for (int wIdx = 0, rasterWIdx = j - xOrigin; wIdx < kWidth; wIdx++, rasterWIdx++) { + int curIndex = rasterHIdx * rowLength + rasterWIdx * numBands; + for (int idx = 0; idx < numBands; idx++) { + newPixels[pixelIndex + idx] += data[kernelIdx] + * pixels[curIndex + idx]; + } + kernelIdx--; + } + } + + // Check for overflow now + for (int idx = 0; idx < numBands; idx++) { + if (((int)newPixels[pixelIndex + idx] & masks[idx]) != 0) { + if (newPixels[pixelIndex + idx] < 0) { + newPixels[pixelIndex + idx] = 0; + } else { + newPixels[pixelIndex + idx] = maxValues[idx]; + } + } + } + } + } + + dst.setPixels(dstMinX, dstMinY, srcWidth, srcHeight, newPixels); + } catch (Exception e) { // Something goes wrong, signal error + return 1; + } + return 0; + } + + public final BufferedImage filter(BufferedImage src, BufferedImage dst) { + if (src == null) { + // awt.259=Source image is null + throw new NullPointerException(Messages.getString("awt.259")); //$NON-NLS-1$ + } + + if (src == dst) { + // awt.25A=Source equals to destination + throw new IllegalArgumentException(Messages.getString("awt.25A")); //$NON-NLS-1$ + } + + ColorModel srcCM = src.getColorModel(); + BufferedImage finalDst = null; + + if (srcCM instanceof IndexColorModel) { + src = ((IndexColorModel)srcCM).convertToIntDiscrete(src.getRaster(), true); + srcCM = src.getColorModel(); + } + + if (dst == null) { + dst = createCompatibleDestImage(src, srcCM); + } else { + if (!srcCM.equals(dst.getColorModel())) { + // Treat BufferedImage.TYPE_INT_RGB and + // BufferedImage.TYPE_INT_ARGB as same + if (!((src.getType() == BufferedImage.TYPE_INT_RGB || src.getType() == BufferedImage.TYPE_INT_ARGB) && (dst + .getType() == BufferedImage.TYPE_INT_RGB || dst.getType() == BufferedImage.TYPE_INT_ARGB))) { + finalDst = dst; + dst = createCompatibleDestImage(src, srcCM); + } + } + } + + // Skip alpha channel for TYPE_INT_RGB images + // TODO + // if (ippFilter(src.getRaster(), dst.getRaster(), src.getType()) != 0) + if (slowFilter(src.getRaster(), dst.getRaster()) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + } + + if (finalDst != null) { + Graphics2D g = finalDst.createGraphics(); + g.setComposite(AlphaComposite.Src); + g.drawImage(dst, 0, 0, null); + } else { + finalDst = dst; + } + + return finalDst; + } + + // TODO remove when this method is used + /** + * Ipp filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @param imageType + * the image type. + * @return the int. + */ + @SuppressWarnings("unused") + private int ippFilter(Raster src, WritableRaster dst, int imageType) { + int srcStride, dstStride; + boolean skipChannel = false; + int channels; + int offsets[] = null; + + switch (imageType) { + case BufferedImage.TYPE_INT_RGB: + case BufferedImage.TYPE_INT_BGR: { + channels = 4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; + skipChannel = true; + break; + } + + case BufferedImage.TYPE_INT_ARGB: + case BufferedImage.TYPE_INT_ARGB_PRE: + case BufferedImage.TYPE_4BYTE_ABGR: + case BufferedImage.TYPE_4BYTE_ABGR_PRE: { + channels = 4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; + break; + } + + case BufferedImage.TYPE_BYTE_GRAY: { + channels = 1; + srcStride = src.getWidth(); + dstStride = dst.getWidth(); + break; + } + + case BufferedImage.TYPE_3BYTE_BGR: { + channels = 3; + srcStride = src.getWidth() * 3; + dstStride = dst.getWidth() * 3; + break; + } + + case BufferedImage.TYPE_USHORT_GRAY: // TODO - could be done in + // native code? + case BufferedImage.TYPE_USHORT_565_RGB: + case BufferedImage.TYPE_USHORT_555_RGB: + case BufferedImage.TYPE_BYTE_BINARY: { + return slowFilter(src, dst); + } + + default: { + SampleModel srcSM = src.getSampleModel(); + SampleModel dstSM = dst.getSampleModel(); + + if (srcSM instanceof PixelInterleavedSampleModel + && dstSM instanceof PixelInterleavedSampleModel) { + // Check PixelInterleavedSampleModel + if (srcSM.getDataType() != DataBuffer.TYPE_BYTE + || dstSM.getDataType() != DataBuffer.TYPE_BYTE) { + return slowFilter(src, dst); + } + + channels = srcSM.getNumBands(); // Have IPP functions for 1, + // 3 and 4 channels + if (!(channels == 1 || channels == 3 || channels == 4)) { + return slowFilter(src, dst); + } + + srcStride = ((ComponentSampleModel)srcSM).getScanlineStride(); + dstStride = ((ComponentSampleModel)dstSM).getScanlineStride(); + } else if (srcSM instanceof SinglePixelPackedSampleModel + && dstSM instanceof SinglePixelPackedSampleModel) { + // Check SinglePixelPackedSampleModel + SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)srcSM; + SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel)dstSM; + + channels = sppsm1.getNumBands(); + + // TYPE_INT_RGB, TYPE_INT_ARGB... + if (sppsm1.getDataType() != DataBuffer.TYPE_INT + || sppsm2.getDataType() != DataBuffer.TYPE_INT + || !(channels == 3 || channels == 4)) { + return slowFilter(src, dst); + } + + // Check compatibility of sample models + if (!Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) + || !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())) { + return slowFilter(src, dst); + } + + for (int i = 0; i < channels; i++) { + if (sppsm1.getSampleSize(i) != 8) { + return slowFilter(src, dst); + } + } + + if (channels == 3) { // Cannot skip channel, don't know + // which is alpha... + channels = 4; + } + + srcStride = sppsm1.getScanlineStride() * 4; + dstStride = sppsm2.getScanlineStride() * 4; + } else { + return slowFilter(src, dst); + } + + // Fill offsets if there's a child raster + if (src.getParent() != null || dst.getParent() != null) { + if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0 + || dst.getSampleModelTranslateX() != 0 + || dst.getSampleModelTranslateY() != 0) { + offsets = new int[4]; + offsets[0] = -src.getSampleModelTranslateX() + src.getMinX(); + offsets[1] = -src.getSampleModelTranslateY() + src.getMinY(); + offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX(); + offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY(); + } + } + } + } + + Object srcData, dstData; + AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance(); + try { + srcData = dbAccess.getData(src.getDataBuffer()); + dstData = dbAccess.getData(dst.getDataBuffer()); + } catch (IllegalArgumentException e) { + return -1; // Unknown data buffer type + } + + return ippFilter32f(kernel.data, kernel.getWidth(), kernel.getHeight(), + kernel.getXOrigin(), kernel.getYOrigin(), edgeCond, srcData, src.getWidth(), src + .getHeight(), srcStride, dstData, dst.getWidth(), dst.getHeight(), + dstStride, channels, skipChannel, offsets); + } + + /** + * Ipp filter32f. + * + * @param kernel + * the kernel. + * @param kWidth + * the k width. + * @param kHeight + * the k height. + * @param anchorX + * the anchor x. + * @param anchorY + * the anchor y. + * @param borderType + * the border type. + * @param src + * the src. + * @param srcWidth + * the src width. + * @param srcHeight + * the src height. + * @param srcStride + * the src stride. + * @param dst + * the dst. + * @param dstWidth + * the dst width. + * @param dstHeight + * the dst height. + * @param dstStride + * the dst stride. + * @param channels + * the channels. + * @param skipChannel + * the skip channel. + * @param offsets + * the offsets. + * @return the int. + */ + private native int ippFilter32f(float kernel[], int kWidth, int kHeight, int anchorX, + int anchorY, int borderType, Object src, int srcWidth, int srcHeight, int srcStride, + Object dst, int dstWidth, int dstHeight, int dstStride, int channels, + boolean skipChannel, int offsets[]); +} diff --git a/awt/java/awt/image/CropImageFilter.java b/awt/java/awt/image/CropImageFilter.java new file mode 100644 index 0000000..2f4ca78 --- /dev/null +++ b/awt/java/awt/image/CropImageFilter.java @@ -0,0 +1,196 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.util.Hashtable; + +/** + * The CropImageFilter class crops a rectangular region of an source Image and + * provides a source for a new image containing the extracted region. + * + * @since Android 1.0 + */ +public class CropImageFilter extends ImageFilter { + + /** + * The HEIGHT. + */ + private final int X, Y, WIDTH, HEIGHT; + + /** + * Instantiates a new CropImageFilter object with the specified rectangular + * area. + * + * @param x + * the X coordinate of rectangular area. + * @param y + * the Y coordinate of rectangular area. + * @param w + * the width of rectangular area. + * @param h + * the height of rectangular area. + */ + public CropImageFilter(int x, int y, int w, int h) { + X = x; + Y = y; + WIDTH = w; + HEIGHT = h; + } + + @SuppressWarnings("unchecked") + @Override + public void setProperties(Hashtable<?, ?> props) { + Hashtable<Object, Object> fprops; + if (props == null) { + fprops = new Hashtable<Object, Object>(); + } else { + fprops = (Hashtable<Object, Object>)props.clone(); + } + String propName = "Crop Filters"; //$NON-NLS-1$ + String prop = "x=" + X + "; y=" + Y + "; width=" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + WIDTH + "; height=" + HEIGHT; //$NON-NLS-1$ + Object o = fprops.get(propName); + if (o != null) { + if (o instanceof String) { + prop = (String)o + "; " + prop; //$NON-NLS-1$ + } else { + prop = o.toString() + "; " + prop; //$NON-NLS-1$ + } + } + fprops.put(propName, prop); + consumer.setProperties(fprops); + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize) { + + if (x + w < X || X + WIDTH < x || y + h < Y || Y + HEIGHT < y) { + return; + } + + int destX, destY, destWidth, destHeight, endX, endY, srcEndX, srcEndY; + + int newOffset = off; + + endX = X + WIDTH; + endY = Y + HEIGHT; + + srcEndX = x + w; + srcEndY = y + h; + + if (x <= X) { + destX = 0; + newOffset += X; + if (endX >= srcEndX) { + destWidth = srcEndX - X; + } else { + destWidth = WIDTH; + } + } else { + destX = x - X; + if (endX >= srcEndX) { + destWidth = w; + } else { + destWidth = endX - x; + } + } + + if (y <= Y) { + newOffset += scansize * (Y - y); + destY = 0; + if (endY >= srcEndY) { + destHeight = srcEndY - Y; + } else { + destHeight = HEIGHT; + } + } else { + destY = y - Y; + if (endY >= srcEndY) { + destHeight = h; + } else { + destHeight = endY - y; + } + } + consumer.setPixels(destX, destY, destWidth, destHeight, model, pixels, newOffset, scansize); + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize) { + + if (x + w < X || X + WIDTH < x || y + h < Y || Y + HEIGHT < y) { + return; + } + + int destX, destY, destWidth, destHeight, endX, endY, srcEndX, srcEndY; + + int newOffset = off; + + endX = X + WIDTH; + endY = Y + HEIGHT; + + srcEndX = x + w; + srcEndY = y + h; + + if (x <= X) { + destX = 0; + newOffset += X; + if (endX >= srcEndX) { + destWidth = srcEndX - X; + } else { + destWidth = WIDTH; + } + } else { + destX = x - X; + if (endX >= srcEndX) { + destWidth = w; + } else { + destWidth = endX - x; + } + } + + if (y <= Y) { + newOffset += scansize * (Y - y); + destY = 0; + if (endY >= srcEndY) { + destHeight = srcEndY - Y; + } else { + destHeight = HEIGHT; + } + } else { + destY = y - Y; + if (endY >= srcEndY) { + destHeight = h; + } else { + destHeight = endY - y; + } + } + consumer.setPixels(destX, destY, destWidth, destHeight, model, pixels, newOffset, scansize); + } + + @Override + public void setDimensions(int w, int h) { + consumer.setDimensions(WIDTH, HEIGHT); + } + +} diff --git a/awt/java/awt/image/DataBuffer.java b/awt/java/awt/image/DataBuffer.java new file mode 100644 index 0000000..92f900f --- /dev/null +++ b/awt/java/awt/image/DataBuffer.java @@ -0,0 +1,481 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import org.apache.harmony.awt.gl.image.DataBufferListener; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class DataBuffer is a wrapper class for a data array to be used for the + * situation where a suite of functionality acts on a set of data in a + * consistent way even though the primitive type of the data may vary from one + * use to the next. + * + * @since Android 1.0 + */ +public abstract class DataBuffer { + + /** + * The Constant TYPE_BYTE. + */ + public static final int TYPE_BYTE = 0; + + /** + * The Constant TYPE_USHORT. + */ + public static final int TYPE_USHORT = 1; + + /** + * The Constant TYPE_SHORT. + */ + public static final int TYPE_SHORT = 2; + + /** + * The Constant TYPE_INT. + */ + public static final int TYPE_INT = 3; + + /** + * The Constant TYPE_FLOAT. + */ + public static final int TYPE_FLOAT = 4; + + /** + * The Constant TYPE_DOUBLE. + */ + public static final int TYPE_DOUBLE = 5; + + /** + * The Constant TYPE_UNDEFINED. + */ + public static final int TYPE_UNDEFINED = 32; + + /** + * The data type indicates the primitive type of the data in this + * DataBuffer. + */ + protected int dataType; + + /** + * The number of data arrays in this DataBuffer. + */ + protected int banks; + + /** + * The starting index for reading the data from the first (or only) internal + * data array. + */ + protected int offset; + + /** + * The length (number of elements) of the data arrays. + */ + protected int size; + + /** + * The starting indices for reading the data from the internal data arrays. + */ + protected int offsets[]; + + /** + * The data changed. + */ + boolean dataChanged = true; + + /** + * The data taken. + */ + boolean dataTaken = false; + + /** + * The listener. + */ + DataBufferListener listener; + + static { + AwtImageBackdoorAccessorImpl.init(); + } + + /** + * Instantiates a new data buffer. + * + * @param dataType + * the data type. + * @param size + * the length (number of elements) of the data arrays. + * @param numBanks + * the number of data arrays to create. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. + */ + protected DataBuffer(int dataType, int size, int numBanks, int[] offsets) { + this.dataType = dataType; + this.size = size; + this.banks = numBanks; + this.offsets = offsets.clone(); + this.offset = offsets[0]; + } + + /** + * Instantiates a new data buffer with all of the data arrays starting at + * the same index. + * + * @param dataType + * the data type. + * @param size + * the length (number of elements) of the data arrays. + * @param numBanks + * the number of data arrays to create. + * @param offset + * the offset to use for all of the data arrays. + */ + protected DataBuffer(int dataType, int size, int numBanks, int offset) { + this.dataType = dataType; + this.size = size; + this.banks = numBanks; + this.offset = offset; + this.offsets = new int[numBanks]; + int i = 0; + while (i < numBanks) { + offsets[i++] = offset; + } + } + + /** + * Instantiates a new data buffer with all of the data arrays read from the + * beginning (at offset zero). + * + * @param dataType + * the data type. + * @param size + * the length (number of elements) of the data arrays. + * @param numBanks + * the number of data arrays to create. + */ + protected DataBuffer(int dataType, int size, int numBanks) { + this.dataType = dataType; + this.size = size; + this.banks = numBanks; + this.offset = 0; + this.offsets = new int[numBanks]; + } + + /** + * Instantiates a new data buffer with one internal data array read from the + * beginning (at offset zero). + * + * @param dataType + * the data type. + * @param size + * the length (number of elements) of the data arrays. + */ + protected DataBuffer(int dataType, int size) { + this.dataType = dataType; + this.size = size; + this.banks = 1; + this.offset = 0; + this.offsets = new int[1]; + } + + /** + * Sets the data value in the specified array at the specified index. + * + * @param bank + * the internal array to the data to. + * @param i + * the index within the array where the data should be written. + * @param val + * the value to write into the array. + */ + public abstract void setElem(int bank, int i, int val); + + /** + * Sets the float data value in the specified array at the specified index. + * + * @param bank + * the internal array to the data to. + * @param i + * the index within the array where the data should be written. + * @param val + * the value to write into the array. + */ + public void setElemFloat(int bank, int i, float val) { + setElem(bank, i, (int)val); + } + + /** + * Sets the double data value in the specified array at the specified index. + * + * @param bank + * the internal array to the data to. + * @param i + * the index within the array where the data should be written. + * @param val + * the value to write into the array. + */ + public void setElemDouble(int bank, int i, double val) { + setElem(bank, i, (int)val); + } + + /** + * Sets the data value in the first array at the specified index. + * + * @param i + * the index within the array where the data should be written. + * @param val + * the value to write into the array. + */ + public void setElem(int i, int val) { + setElem(0, i, val); + } + + /** + * Gets the data value from the specified data array at the specified index. + * + * @param bank + * the data array to read from. + * @param i + * the index within the array where the data should be read. + * @return the data element. + */ + public abstract int getElem(int bank, int i); + + /** + * Gets the float-type data value from the specified data array at the + * specified index. + * + * @param bank + * the data array to read from. + * @param i + * the index within the array where the data should be read. + * @return the data element. + */ + public float getElemFloat(int bank, int i) { + return getElem(bank, i); + } + + /** + * Gets the double-type data value from the specified data array at the + * specified index. + * + * @param bank + * the data array to read from. + * @param i + * the index within the array where the data should be read. + * @return the data element. + */ + public double getElemDouble(int bank, int i) { + return getElem(bank, i); + } + + /** + * Sets the float data value in the first array at the specified index. + * + * @param i + * the index within the array where the data should be written. + * @param val + * the value to write into the array. + */ + public void setElemFloat(int i, float val) { + setElemFloat(0, i, val); + } + + /** + * Sets the double data value in the first array at the specified index. + * + * @param i + * the index within the array where the data should be written. + * @param val + * the value to write into the array. + */ + public void setElemDouble(int i, double val) { + setElemDouble(0, i, val); + } + + /** + * Gets the data value from the first data array at the specified index and + * returns it as an integer. + * + * @param i + * the index within the array where the data should be read. + * @return the data element. + */ + public int getElem(int i) { + return getElem(0, i); + } + + /** + * Gets the data value from the first data array at the specified index and + * returns it as a float. + * + * @param i + * the index within the array where the data should be read. + * @return the data element. + */ + public float getElemFloat(int i) { + return getElem(0, i); + } + + /** + * Gets the data value from the first data array at the specified index and + * returns it as a double. + * + * @param i + * the index within the array where the data should be read. + * @return the data element. + */ + public double getElemDouble(int i) { + return getElem(i); + } + + /** + * Gets the array giving the offsets corresponding to the internal data + * arrays. + * + * @return the array of offsets. + */ + public int[] getOffsets() { + return offsets; + } + + /** + * Gets the size in bits of the primitive data type. + * + * @return the size in bits of the primitive data type. + */ + public int getSize() { + return size; + } + + /** + * Gets the offset corresponding to the first internal data array. + * + * @return the offset. + */ + public int getOffset() { + return offset; + } + + /** + * Gets the number of data arrays in this DataBuffer. + * + * @return the number of data arrays. + */ + public int getNumBanks() { + return banks; + } + + /** + * Gets the primitive type of this buffer's data. + * + * @return the data type. + */ + public int getDataType() { + return this.dataType; + } + + /** + * Gets the size in bits of the primitive data type. + * + * @param type + * the primitive type. + * @return the size in bits of the primitive data type. + */ + public static int getDataTypeSize(int type) { + switch (type) { + + case TYPE_BYTE: + return 8; + + case TYPE_USHORT: + case TYPE_SHORT: + return 16; + + case TYPE_INT: + case TYPE_FLOAT: + return 32; + + case TYPE_DOUBLE: + return 64; + + default: + // awt.22C=Unknown data type {0} + throw new IllegalArgumentException(Messages.getString("awt.22C", type)); //$NON-NLS-1$ + } + } + + /** + * Notifies the listener that the data has changed. + */ + void notifyChanged() { + if (listener != null && !dataChanged) { + dataChanged = true; + listener.dataChanged(); + } + } + + /** + * Notifies the listener that the data has been released. + */ + void notifyTaken() { + if (listener != null && !dataTaken) { + dataTaken = true; + listener.dataTaken(); + } + } + + /** + * Release the data. + */ + void releaseData() { + if (listener != null && dataTaken) { + dataTaken = false; + listener.dataReleased(); + } + } + + /** + * Adds the data buffer listener. + * + * @param listener + * the listener. + */ + void addDataBufferListener(DataBufferListener listener) { + this.listener = listener; + } + + /** + * Removes the data buffer listener. + */ + void removeDataBufferListener() { + listener = null; + } + + /** + * Validate. + */ + void validate() { + dataChanged = false; + } + +} diff --git a/awt/java/awt/image/DataBufferByte.java b/awt/java/awt/image/DataBufferByte.java new file mode 100644 index 0000000..3407de8 --- /dev/null +++ b/awt/java/awt/image/DataBufferByte.java @@ -0,0 +1,183 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +/** + * The Class DataBufferByte is the subclass of DataBuffer for the case where the + * underlying data is of type byte. + * + * @since Android 1.0 + */ +public final class DataBufferByte extends DataBuffer { + + /** + * The data. + */ + byte data[][]; + + /** + * Instantiates a new data buffer of type unsigned short. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. + */ + public DataBufferByte(byte dataArrays[][], int size, int offsets[]) { + super(TYPE_BYTE, size, dataArrays.length, offsets); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type unsigned short. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + */ + public DataBufferByte(byte dataArrays[][], int size) { + super(TYPE_BYTE, size, dataArrays.length); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type unsigned short with a single + * underlying array of data. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + * @param offset + * the starting index to use when reading the data. + */ + public DataBufferByte(byte dataArray[], int size, int offset) { + super(TYPE_BYTE, size, 1, offset); + data = new byte[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type unsigned short with a single + * underlying array of data starting at index 0. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + */ + public DataBufferByte(byte dataArray[], int size) { + super(TYPE_BYTE, size); + data = new byte[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new empty data buffer of type unsigned short with offsets + * equal to zero. + * + * @param size + * the length (number of elements) to use from the data arrays. + * @param numBanks + * the number of data arrays to create. + */ + public DataBufferByte(int size, int numBanks) { + super(TYPE_BYTE, size, numBanks); + data = new byte[numBanks][]; + int i = 0; + while (i < numBanks) { + data[i++] = new byte[size]; + } + } + + /** + * Instantiates a new empty data buffer of type unsigned short with a single + * underlying array of data starting at index 0. + * + * @param size + * the length (number of elements) to use. + */ + public DataBufferByte(int size) { + super(TYPE_BYTE, size); + data = new byte[1][]; + data[0] = new byte[size]; + } + + @Override + public void setElem(int bank, int i, int val) { + data[bank][offsets[bank] + i] = (byte)val; + notifyChanged(); + } + + @Override + public void setElem(int i, int val) { + data[0][offset + i] = (byte)val; + notifyChanged(); + } + + @Override + public int getElem(int bank, int i) { + return (data[bank][offsets[bank] + i]) & 0xff; + } + + /** + * Gets the data of the specified internal data array. + * + * @param bank + * the index of the desired data array. + * @return the data. + */ + public byte[] getData(int bank) { + notifyTaken(); + return data[bank]; + } + + @Override + public int getElem(int i) { + return (data[0][offset + i]) & 0xff; + } + + /** + * Gets the bank data. + * + * @return the bank data. + */ + public byte[][] getBankData() { + notifyTaken(); + return data.clone(); + } + + /** + * Gets the data of the first data array. + * + * @return the data. + */ + public byte[] getData() { + notifyTaken(); + return data[0]; + } + +} diff --git a/awt/java/awt/image/DataBufferDouble.java b/awt/java/awt/image/DataBufferDouble.java new file mode 100644 index 0000000..5d0a516 --- /dev/null +++ b/awt/java/awt/image/DataBufferDouble.java @@ -0,0 +1,226 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +/** + * The Class DataBufferDouble is the subclass of DataBuffer for the case where + * the underlying data is of type double. + * + * @since Android 1.0 + */ +public final class DataBufferDouble extends DataBuffer { + + /** + * The data. + */ + double data[][]; + + /** + * Instantiates a new data buffer of type double. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. + */ + public DataBufferDouble(double dataArrays[][], int size, int offsets[]) { + super(TYPE_DOUBLE, size, dataArrays.length, offsets); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type double. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + */ + public DataBufferDouble(double dataArrays[][], int size) { + super(TYPE_DOUBLE, size, dataArrays.length); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type double with a single underlying + * array of data. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + * @param offset + * the starting index to use when reading the data. + */ + public DataBufferDouble(double dataArray[], int size, int offset) { + super(TYPE_DOUBLE, size, 1, offset); + data = new double[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type double with a single underlying + * array of data starting at index 0. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + */ + public DataBufferDouble(double dataArray[], int size) { + super(TYPE_DOUBLE, size); + data = new double[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new empty data buffer of type double with offsets equal to + * zero. + * + * @param size + * the length (number of elements) to use from the data arrays. + * @param numBanks + * the number of data arrays to create. + */ + public DataBufferDouble(int size, int numBanks) { + super(TYPE_DOUBLE, size, numBanks); + data = new double[numBanks][]; + int i = 0; + while (i < numBanks) { + data[i++] = new double[size]; + } + } + + /** + * Instantiates a new empty data buffer of type double with a single + * underlying array of data starting at index 0. + * + * @param size + * the length (number of elements) to use. + */ + public DataBufferDouble(int size) { + super(TYPE_DOUBLE, size); + data = new double[1][]; + data[0] = new double[size]; + } + + @Override + public void setElem(int bank, int i, int val) { + data[bank][offsets[bank] + i] = val; + notifyChanged(); + } + + @Override + public void setElemFloat(int bank, int i, float val) { + data[bank][offsets[bank] + i] = val; + notifyChanged(); + } + + @Override + public void setElemDouble(int bank, int i, double val) { + data[bank][offsets[bank] + i] = val; + notifyChanged(); + } + + @Override + public void setElem(int i, int val) { + data[0][offset + i] = val; + notifyChanged(); + } + + @Override + public int getElem(int bank, int i) { + return (int)(data[bank][offsets[bank] + i]); + } + + @Override + public float getElemFloat(int bank, int i) { + return (float)(data[bank][offsets[bank] + i]); + } + + @Override + public double getElemDouble(int bank, int i) { + return data[bank][offsets[bank] + i]; + } + + @Override + public void setElemFloat(int i, float val) { + data[0][offset + i] = val; + notifyChanged(); + } + + @Override + public void setElemDouble(int i, double val) { + data[0][offset + i] = val; + notifyChanged(); + } + + /** + * Gets the data of the specified internal data array. + * + * @param bank + * the index of the desired data array. + * @return the data. + */ + public double[] getData(int bank) { + notifyTaken(); + return data[bank]; + } + + @Override + public int getElem(int i) { + return (int)(data[0][offset + i]); + } + + @Override + public float getElemFloat(int i) { + return (float)(data[0][offset + i]); + } + + @Override + public double getElemDouble(int i) { + return data[0][offset + i]; + } + + /** + * Gets the bank data. + * + * @return the bank data. + */ + public double[][] getBankData() { + notifyTaken(); + return data.clone(); + } + + /** + * Gets the data of the first data array. + * + * @return the data. + */ + public double[] getData() { + notifyTaken(); + return data[0]; + } +} diff --git a/awt/java/awt/image/DataBufferFloat.java b/awt/java/awt/image/DataBufferFloat.java new file mode 100644 index 0000000..9a4a6bf --- /dev/null +++ b/awt/java/awt/image/DataBufferFloat.java @@ -0,0 +1,226 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +/** + * The Class DataBufferFloat is the subclass of DataBuffer for the case where + * the underlying data is float. + * + * @since Android 1.0 + */ +public final class DataBufferFloat extends DataBuffer { + + /** + * The data. + */ + float data[][]; + + /** + * Instantiates a new data buffer of type float. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. + */ + public DataBufferFloat(float dataArrays[][], int size, int offsets[]) { + super(TYPE_FLOAT, size, dataArrays.length, offsets); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type float. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + */ + public DataBufferFloat(float dataArrays[][], int size) { + super(TYPE_FLOAT, size, dataArrays.length); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type float with a single underlying + * array of data. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + * @param offset + * the starting index to use when reading the data. + */ + public DataBufferFloat(float dataArray[], int size, int offset) { + super(TYPE_FLOAT, size, 1, offset); + data = new float[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type float with a single underlying + * array of data starting at index 0. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + */ + public DataBufferFloat(float dataArray[], int size) { + super(TYPE_FLOAT, size); + data = new float[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new empty data buffer of type float with offsets equal to + * zero. + * + * @param size + * the length (number of elements) to use from the data arrays. + * @param numBanks + * the number of data arrays to create. + */ + public DataBufferFloat(int size, int numBanks) { + super(TYPE_FLOAT, size, numBanks); + data = new float[numBanks][]; + int i = 0; + while (i < numBanks) { + data[i++] = new float[size]; + } + } + + /** + * Instantiates a new empty data buffer of type float with a single + * underlying array of data starting at index 0. + * + * @param size + * the length (number of elements) to use. + */ + public DataBufferFloat(int size) { + super(TYPE_FLOAT, size); + data = new float[1][]; + data[0] = new float[size]; + } + + @Override + public void setElem(int bank, int i, int val) { + data[bank][offsets[bank] + i] = val; + notifyChanged(); + } + + @Override + public void setElemFloat(int bank, int i, float val) { + data[bank][offsets[bank] + i] = val; + notifyChanged(); + } + + @Override + public void setElemDouble(int bank, int i, double val) { + data[bank][offsets[bank] + i] = (float)val; + notifyChanged(); + } + + @Override + public void setElem(int i, int val) { + data[0][offset + i] = val; + notifyChanged(); + } + + @Override + public int getElem(int bank, int i) { + return (int)(data[bank][offsets[bank] + i]); + } + + @Override + public float getElemFloat(int bank, int i) { + return data[bank][offsets[bank] + i]; + } + + @Override + public double getElemDouble(int bank, int i) { + return data[bank][offsets[bank] + i]; + } + + @Override + public void setElemFloat(int i, float val) { + data[0][offset + i] = val; + notifyChanged(); + } + + @Override + public void setElemDouble(int i, double val) { + data[0][offset + i] = (float)val; + notifyChanged(); + } + + /** + * Gets the data of the specified internal data array. + * + * @param bank + * the index of the desired array. + * @return the data. + */ + public float[] getData(int bank) { + notifyTaken(); + return data[bank]; + } + + @Override + public int getElem(int i) { + return (int)(data[0][offset + i]); + } + + @Override + public float getElemFloat(int i) { + return data[0][offset + i]; + } + + @Override + public double getElemDouble(int i) { + return data[0][offset + i]; + } + + /** + * Gets the bank data. + * + * @return the bank data. + */ + public float[][] getBankData() { + notifyTaken(); + return data.clone(); + } + + /** + * Gets the data of the first data array. + * + * @return the data. + */ + public float[] getData() { + notifyTaken(); + return data[0]; + } +} diff --git a/awt/java/awt/image/DataBufferInt.java b/awt/java/awt/image/DataBufferInt.java new file mode 100644 index 0000000..380a127 --- /dev/null +++ b/awt/java/awt/image/DataBufferInt.java @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +/** + * The Class DataBufferInt is the subclass of DataBuffer for the case where the + * underlying data is of type integer. + * + * @since Android 1.0 + */ +public final class DataBufferInt extends DataBuffer { + + /** + * The data. + */ + int data[][]; + + /** + * Instantiates a new data buffer of type integer. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. + */ + public DataBufferInt(int dataArrays[][], int size, int offsets[]) { + super(TYPE_INT, size, dataArrays.length, offsets); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type integer. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + */ + public DataBufferInt(int dataArrays[][], int size) { + super(TYPE_INT, size, dataArrays.length); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type integer with a single underlying + * array of data. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + * @param offset + * the starting index to use when reading the data. + */ + public DataBufferInt(int dataArray[], int size, int offset) { + super(TYPE_INT, size, 1, offset); + data = new int[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type integer with a single underlying + * array of data starting at index 0. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + */ + public DataBufferInt(int dataArray[], int size) { + super(TYPE_INT, size); + data = new int[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new empty data buffer of type integer with offsets equal + * to zero. + * + * @param size + * the length (number of elements) to use from the data arrays. + * @param numBanks + * the number of data arrays to create. + */ + public DataBufferInt(int size, int numBanks) { + super(TYPE_INT, size, numBanks); + data = new int[numBanks][]; + int i = 0; + while (i < numBanks) { + data[i++] = new int[size]; + } + } + + /** + * Instantiates a new empty data buffer of type integer with a single + * underlying array of data starting at index 0. + * + * @param size + * the length (number of elements) to use. + */ + public DataBufferInt(int size) { + super(TYPE_INT, size); + data = new int[1][]; + data[0] = new int[size]; + } + + @Override + public void setElem(int bank, int i, int val) { + data[bank][offsets[bank] + i] = val; + notifyChanged(); + } + + @Override + public void setElem(int i, int val) { + data[0][offset + i] = val; + notifyChanged(); + } + + @Override + public int getElem(int bank, int i) { + return data[bank][offsets[bank] + i]; + } + + /** + * Gets the data of the specified internal data array. + * + * @param bank + * the index of the desired data array. + * @return the data. + */ + public int[] getData(int bank) { + notifyTaken(); + return data[bank]; + } + + @Override + public int getElem(int i) { + return data[0][offset + i]; + } + + /** + * Gets the bank data. + * + * @return the bank data. + */ + public int[][] getBankData() { + notifyTaken(); + return data.clone(); + } + + /** + * Gets the data of the first data array. + * + * @return the data. + */ + public int[] getData() { + notifyTaken(); + return data[0]; + } +} diff --git a/awt/java/awt/image/DataBufferShort.java b/awt/java/awt/image/DataBufferShort.java new file mode 100644 index 0000000..1b11b29 --- /dev/null +++ b/awt/java/awt/image/DataBufferShort.java @@ -0,0 +1,181 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +/** + * The Class DataBufferShort is the subclass of DataBuffer for the case where + * the underlying data is short. + * + * @since Android 1.0 + */ +public final class DataBufferShort extends DataBuffer { + + /** + * The data. + */ + short data[][]; + + /** + * Instantiates a new data buffer of type short. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. + */ + public DataBufferShort(short dataArrays[][], int size, int offsets[]) { + super(TYPE_SHORT, size, dataArrays.length, offsets); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type short. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + */ + public DataBufferShort(short dataArrays[][], int size) { + super(TYPE_SHORT, size, dataArrays.length); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type short with a single underlying + * array of data. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + * @param offset + * the starting index to use when reading the data. + */ + public DataBufferShort(short dataArray[], int size, int offset) { + super(TYPE_SHORT, size, 1, offset); + data = new short[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type short with a single underlying + * array of data starting at index 0. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + */ + public DataBufferShort(short dataArray[], int size) { + super(TYPE_SHORT, size); + data = new short[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type short with offsets equal to zero. + * + * @param size + * the length (number of elements) to use from the data arrays. + * @param numBanks + * the number of data arrays to create. + */ + public DataBufferShort(int size, int numBanks) { + super(TYPE_SHORT, size, numBanks); + data = new short[numBanks][]; + int i = 0; + while (i < numBanks) { + data[i++] = new short[size]; + } + } + + /** + * Instantiates a new empty data buffer of type short with a single + * underlying array of data starting at index 0. + * + * @param size + * the length (number of elements) to use. + */ + public DataBufferShort(int size) { + super(TYPE_SHORT, size); + data = new short[1][]; + data[0] = new short[size]; + } + + @Override + public void setElem(int bank, int i, int val) { + data[bank][offsets[bank] + i] = (short)val; + notifyChanged(); + } + + @Override + public void setElem(int i, int val) { + data[0][offset + i] = (short)val; + notifyChanged(); + } + + @Override + public int getElem(int bank, int i) { + return (data[bank][offsets[bank] + i]); + } + + /** + * Gets the data of the specified internal data array. + * + * @param bank + * the index of the desired data array. + * @return the data. + */ + public short[] getData(int bank) { + notifyTaken(); + return data[bank]; + } + + @Override + public int getElem(int i) { + return (data[0][offset + i]); + } + + /** + * Gets the bank data. + * + * @return the bank data. + */ + public short[][] getBankData() { + notifyTaken(); + return data.clone(); + } + + /** + * Gets the data of the first data array. + * + * @return the data. + */ + public short[] getData() { + notifyTaken(); + return data[0]; + } +} diff --git a/awt/java/awt/image/DataBufferUShort.java b/awt/java/awt/image/DataBufferUShort.java new file mode 100644 index 0000000..58d9d83 --- /dev/null +++ b/awt/java/awt/image/DataBufferUShort.java @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class DataBufferUShort is the subclass of DataBuffer for the case where + * the underlying data is unsigned short. + * + * @since Android 1.0 + */ +public final class DataBufferUShort extends DataBuffer { + + /** + * The data. + */ + short data[][]; + + /** + * Instantiates a new data buffer of type unsigned short. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. + */ + public DataBufferUShort(short dataArrays[][], int size, int offsets[]) { + super(TYPE_USHORT, size, dataArrays.length, offsets); + for (int i = 0; i < dataArrays.length; i++) { + if (dataArrays[i].length < offsets[i] + size) { + // awt.28d=Length of dataArray[{0}] is less than size + + // offset[{1}] + throw new IllegalArgumentException(Messages.getString("awt.28D", i, i)); //$NON-NLS-1$ + } + } + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type unsigned short. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + */ + public DataBufferUShort(short dataArrays[][], int size) { + super(TYPE_USHORT, size, dataArrays.length); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type unsigned short with a single + * underlying array of data. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + * @param offset + * the starting index to use when reading the data. + */ + public DataBufferUShort(short dataArray[], int size, int offset) { + super(TYPE_USHORT, size, 1, offset); + if (dataArray.length < size + offset) { + // awt.28E=Length of dataArray is less than size + offset + throw new IllegalArgumentException(Messages.getString("awt.28E")); //$NON-NLS-1$ + } + data = new short[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type unsigned short with a single + * underlying array of data starting at index 0. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + */ + public DataBufferUShort(short dataArray[], int size) { + super(TYPE_USHORT, size); + data = new short[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new empty data buffer of type unsigned short with offsets + * equal to zero. + * + * @param size + * the length (number of elements) to use from the data arrays. + * @param numBanks + * the number of data arrays to create. + */ + public DataBufferUShort(int size, int numBanks) { + super(TYPE_USHORT, size, numBanks); + data = new short[numBanks][]; + int i = 0; + while (i < numBanks) { + data[i++] = new short[size]; + } + } + + /** + * Instantiates a new empty data buffer of type unsigned short with a single + * underlying array of data starting at index 0. + * + * @param size + * the length (number of elements) to use. + */ + public DataBufferUShort(int size) { + super(TYPE_USHORT, size); + data = new short[1][]; + data[0] = new short[size]; + } + + @Override + public void setElem(int bank, int i, int val) { + data[bank][offsets[bank] + i] = (short)val; + notifyChanged(); + } + + @Override + public void setElem(int i, int val) { + data[0][offset + i] = (short)val; + notifyChanged(); + } + + @Override + public int getElem(int bank, int i) { + return (data[bank][offsets[bank] + i]) & 0xffff; + } + + /** + * Gets the data of the specified internal data array. + * + * @param bank + * the index of the desired data array. + * @return the data. + */ + public short[] getData(int bank) { + notifyTaken(); + return data[bank]; + } + + @Override + public int getElem(int i) { + return (data[0][offset + i]) & 0xffff; + } + + /** + * Gets the bank data. + * + * @return the bank data. + */ + public short[][] getBankData() { + notifyTaken(); + return data.clone(); + } + + /** + * Gets the data of the first data array. + * + * @return the data. + */ + public short[] getData() { + notifyTaken(); + return data[0]; + } +} diff --git a/awt/java/awt/image/DirectColorModel.java b/awt/java/awt/image/DirectColorModel.java new file mode 100644 index 0000000..700eb7a --- /dev/null +++ b/awt/java/awt/image/DirectColorModel.java @@ -0,0 +1,889 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.color.ColorSpace; +import java.awt.Transparency; +import java.util.Arrays; + +import org.apache.harmony.awt.gl.color.LUTColorConverter; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class DirectColorModel represents a standard (packed) RGB color model + * with additional support for converting between sRGB color space and 8 or 16 + * bit linear RGB color space using lookup tables. + * + * @since Android 1.0 + */ +public class DirectColorModel extends PackedColorModel { + + /** + * The from_ linea r_ rg b_ lut. + */ + private byte from_LINEAR_RGB_LUT[]; // Lookup table for conversion from + + // Linear RGB Color Space into sRGB + + /** + * The to_ linea r_8 rg b_ lut. + */ + private byte to_LINEAR_8RGB_LUT[]; // Lookup table for conversion from + + // sRGB Color Space into Linear RGB + // 8 bit + + /** + * The to_ linea r_16 rg b_ lut. + */ + private short to_LINEAR_16RGB_LUT[]; // Lookup table for conversion from + + // sRGB Color Space into Linear RGB + // 16 bit + + /** + * The alpha lut. + */ + private byte alphaLUT[]; // Lookup table for scale alpha value + + /** + * The color lu ts. + */ + private byte colorLUTs[][]; // Lookup tables for scale color values + + /** + * The is_s rgb. + */ + private boolean is_sRGB; // ColorModel has sRGB ColorSpace + + /** + * The is_ linea r_ rgb. + */ + private boolean is_LINEAR_RGB; // Color Model has Linear RGB Color + + // Space + + /** + * The LINEA r_ rg b_ length. + */ + private int LINEAR_RGB_Length; // Linear RGB bit length + + /** + * The factor. + */ + private float fFactor; // Scale factor + + /** + * Instantiates a new direct color model. + * + * @param space + * the color space. + * @param bits + * the array of component masks. + * @param rmask + * the bitmask corresponding to the red band. + * @param gmask + * the bitmask corresponding to the green band. + * @param bmask + * the bitmask corresponding to the blue band. + * @param amask + * the bitmask corresponding to the alpha band. + * @param isAlphaPremultiplied + * whether the alpha is pre-multiplied in this color model. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + * @throws IllegalArgumentException + * if the number of bits in the combined bitmasks for the color + * bands is less than one or greater than 32. + */ + public DirectColorModel(ColorSpace space, int bits, int rmask, int gmask, int bmask, int amask, + boolean isAlphaPremultiplied, int transferType) { + + super(space, bits, rmask, gmask, bmask, amask, isAlphaPremultiplied, + (amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT), transferType); + + initLUTs(); + } + + /** + * Instantiates a new direct color model, determining the transfer type from + * the bits array, the transparency from the alpha mask, and the default + * color space {@link ColorSpace#CS_sRGB}. + * + * @param bits + * the array of component masks. + * @param rmask + * the bitmask corresponding to the red band. + * @param gmask + * the bitmask corresponding to the green band. + * @param bmask + * the bitmask corresponding to the blue band. + * @param amask + * the bitmask corresponding to the alpha band. + */ + public DirectColorModel(int bits, int rmask, int gmask, int bmask, int amask) { + + super(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits, rmask, gmask, bmask, amask, false, + (amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT), ColorModel + .getTransferType(bits)); + + initLUTs(); + } + + /** + * Instantiates a new direct color model with no alpha channel, determining + * the transfer type from the bits array, the default color space + * {@link ColorSpace#CS_sRGB}, and with the transparency set to + * {@link Transparency#OPAQUE}. + * + * @param bits + * the array of component masks. + * @param rmask + * the bitmask corresponding to the red band. + * @param gmask + * the bitmask corresponding to the green band. + * @param bmask + * the bitmask corresponding to the blue band. + */ + public DirectColorModel(int bits, int rmask, int gmask, int bmask) { + this(bits, rmask, gmask, bmask, 0); + } + + @Override + public Object getDataElements(int components[], int offset, Object obj) { + int pixel = 0; + for (int i = 0; i < numComponents; i++) { + pixel |= (components[offset + i] << offsets[i]) & componentMasks[i]; + } + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[]; + if (obj == null) { + ba = new byte[1]; + } else { + ba = (byte[])obj; + } + ba[0] = (byte)pixel; + obj = ba; + break; + + case DataBuffer.TYPE_USHORT: + short sa[]; + if (obj == null) { + sa = new short[1]; + } else { + sa = (short[])obj; + } + sa[0] = (short)pixel; + obj = sa; + break; + + case DataBuffer.TYPE_INT: + int ia[]; + if (obj == null) { + ia = new int[1]; + } else { + ia = (int[])obj; + } + ia[0] = pixel; + obj = ia; + break; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + + return obj; + } + + @Override + public Object getDataElements(int rgb, Object pixel) { + if (equals(ColorModel.getRGBdefault())) { + int ia[]; + if (pixel == null) { + ia = new int[1]; + } else { + ia = (int[])pixel; + } + ia[0] = rgb; + return ia; + } + + int alpha = (rgb >> 24) & 0xff; + int red = (rgb >> 16) & 0xff; + int green = (rgb >> 8) & 0xff; + int blue = rgb & 0xff; + + float comp[] = new float[numColorComponents]; + float normComp[] = null; + + if (is_sRGB || is_LINEAR_RGB) { + if (is_LINEAR_RGB) { + if (LINEAR_RGB_Length == 8) { + red = to_LINEAR_8RGB_LUT[red] & 0xff; + green = to_LINEAR_8RGB_LUT[green] & 0xff; + blue = to_LINEAR_8RGB_LUT[blue] & 0xff; + } else { + red = to_LINEAR_16RGB_LUT[red] & 0xffff; + green = to_LINEAR_16RGB_LUT[green] & 0xffff; + blue = to_LINEAR_16RGB_LUT[blue] & 0xffff; + } + } + comp[0] = red / fFactor; + comp[1] = green / fFactor; + comp[2] = blue / fFactor; + if (!hasAlpha) { + normComp = comp; + } else { + float normAlpha = alpha / 255.0f; + normComp = new float[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + normComp[i] = comp[i]; + } + normComp[numColorComponents] = normAlpha; + } + } else { + comp[0] = red / fFactor; + comp[1] = green / fFactor; + comp[2] = blue / fFactor; + float rgbComp[] = cs.fromRGB(comp); + if (!hasAlpha) { + normComp = rgbComp; + } else { + float normAlpha = alpha / 255.0f; + normComp = new float[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + normComp[i] = rgbComp[i]; + } + normComp[numColorComponents] = normAlpha; + } + } + + int pxl = 0; + if (hasAlpha) { + float normAlpha = normComp[numColorComponents]; + alpha = (int)(normAlpha * maxValues[numColorComponents] + 0.5f); + if (isAlphaPremultiplied) { + red = (int)(normComp[0] * normAlpha * maxValues[0] + 0.5f); + green = (int)(normComp[1] * normAlpha * maxValues[1] + 0.5f); + blue = (int)(normComp[2] * normAlpha * maxValues[2] + 0.5f); + } else { + red = (int)(normComp[0] * maxValues[0] + 0.5f); + green = (int)(normComp[1] * maxValues[1] + 0.5f); + blue = (int)(normComp[2] * maxValues[2] + 0.5f); + } + pxl = (alpha << offsets[3]) & componentMasks[3]; + } else { + red = (int)(normComp[0] * maxValues[0] + 0.5f); + green = (int)(normComp[1] * maxValues[1] + 0.5f); + blue = (int)(normComp[2] * maxValues[2] + 0.5f); + } + + pxl |= ((red << offsets[0]) & componentMasks[0]) + | ((green << offsets[1]) & componentMasks[1]) + | ((blue << offsets[2]) & componentMasks[2]); + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[]; + if (pixel == null) { + ba = new byte[1]; + } else { + ba = (byte[])pixel; + } + ba[0] = (byte)pxl; + return ba; + + case DataBuffer.TYPE_USHORT: + short sa[]; + if (pixel == null) { + sa = new short[1]; + } else { + sa = (short[])pixel; + } + sa[0] = (short)pxl; + return sa; + + case DataBuffer.TYPE_INT: + int ia[]; + if (pixel == null) { + ia = new int[1]; + } else { + ia = (int[])pixel; + } + ia[0] = pxl; + return ia; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + } + + @Override + public final ColorModel coerceData(WritableRaster raster, boolean isAlphaPremultiplied) { + + if (!hasAlpha || this.isAlphaPremultiplied == isAlphaPremultiplied) { + return this; + } + + int minX = raster.getMinX(); + int minY = raster.getMinY(); + int w = raster.getWidth(); + int h = raster.getHeight(); + + int components[] = null; + int transparentComponents[] = new int[numComponents]; + + float alphaFactor = maxValues[numColorComponents]; + + if (isAlphaPremultiplied) { + switch (transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + components = raster.getPixel(x, minY, components); + if (components[numColorComponents] == 0) { + raster.setPixel(x, minY, transparentComponents); + } else { + float alpha = components[numColorComponents] / alphaFactor; + for (int n = 0; n < numColorComponents; n++) { + components[n] = (int)(alpha * components[n] + 0.5f); + } + raster.setPixel(x, minY, components); + } + } + + } + break; + + default: + // awt.214=This Color Model doesn't support this + // transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + } else { + switch (transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + components = raster.getPixel(x, minY, components); + if (components[numColorComponents] != 0) { + float alpha = alphaFactor / components[numColorComponents]; + for (int n = 0; n < numColorComponents; n++) { + components[n] = (int)(alpha * components[n] + 0.5f); + } + raster.setPixel(x, minY, components); + } + } + + } + break; + + default: + // awt.214=This Color Model doesn't support this + // transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + + } + + return new DirectColorModel(cs, pixel_bits, componentMasks[0], componentMasks[1], + componentMasks[2], componentMasks[3], isAlphaPremultiplied, transferType); + } + + @Override + public String toString() { + // The output format based on 1.5 release behaviour. + // It could be reveled such way: + // BufferedImage bi = new BufferedImage(1, 1, + // BufferedImage.TYPE_INT_ARGB); + // ColorModel cm = bi.getColorModel(); + // System.out.println(cm.toString()); + String str = "DirectColorModel:" + " rmask = " + //$NON-NLS-1$ //$NON-NLS-2$ + Integer.toHexString(componentMasks[0]) + " gmask = " + //$NON-NLS-1$ + Integer.toHexString(componentMasks[1]) + " bmask = " + //$NON-NLS-1$ + Integer.toHexString(componentMasks[2]) + " amask = " + //$NON-NLS-1$ + (!hasAlpha ? "0" : Integer.toHexString(componentMasks[3])); //$NON-NLS-1$ + + return str; + } + + @Override + public final int[] getComponents(Object pixel, int components[], int offset) { + + if (components == null) { + components = new int[numComponents + offset]; + } + + int intPixel = 0; + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])pixel; + intPixel = ba[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])pixel; + intPixel = sa[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[])pixel; + intPixel = ia[0]; + break; + + default: + // awt.22D=This transferType ( {0} ) is not supported by this + // color model + throw new UnsupportedOperationException(Messages.getString("awt.22D", //$NON-NLS-1$ + transferType)); + } + + return getComponents(intPixel, components, offset); + } + + @Override + public int getRed(Object inData) { + int pixel = 0; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])inData; + pixel = ba[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])inData; + pixel = sa[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[])inData; + pixel = ia[0]; + break; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + return getRed(pixel); + } + + @Override + public int getRGB(Object inData) { + int pixel = 0; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])inData; + pixel = ba[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])inData; + pixel = sa[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[])inData; + pixel = ia[0]; + break; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + return getRGB(pixel); + } + + @Override + public int getGreen(Object inData) { + int pixel = 0; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])inData; + pixel = ba[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])inData; + pixel = sa[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[])inData; + pixel = ia[0]; + break; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + return getGreen(pixel); + } + + @Override + public int getBlue(Object inData) { + int pixel = 0; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])inData; + pixel = ba[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])inData; + pixel = sa[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[])inData; + pixel = ia[0]; + break; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + return getBlue(pixel); + } + + @Override + public int getAlpha(Object inData) { + int pixel = 0; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])inData; + pixel = ba[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])inData; + pixel = sa[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[])inData; + pixel = ia[0]; + break; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + return getAlpha(pixel); + } + + @Override + public final WritableRaster createCompatibleWritableRaster(int w, int h) { + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new IllegalArgumentException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + int bandMasks[] = componentMasks.clone(); + + if (pixel_bits > 16) { + return Raster.createPackedRaster(DataBuffer.TYPE_INT, w, h, bandMasks, null); + } else if (pixel_bits > 8) { + return Raster.createPackedRaster(DataBuffer.TYPE_USHORT, w, h, bandMasks, null); + } else { + return Raster.createPackedRaster(DataBuffer.TYPE_BYTE, w, h, bandMasks, null); + } + } + + @Override + public boolean isCompatibleRaster(Raster raster) { + SampleModel sm = raster.getSampleModel(); + if (!(sm instanceof SinglePixelPackedSampleModel)) { + return false; + } + + SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel)sm; + + if (sppsm.getNumBands() != numComponents) { + return false; + } + if (raster.getTransferType() != transferType) { + return false; + } + + int maskBands[] = sppsm.getBitMasks(); + return Arrays.equals(maskBands, componentMasks); + } + + @Override + public int getDataElement(int components[], int offset) { + int pixel = 0; + for (int i = 0; i < numComponents; i++) { + pixel |= (components[offset + i] << offsets[i]) & componentMasks[i]; + } + return pixel; + } + + @Override + public final int[] getComponents(int pixel, int components[], int offset) { + if (components == null) { + components = new int[numComponents + offset]; + } + for (int i = 0; i < numComponents; i++) { + components[offset + i] = (pixel & componentMasks[i]) >> offsets[i]; + } + return components; + } + + @Override + public final int getRed(int pixel) { + if (is_sRGB) { + return getComponentFrom_sRGB(pixel, 0); + } + if (is_LINEAR_RGB) { + return getComponentFrom_LINEAR_RGB(pixel, 0); + } + return getComponentFrom_RGB(pixel, 0); + } + + @Override + public final int getRGB(int pixel) { + return (getAlpha(pixel) << 24) | (getRed(pixel) << 16) | (getGreen(pixel) << 8) + | getBlue(pixel); + } + + @Override + public final int getGreen(int pixel) { + if (is_sRGB) { + return getComponentFrom_sRGB(pixel, 1); + } + if (is_LINEAR_RGB) { + return getComponentFrom_LINEAR_RGB(pixel, 1); + } + return getComponentFrom_RGB(pixel, 1); + } + + @Override + public final int getBlue(int pixel) { + if (is_sRGB) { + return getComponentFrom_sRGB(pixel, 2); + } + if (is_LINEAR_RGB) { + return getComponentFrom_LINEAR_RGB(pixel, 2); + } + return getComponentFrom_RGB(pixel, 2); + } + + @Override + public final int getAlpha(int pixel) { + if (!hasAlpha) { + return 255; + } + int a = (pixel & componentMasks[3]) >>> offsets[3]; + if (bits[3] == 8) { + return a; + } + return alphaLUT[a] & 0xff; + } + + /** + * Gets the red mask. + * + * @return the red mask. + */ + public final int getRedMask() { + return componentMasks[0]; + } + + /** + * Gets the green mask. + * + * @return the green mask. + */ + public final int getGreenMask() { + return componentMasks[1]; + } + + /** + * Gets the blue mask. + * + * @return the blue mask. + */ + public final int getBlueMask() { + return componentMasks[2]; + } + + /** + * Gets the alpha mask. + * + * @return the alpha mask. + */ + public final int getAlphaMask() { + if (hasAlpha) { + return componentMasks[3]; + } + return 0; + } + + /** + * Initialization of Lookup tables. + */ + private void initLUTs() { + is_sRGB = cs.isCS_sRGB(); + is_LINEAR_RGB = (cs == LUTColorConverter.LINEAR_RGB_CS); + + if (is_LINEAR_RGB) { + if (maxBitLength > 8) { + LINEAR_RGB_Length = 16; + from_LINEAR_RGB_LUT = LUTColorConverter.getFrom16lRGBtosRGB_LUT(); + to_LINEAR_16RGB_LUT = LUTColorConverter.getFromsRGBto16lRGB_LUT(); + } else { + LINEAR_RGB_Length = 8; + from_LINEAR_RGB_LUT = LUTColorConverter.getFrom8lRGBtosRGB_LUT(); + to_LINEAR_8RGB_LUT = LUTColorConverter.getFromsRGBto8lRGB_LUT(); + } + fFactor = ((1 << LINEAR_RGB_Length) - 1); + } else { + fFactor = 255.0f; + } + + if (hasAlpha && bits[3] != 8) { + alphaLUT = new byte[maxValues[3] + 1]; + for (int i = 0; i <= maxValues[3]; i++) { + alphaLUT[i] = (byte)(scales[3] * i + 0.5f); + } + + } + + if (!isAlphaPremultiplied) { + colorLUTs = new byte[3][]; + + if (is_sRGB) { + for (int i = 0; i < numColorComponents; i++) { + if (bits[i] != 8) { + for (int j = 0; j < i; j++) { + if (bits[i] == bits[j]) { + colorLUTs[i] = colorLUTs[j]; + break; + } + } + colorLUTs[i] = new byte[maxValues[i] + 1]; + for (int j = 0; j <= maxValues[i]; j++) { + colorLUTs[i][j] = (byte)(scales[i] * j + 0.5f); + } + } + } + } + + if (is_LINEAR_RGB) { + for (int i = 0; i < numColorComponents; i++) { + if (bits[i] != LINEAR_RGB_Length) { + for (int j = 0; j < i; j++) { + if (bits[i] == bits[j]) { + colorLUTs[i] = colorLUTs[j]; + break; + } + } + colorLUTs[i] = new byte[maxValues[i] + 1]; + for (int j = 0; j <= maxValues[0]; j++) { + int idx; + if (LINEAR_RGB_Length == 8) { + idx = (int)(scales[i] * j + 0.5f); + } else { + idx = (int)(scales[i] * j * 257.0f + 0.5f); + } + colorLUTs[i][j] = from_LINEAR_RGB_LUT[idx]; + } + } + } + } + + } + } + + /** + * This method return RGB component value if Color Model has sRGB + * ColorSpace. + * + * @param pixel + * the integer representation of the pixel. + * @param idx + * the index of the pixel component. + * @return the value of the pixel component scaled from 0 to 255. + */ + private int getComponentFrom_sRGB(int pixel, int idx) { + int comp = (pixel & componentMasks[idx]) >> offsets[idx]; + if (isAlphaPremultiplied) { + int alpha = (pixel & componentMasks[3]) >>> offsets[3]; + comp = alpha == 0 ? 0 : (int)(scales[idx] * comp * 255.0f / (scales[3] * alpha) + 0.5f); + } else if (bits[idx] != 8) { + comp = colorLUTs[idx][comp] & 0xff; + } + return comp; + } + + /** + * This method return RGB component value if Color Model has Linear RGB + * ColorSpace. + * + * @param pixel + * the integer representation of the pixel. + * @param idx + * the index of the pixel component. + * @return the value of the pixel component scaled from 0 to 255. + */ + private int getComponentFrom_LINEAR_RGB(int pixel, int idx) { + int comp = (pixel & componentMasks[idx]) >> offsets[idx]; + if (isAlphaPremultiplied) { + float factor = ((1 << LINEAR_RGB_Length) - 1); + int alpha = (pixel & componentMasks[3]) >> offsets[3]; + comp = alpha == 0 ? 0 : (int)(scales[idx] * comp * factor / (scales[3] * alpha) + 0.5f); + } else if (bits[idx] != LINEAR_RGB_Length) { + comp = colorLUTs[idx][comp] & 0xff; + } else { + comp = from_LINEAR_RGB_LUT[comp] & 0xff; + } + return comp; + } + + /** + * This method return RGB component value if Color Model has arbitrary RGB + * ColorSapce. + * + * @param pixel + * the integer representation of the pixel. + * @param idx + * the index of the pixel component. + * @return the value of the pixel component scaled from 0 to 255. + */ + private int getComponentFrom_RGB(int pixel, int idx) { + int components[] = getComponents(pixel, null, 0); + float[] normComponents = getNormalizedComponents(components, 0, null, 0); + float[] sRGBcomponents = cs.toRGB(normComponents); + return (int)(sRGBcomponents[idx] * 255.0f + 0.5f); + } + +} diff --git a/awt/java/awt/image/FilteredImageSource.java b/awt/java/awt/image/FilteredImageSource.java new file mode 100644 index 0000000..ed8558d --- /dev/null +++ b/awt/java/awt/image/FilteredImageSource.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.util.Hashtable; + +/** + * The FilteredImageSource class is used for producing image data for a new + * filtered version of the original image using the specified filter object. + * + * @since Android 1.0 + */ +public class FilteredImageSource implements ImageProducer { + + /** + * The source. + */ + private final ImageProducer source; + + /** + * The filter. + */ + private final ImageFilter filter; + + /** + * The cons table. + */ + private final Hashtable<ImageConsumer, ImageConsumer> consTable = new Hashtable<ImageConsumer, ImageConsumer>(); + + /** + * Instantiates a new FilteredImageSource object with the specified + * ImageProducer and the ImageFilter objects. + * + * @param orig + * the specified ImageProducer. + * @param imgf + * the specified ImageFilter. + */ + public FilteredImageSource(ImageProducer orig, ImageFilter imgf) { + source = orig; + filter = imgf; + } + + public synchronized boolean isConsumer(ImageConsumer ic) { + if (ic != null) { + return consTable.containsKey(ic); + } + return false; + } + + public void startProduction(ImageConsumer ic) { + addConsumer(ic); + ImageConsumer fic = consTable.get(ic); + source.startProduction(fic); + } + + public void requestTopDownLeftRightResend(ImageConsumer ic) { + if (ic != null && isConsumer(ic)) { + ImageFilter fic = (ImageFilter)consTable.get(ic); + fic.resendTopDownLeftRight(source); + } + } + + public synchronized void removeConsumer(ImageConsumer ic) { + if (ic != null && isConsumer(ic)) { + ImageConsumer fic = consTable.get(ic); + source.removeConsumer(fic); + consTable.remove(ic); + } + } + + public synchronized void addConsumer(ImageConsumer ic) { + if (ic != null && !isConsumer(ic)) { + ImageConsumer fic = filter.getFilterInstance(ic); + source.addConsumer(fic); + consTable.put(ic, fic); + } + } +} diff --git a/awt/java/awt/image/ImageConsumer.java b/awt/java/awt/image/ImageConsumer.java new file mode 100644 index 0000000..caf87d1 --- /dev/null +++ b/awt/java/awt/image/ImageConsumer.java @@ -0,0 +1,185 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.util.Hashtable; + +/** + * The ImageConsumer interface provides the data about the image and about how + * its data is delivered. A ImageProducer provides all of the information about + * the image using the methods defined in this interface. + * + * @since Android 1.0 + */ +public interface ImageConsumer { + + /** + * The Constant RANDOMPIXELORDER indicates that the pixels are delivered in + * a random order. + */ + public static final int RANDOMPIXELORDER = 1; + + /** + * The Constant TOPDOWNLEFTRIGHT indicates that the pixels are delivered in + * top-down, left-to-right order. + */ + public static final int TOPDOWNLEFTRIGHT = 2; + + /** + * The Constant COMPLETESCANLINES indicates that the pixels are delivered in + * complete scanline. + */ + public static final int COMPLETESCANLINES = 4; + + /** + * The Constant SINGLEPASS indicates that pixels are delivered in a single + * pass. + */ + public static final int SINGLEPASS = 8; + + /** + * The Constant SINGLEFRAME indicates that image consists of single frame. + */ + public static final int SINGLEFRAME = 16; + + /** + * The Constant IMAGEERROR indicates an image error during image producing. + */ + public static final int IMAGEERROR = 1; + + /** + * The Constant SINGLEFRAMEDONE indicates that only one of the image's + * frames is completed. + */ + public static final int SINGLEFRAMEDONE = 2; + + /** + * The Constant STATICIMAGEDONE indicates that the image is completed. + */ + public static final int STATICIMAGEDONE = 3; + + /** + * The Constant IMAGEABORTED indicates that the image producing process is + * aborted. + */ + public static final int IMAGEABORTED = 4; + + /** + * Sets the properties for the image associated with this ImageConsumer. + * + * @param props + * the properties for the image associated with this + * ImageConsumer. + */ + public void setProperties(Hashtable<?, ?> props); + + /** + * Sets the ColorModel object. + * + * @param model + * the new ColorModel. + */ + public void setColorModel(ColorModel model); + + /** + * Sets the pixels for the specified rectangular area of the image. + * + * @param x + * the X coordinate of rectangular area. + * @param y + * the Y coordinate of rectangular area. + * @param w + * the width of rectangular area. + * @param h + * the height of rectangular area. + * @param model + * the specified ColorModel to be used for pixels converting. + * @param pixels + * the array of pixels. + * @param off + * the offset of pixels array. + * @param scansize + * the distance from the one row of pixels to the next row in the + * specified array. + */ + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize); + + /** + * Sets the pixels for the specified rectangular area of the image. + * + * @param x + * the X coordinate of rectangular area. + * @param y + * the Y coordinate of rectangular area. + * @param w + * the width of rectangular area. + * @param h + * the height of rectangular area. + * @param model + * the specified ColorModel to be used for pixels converting. + * @param pixels + * the array of pixels. + * @param off + * the offset of pixels array. + * @param scansize + * the distance from the one row of pixels to the next row in the + * specified array. + */ + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize); + + /** + * Sets the dimensions of a source image. + * + * @param width + * the width of the image. + * @param height + * the height of the image. + */ + public void setDimensions(int width, int height); + + /** + * Sets the hint flags of pixels order, which is used by the ImageConsumer + * for obtaining pixels from the ImageProducer for which this ImageConsumer + * is added. + * + * @param hintflags + * the mask of hint flags. + */ + public void setHints(int hintflags); + + /** + * THis method is called in the one of the following cases: + * <ul> + * <li>The ImageProducer (for which this ImageConsumer is added) has been + * delivered all pixels of the source image.</li> + * <li>A one frame of an animation has been completed.</li> + * <li>An error while loading or producing of the image has occurred. + * </ul> + * + * @param status + * the status of image producing. + */ + public void imageComplete(int status); + +} diff --git a/awt/java/awt/image/ImageFilter.java b/awt/java/awt/image/ImageFilter.java new file mode 100644 index 0000000..d2c9f50 --- /dev/null +++ b/awt/java/awt/image/ImageFilter.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.util.Hashtable; + +/** + * The ImageFilter class provides a filter for delivering image data from an + * ImageProducer to an ImageConsumer. + * + * @since Android 1.0 + */ +public class ImageFilter implements ImageConsumer, Cloneable { + + /** + * The consumer. + */ + protected ImageConsumer consumer; + + /** + * Instantiates a new ImageFilter. + */ + public ImageFilter() { + super(); + } + + /** + * Gets an instance of an ImageFilter object which performs the filtering + * for the specified ImageConsumer. + * + * @param ic + * the specified ImageConsumer. + * @return an ImageFilter used to perform the filtering for the specified + * ImageConsumer. + */ + public ImageFilter getFilterInstance(ImageConsumer ic) { + ImageFilter filter = (ImageFilter)clone(); + filter.consumer = ic; + return filter; + } + + @SuppressWarnings("unchecked") + public void setProperties(Hashtable<?, ?> props) { + Hashtable<Object, Object> fprops; + if (props == null) { + fprops = new Hashtable<Object, Object>(); + } else { + fprops = (Hashtable<Object, Object>)props.clone(); + } + String propName = "Filters"; //$NON-NLS-1$ + String prop = "Null filter"; //$NON-NLS-1$ + Object o = fprops.get(propName); + if (o != null) { + if (o instanceof String) { + prop = (String)o + "; " + prop; //$NON-NLS-1$ + } else { + prop = o.toString() + "; " + prop; //$NON-NLS-1$ + } + } + fprops.put(propName, prop); + consumer.setProperties(fprops); + } + + /** + * Returns a copy of this ImageFilter. + * + * @return a copy of this ImageFilter. + */ + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + return null; + } + } + + /** + * Responds to a request for a Top-Down-Left-Right ordered resend of the + * pixel data from an ImageConsumer. + * + * @param ip + * the ImageProducer that provides this instance of the filter. + */ + public void resendTopDownLeftRight(ImageProducer ip) { + ip.requestTopDownLeftRightResend(this); + } + + public void setColorModel(ColorModel model) { + consumer.setColorModel(model); + } + + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize) { + consumer.setPixels(x, y, w, h, model, pixels, off, scansize); + } + + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize) { + consumer.setPixels(x, y, w, h, model, pixels, off, scansize); + } + + public void setDimensions(int width, int height) { + consumer.setDimensions(width, height); + } + + public void setHints(int hints) { + consumer.setHints(hints); + } + + public void imageComplete(int status) { + consumer.imageComplete(status); + } + +} diff --git a/awt/java/awt/image/ImageObserver.java b/awt/java/awt/image/ImageObserver.java new file mode 100644 index 0000000..21ec41b --- /dev/null +++ b/awt/java/awt/image/ImageObserver.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.Image; + +/** + * the ImageObserver interface is an asynchronous update interface for receiving + * notifications about Image construction status. + * + * @since Android 1.0 + */ +public interface ImageObserver { + + /** + * The Constant WIDTH indicates that the width of the image is available. + */ + public static final int WIDTH = 1; + + /** + * The Constant HEIGHT indicates that the width of the image is available. + */ + public static final int HEIGHT = 2; + + /** + * The Constant PROPERTIES indicates that the properties of the image are + * available. + */ + public static final int PROPERTIES = 4; + + /** + * The Constant SOMEBITS indicates that more bits needed for drawing a + * scaled variation of the image pixels are available. + */ + public static final int SOMEBITS = 8; + + /** + * The Constant FRAMEBITS indicates that complete frame of a image which was + * previously drawn is now available for drawing again. + */ + public static final int FRAMEBITS = 16; + + /** + * The Constant ALLBITS indicates that an image which was previously drawn + * is now complete and can be drawn again. + */ + public static final int ALLBITS = 32; + + /** + * The Constant ERROR indicates that error occurred. + */ + public static final int ERROR = 64; + + /** + * The Constant ABORT indicates that the image producing is aborted. + */ + public static final int ABORT = 128; + + /** + * This method is called when information about an Image interface becomes + * available. This method returns true if further updates are needed, false + * if not. + * + * @param img + * the image to be observed. + * @param infoflags + * the bitwise OR combination of information flags: ABORT, + * ALLBITS, ERROR, FRAMEBITS, HEIGHT, PROPERTIES, SOMEBITS, + * WIDTH. + * @param x + * the X coordinate. + * @param y + * the Y coordinate. + * @param width + * the width. + * @param height + * the height. + * @return true if further updates are needed, false if not. + */ + public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height); + +} diff --git a/awt/java/awt/image/ImageProducer.java b/awt/java/awt/image/ImageProducer.java new file mode 100644 index 0000000..9138be2 --- /dev/null +++ b/awt/java/awt/image/ImageProducer.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +/** + * The ImageProducer provides an interface for objects which produce the image + * data. ImageProducer is used for reconstructing the image. Each image contains + * an ImageProducer. + * + * @since Android 1.0 + */ +public interface ImageProducer { + + /** + * Checks if the specified ImageConsumer is registered with this + * ImageProvider or not. + * + * @param ic + * the ImageConsumer to be checked. + * @return true, if the specified ImageConsumer is registered with this + * ImageProvider, false otherwise. + */ + public boolean isConsumer(ImageConsumer ic); + + /** + * Starts a reconstruction of the image data which will be delivered to this + * consumer. This method adds the specified ImageConsumer before + * reconstructing the image. + * + * @param ic + * the specified ImageConsumer. + */ + public void startProduction(ImageConsumer ic); + + /** + * Requests the ImageProducer to resend the image data in + * ImageConsumer.TOPDOWNLEFTRIGHT order. + * + * @param ic + * the specified ImageConsumer. + */ + public void requestTopDownLeftRightResend(ImageConsumer ic); + + /** + * Deregisters the specified ImageConsumer. + * + * @param ic + * the specified ImageConsumer. + */ + public void removeConsumer(ImageConsumer ic); + + /** + * Adds the specified ImageConsumer object to this ImageProducer. + * + * @param ic + * the specified ImageConsumer. + */ + public void addConsumer(ImageConsumer ic); + +} diff --git a/awt/java/awt/image/ImagingOpException.java b/awt/java/awt/image/ImagingOpException.java new file mode 100644 index 0000000..e0c0127 --- /dev/null +++ b/awt/java/awt/image/ImagingOpException.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Oct 5, 2005 + */ + +package java.awt.image; + +/** + * The ImagingOpException class provides error notification when the + * BufferedImageOp or RasterOp filter methods can not perform the desired filter + * operation. + * + * @since Android 1.0 + */ +public class ImagingOpException extends RuntimeException { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 8026288481846276658L; + + /** + * Instantiates a new ImagingOpException with a detail message. + * + * @param s + * the detail message. + */ + public ImagingOpException(String s) { + super(s); + } +} diff --git a/awt/java/awt/image/IndexColorModel.java b/awt/java/awt/image/IndexColorModel.java new file mode 100644 index 0000000..0b06acd --- /dev/null +++ b/awt/java/awt/image/IndexColorModel.java @@ -0,0 +1,1080 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.math.BigInteger; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class IndexColorModel represents a color model in which the color values + * of the pixels are read from a palette. + * + * @since Android 1.0 + */ +public class IndexColorModel extends ColorModel { + + /** + * The color map. + */ + private int colorMap[]; // Color Map + + /** + * The map size. + */ + private int mapSize; // Color Map size + + /** + * The transparent index. + */ + private int transparentIndex; // Index of fully transparent pixel + + /** + * The gray palette. + */ + private boolean grayPalette; // Color Model has Color Map with Gray Pallete + + /** + * The valid bits. + */ + private BigInteger validBits; // Specify valid Color Map values + + /** + * The Constant CACHESIZE. + */ + private static final int CACHESIZE = 20; // Cache size. Cache used for + + // improving performace of selection + // nearest color in Color Map + + /** + * The cachetable. + */ + private final int cachetable[] = new int[CACHESIZE * 2]; // Cache table - + + // used for + + // storing RGB values and that appropriate indices + // in the Color Map + + /** + * The next insert idx. + */ + private int nextInsertIdx = 0; // Next index for insertion into Cache table + + /** + * The total inserted. + */ + private int totalInserted = 0; // Number of inserted values into Cache table + + /** + * Instantiates a new index color model. + * + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param cmap + * the array that gives the color mapping. + * @param start + * the start index of the color mapping data within the cmap + * array. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + * @param validBits + * a list of which bits represent valid colormap values, or null + * if all are valid. + * @throws IllegalArgumentException + * if the size of the color map is less than one. + */ + public IndexColorModel(int bits, int size, int cmap[], int start, int transferType, + BigInteger validBits) { + + super(bits, IndexColorModel.createBits(true), ColorSpace.getInstance(ColorSpace.CS_sRGB), + true, false, Transparency.OPAQUE, validateTransferType(transferType)); + + if (size < 1) { + // awt.264=Size of the color map is less than 1 + throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$ + } + + mapSize = size; + colorMap = new int[mapSize]; + transparentIndex = -1; + + if (validBits != null) { + for (int i = 0; i < mapSize; i++) { + if (!validBits.testBit(i)) { + this.validBits = validBits; + } + break; + } + } + + transparency = Transparency.OPAQUE; + int alphaMask = 0xff000000; + int alpha = 0; + + for (int i = 0; i < mapSize; i++, start++) { + colorMap[i] = cmap[start]; + alpha = cmap[start] & alphaMask; + + if (alpha == alphaMask) { + continue; + } + if (alpha == 0) { + if (transparentIndex < 0) { + transparentIndex = i; + } + if (transparency == Transparency.OPAQUE) { + transparency = Transparency.BITMASK; + } + } else if (alpha != alphaMask && transparency != Transparency.TRANSLUCENT) { + transparency = Transparency.TRANSLUCENT; + } + + } + checkPalette(); + + } + + /** + * Instantiates a new index color model. + * + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param cmap + * the array that gives the color mapping. + * @param start + * the start index of the color mapping data within the cmap + * array. + * @param hasalpha + * whether this color model uses alpha. + * @param trans + * the transparency supported, @see java.awt.Transparency. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + * @throws IllegalArgumentException + * if the size of the color map is less than one. + */ + public IndexColorModel(int bits, int size, int cmap[], int start, boolean hasalpha, int trans, + int transferType) { + + super(bits, IndexColorModel.createBits(hasalpha || (trans >= 0)), ColorSpace + .getInstance(ColorSpace.CS_sRGB), (hasalpha || (trans >= 0)), false, + Transparency.OPAQUE, validateTransferType(transferType)); + + if (size < 1) { + // awt.264=Size of the color map is less than 1 + throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$ + } + + mapSize = size; + colorMap = new int[mapSize]; + if (trans >= 0 && trans < mapSize) { + transparentIndex = trans; + transparency = Transparency.BITMASK; + } else { + transparentIndex = -1; + transparency = Transparency.OPAQUE; + } + + int alphaMask = 0xff000000; + int alpha = 0; + + for (int i = 0; i < mapSize; i++, start++) { + if (transparentIndex == i) { + colorMap[i] = cmap[start] & 0x00ffffff; + continue; + } + if (hasalpha) { + alpha = cmap[start] & alphaMask; + colorMap[i] = cmap[start]; + + if (alpha == alphaMask) { + continue; + } + if (alpha == 0) { + if (trans < 0) { + trans = i; + } + if (transparency == Transparency.OPAQUE) { + transparency = Transparency.BITMASK; + } + } else if (alpha != 0 && transparency != Transparency.TRANSLUCENT) { + transparency = Transparency.TRANSLUCENT; + } + } else { + colorMap[i] = alphaMask | cmap[start]; + } + } + checkPalette(); + + } + + /** + * Instantiates a new index color model by building the color map from + * arrays of red, green, blue, and alpha values. + * + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param r + * the array giving the red components of the entries in the + * color map. + * @param g + * the array giving the green components of the entries in the + * color map. + * @param b + * the array giving the blue components of the entries in the + * color map. + * @param a + * the array giving the alpha components of the entries in the + * color map. + * @throws IllegalArgumentException + * if the size of the color map is less than one. + * @throws ArrayIndexOutOfBoundsException + * if the size of one of the component arrays is less than the + * size of the color map. + */ + public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[], byte a[]) { + + super(bits, IndexColorModel.createBits(true), ColorSpace.getInstance(ColorSpace.CS_sRGB), + true, false, Transparency.OPAQUE, validateTransferType(ColorModel + .getTransferType(bits))); + + createColorMap(size, r, g, b, a, -1); + checkPalette(); + } + + /** + * Instantiates a new index color model by building the color map from + * arrays of red, green, and blue values. + * + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param r + * the array giving the red components of the entries in the + * color map. + * @param g + * the array giving the green components of the entries in the + * color map. + * @param b + * the array giving the blue components of the entries in the + * color map. + * @param trans + * the transparency supported, @see java.awt.Transparency. + * @throws IllegalArgumentException + * if the size of the color map is less than one. + * @throws ArrayIndexOutOfBoundsException + * if the size of one of the component arrays is less than the + * size of the color map. + */ + public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[], int trans) { + + super(bits, IndexColorModel.createBits((trans >= 0)), ColorSpace + .getInstance(ColorSpace.CS_sRGB), (trans >= 0), false, Transparency.OPAQUE, + validateTransferType(ColorModel.getTransferType(bits))); + + createColorMap(size, r, g, b, null, trans); + checkPalette(); + } + + /** + * Instantiates a new index color model by building the color map from + * arrays of red, green, and blue values. + * + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param r + * the array giving the red components of the entries in the + * color map. + * @param g + * the array giving the green components of the entries in the + * color map. + * @param b + * the array giving the blue components of the entries in the + * color map. + * @throws IllegalArgumentException + * if the size of the color map is less than one. + * @throws ArrayIndexOutOfBoundsException + * if the size of one of the component arrays is less than the + * size of the color map. + */ + public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[]) { + super(bits, IndexColorModel.createBits(false), ColorSpace.getInstance(ColorSpace.CS_sRGB), + false, false, Transparency.OPAQUE, validateTransferType(ColorModel + .getTransferType(bits))); + + createColorMap(size, r, g, b, null, -1); + checkPalette(); + } + + /** + * Instantiates a new index color model. + * + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param cmap + * the array that gives the color mapping. + * @param start + * the start index of the color mapping data within the cmap + * array. + * @param hasalpha + * whether this color model uses alpha. + * @param trans + * the transparency supported, @see java.awt.Transparency. + * @throws IllegalArgumentException + * if the size of the color map is less than one. + */ + public IndexColorModel(int bits, int size, byte cmap[], int start, boolean hasalpha, int trans) { + + super(bits, IndexColorModel.createBits(hasalpha || (trans >= 0)), ColorSpace + .getInstance(ColorSpace.CS_sRGB), (hasalpha || (trans >= 0)), false, + Transparency.OPAQUE, validateTransferType(ColorModel.getTransferType(bits))); + + if (size < 1) { + // awt.264=Size of the color map is less than 1 + throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$ + } + + mapSize = size; + colorMap = new int[mapSize]; + transparentIndex = -1; + + transparency = Transparency.OPAQUE; + int alpha = 0xff000000; + + for (int i = 0; i < mapSize; i++) { + colorMap[i] = (cmap[start++] & 0xff) << 16 | (cmap[start++] & 0xff) << 8 + | (cmap[start++] & 0xff); + if (trans == i) { + if (transparency == Transparency.OPAQUE) { + transparency = Transparency.BITMASK; + } + if (hasalpha) { + start++; + } + continue; + } + if (hasalpha) { + alpha = cmap[start++] & 0xff; + if (alpha == 0) { + if (transparency == Transparency.OPAQUE) { + transparency = Transparency.BITMASK; + if (trans < 0) { + trans = i; + } + } + } else { + if (alpha != 0xff && transparency != Transparency.TRANSLUCENT) { + transparency = Transparency.TRANSLUCENT; + } + } + alpha <<= 24; + } + colorMap[i] |= alpha; + } + + if (trans >= 0 && trans < mapSize) { + transparentIndex = trans; + } + checkPalette(); + + } + + /** + * Instantiates a new index color model. + * + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param cmap + * the array that gives the color mapping. + * @param start + * the start index of the color mapping data within the cmap + * array. + * @param hasalpha + * whether this color model uses alpha. + * @throws IllegalArgumentException + * if the size of the color map is less than one. + */ + public IndexColorModel(int bits, int size, byte cmap[], int start, boolean hasalpha) { + + this(bits, size, cmap, start, hasalpha, -1); + } + + @Override + public Object getDataElements(int[] components, int offset, Object pixel) { + int rgb = (components[offset] << 16) | (components[offset + 1]) << 8 + | components[offset + 2]; + if (hasAlpha) { + rgb |= components[offset + 3] << 24; + } else { + rgb |= 0xff000000; + } + return getDataElements(rgb, pixel); + } + + @Override + public synchronized Object getDataElements(int rgb, Object pixel) { + int red = (rgb >> 16) & 0xff; + int green = (rgb >> 8) & 0xff; + int blue = rgb & 0xff; + int alpha = rgb >>> 24; + int pixIdx = 0; + + for (int i = 0; i < totalInserted; i++) { + int idx = i * 2; + if (rgb == cachetable[idx]) { + return createDataObject(cachetable[idx + 1], pixel); + } + } + + if (!hasAlpha && grayPalette) { + int grey = (red * 77 + green * 150 + blue * 29 + 128) >>> 8; + int minError = 255; + int error = 0; + + for (int i = 0; i < mapSize; i++) { + error = Math.abs((colorMap[i] & 0xff) - grey); + if (error < minError) { + pixIdx = i; + if (error == 0) { + break; + } + minError = error; + } + } + } else if (alpha == 0 && transparentIndex > -1) { + pixIdx = transparentIndex; + } else { + int minAlphaError = 255; + int minError = 195075; // 255^2 + 255^2 + 255^2 + int alphaError; + int error = 0; + + for (int i = 0; i < mapSize; i++) { + int pix = colorMap[i]; + if (rgb == pix) { + pixIdx = i; + break; + } + alphaError = Math.abs(alpha - (pix >>> 24)); + if (alphaError <= minAlphaError) { + minAlphaError = alphaError; + + int buf = ((pix >> 16) & 0xff) - red; + error = buf * buf; + + if (error < minError) { + buf = ((pix >> 8) & 0xff) - green; + error += buf * buf; + + if (error < minError) { + buf = (pix & 0xff) - blue; + error += buf * buf; + + if (error < minError) { + pixIdx = i; + minError = error; + } + } + } + } + } + } + + cachetable[nextInsertIdx] = rgb; + cachetable[nextInsertIdx + 1] = pixIdx; + + nextInsertIdx = (nextInsertIdx + 2) % (CACHESIZE * 2); + if (totalInserted < CACHESIZE) { + totalInserted++; + } + + return createDataObject(pixIdx, pixel); + } + + /** + * Converts an image from indexed to RGB format. + * + * @param raster + * the raster containing the source image. + * @param forceARGB + * whether to use the default RGB color model. + * @return the buffered image. + * @throws IllegalArgumentException + * if the raster is not compatible with this color model. + */ + public BufferedImage convertToIntDiscrete(Raster raster, boolean forceARGB) { + + if (!isCompatibleRaster(raster)) { + // awt.265=The raster argument is not compatible with this + // IndexColorModel + throw new IllegalArgumentException(Messages.getString("awt.265")); //$NON-NLS-1$ + } + + ColorModel model; + if (forceARGB || transparency == Transparency.TRANSLUCENT) { + model = ColorModel.getRGBdefault(); + } else if (transparency == Transparency.BITMASK) { + model = new DirectColorModel(25, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x01000000); + } else { + model = new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff); + } + + int w = raster.getWidth(); + int h = raster.getHeight(); + + WritableRaster distRaster = model.createCompatibleWritableRaster(w, h); + + int minX = raster.getMinX(); + int minY = raster.getMinY(); + + Object obj = null; + int pixels[] = null; + + for (int i = 0; i < h; i++, minY++) { + obj = raster.getDataElements(minX, minY, w, 1, obj); + if (obj instanceof byte[]) { + byte ba[] = (byte[])obj; + if (pixels == null) { + pixels = new int[ba.length]; + } + for (int j = 0; j < ba.length; j++) { + pixels[j] = colorMap[ba[j] & 0xff]; + } + } else if (obj instanceof short[]) { + short sa[] = (short[])obj; + if (pixels == null) { + pixels = new int[sa.length]; + } + for (int j = 0; j < sa.length; j++) { + pixels[j] = colorMap[sa[j] & 0xffff]; + } + } + if (obj instanceof int[]) { + int ia[] = (int[])obj; + if (pixels == null) { + pixels = new int[ia.length]; + } + for (int j = 0; j < ia.length; j++) { + pixels[j] = colorMap[ia[j]]; + } + } + + distRaster.setDataElements(0, i, w, 1, pixels); + } + + return new BufferedImage(model, distRaster, false, null); + } + + /** + * Gets the valid pixels. + * + * @return the valid pixels. + */ + public BigInteger getValidPixels() { + return validBits; + } + + @Override + public String toString() { + // The output format based on 1.5 release behaviour. + // It could be reveled such way: + // BufferedImage bi = new BufferedImage(1, 1, + // BufferedImage.TYPE_BYTE_INDEXED); + // ColorModel cm = bi.getColorModel(); + // System.out.println(cm.toString()); + String str = "IndexColorModel: #pixel_bits = " + pixel_bits + //$NON-NLS-1$ + " numComponents = " + numComponents + " color space = " + cs + //$NON-NLS-1$ //$NON-NLS-2$ + " transparency = "; //$NON-NLS-1$ + + if (transparency == Transparency.OPAQUE) { + str = str + "Transparency.OPAQUE"; //$NON-NLS-1$ + } else if (transparency == Transparency.BITMASK) { + str = str + "Transparency.BITMASK"; //$NON-NLS-1$ + } else { + str = str + "Transparency.TRANSLUCENT"; //$NON-NLS-1$ + } + + str = str + " transIndex = " + transparentIndex + " has alpha = " + //$NON-NLS-1$ //$NON-NLS-2$ + hasAlpha + " isAlphaPre = " + isAlphaPremultiplied; //$NON-NLS-1$ + + return str; + } + + @Override + public int[] getComponents(Object pixel, int components[], int offset) { + int pixIdx = -1; + if (pixel instanceof byte[]) { + byte ba[] = (byte[])pixel; + pixIdx = ba[0] & 0xff; + } else if (pixel instanceof short[]) { + short sa[] = (short[])pixel; + pixIdx = sa[0] & 0xffff; + } else if (pixel instanceof int[]) { + int ia[] = (int[])pixel; + pixIdx = ia[0]; + } else { + // awt.219=This transferType is not supported by this color model + throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$ + } + + return getComponents(pixIdx, components, offset); + } + + @Override + public WritableRaster createCompatibleWritableRaster(int w, int h) { + WritableRaster raster; + if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) { + raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, w, h, 1, pixel_bits, null); + } else if (pixel_bits <= 8) { + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, 1, null); + } else if (pixel_bits <= 16) { + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT, w, h, 1, null); + } else { + // awt.266=The number of bits in a pixel is greater than 16 + throw new UnsupportedOperationException(Messages.getString("awt.266")); //$NON-NLS-1$ + } + + return raster; + } + + @Override + public boolean isCompatibleSampleModel(SampleModel sm) { + if (sm == null) { + return false; + } + + if (!(sm instanceof MultiPixelPackedSampleModel) && !(sm instanceof ComponentSampleModel)) { + return false; + } + + if (sm.getTransferType() != transferType) { + return false; + } + if (sm.getNumBands() != 1) { + return false; + } + + return true; + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) { + return new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, w, h, pixel_bits); + } + int bandOffsets[] = new int[1]; + bandOffsets[0] = 0; + return new ComponentSampleModel(transferType, w, h, 1, w, bandOffsets); + + } + + @Override + public boolean isCompatibleRaster(Raster raster) { + int sampleSize = raster.getSampleModel().getSampleSize(0); + return (raster.getTransferType() == transferType && raster.getNumBands() == 1 && (1 << sampleSize) >= mapSize); + } + + @Override + public int getDataElement(int components[], int offset) { + int rgb = (components[offset] << 16) | (components[offset + 1]) << 8 + | components[offset + 2]; + + if (hasAlpha) { + rgb |= components[offset + 3] << 24; + } else { + rgb |= 0xff000000; + } + + int pixel; + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])getDataElements(rgb, null); + pixel = ba[0] & 0xff; + break; + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])getDataElements(rgb, null); + pixel = sa[0] & 0xffff; + break; + default: + // awt.267=The transferType is invalid + throw new UnsupportedOperationException(Messages.getString("awt.267")); //$NON-NLS-1$ + } + + return pixel; + } + + /** + * Gets the color map. + * + * @param rgb + * the destination array where the color map is written. + */ + public final void getRGBs(int rgb[]) { + System.arraycopy(colorMap, 0, rgb, 0, mapSize); + } + + /** + * Gets the red component of the color map. + * + * @param r + * the destination array. + */ + public final void getReds(byte r[]) { + for (int i = 0; i < mapSize; i++) { + r[i] = (byte)(colorMap[i] >> 16); + } + } + + /** + * Gets the green component of the color map. + * + * @param g + * the destination array. + */ + public final void getGreens(byte g[]) { + for (int i = 0; i < mapSize; i++) { + g[i] = (byte)(colorMap[i] >> 8); + } + } + + /** + * Gets the blue component of the color map. + * + * @param b + * the destination array. + */ + public final void getBlues(byte b[]) { + for (int i = 0; i < mapSize; i++) { + b[i] = (byte)colorMap[i]; + } + } + + /** + * Gets the alpha component of the color map. + * + * @param a + * the destination array. + */ + public final void getAlphas(byte a[]) { + for (int i = 0; i < mapSize; i++) { + a[i] = (byte)(colorMap[i] >> 24); + } + } + + @Override + public int[] getComponents(int pixel, int components[], int offset) { + if (components == null) { + components = new int[offset + numComponents]; + } + + components[offset + 0] = getRed(pixel); + components[offset + 1] = getGreen(pixel); + components[offset + 2] = getBlue(pixel); + if (hasAlpha && (components.length - offset) > 3) { + components[offset + 3] = getAlpha(pixel); + } + + return components; + } + + /** + * Checks if the specified pixel is valid for this color model. + * + * @param pixel + * the pixel. + * @return true, if the pixel is valid. + */ + public boolean isValid(int pixel) { + if (validBits == null) { + return (pixel >= 0 && pixel < mapSize); + } + return (pixel < mapSize && validBits.testBit(pixel)); + } + + @Override + public final int getRed(int pixel) { + return (colorMap[pixel] >> 16) & 0xff; + } + + @Override + public final int getRGB(int pixel) { + return colorMap[pixel]; + } + + @Override + public final int getGreen(int pixel) { + return (colorMap[pixel] >> 8) & 0xff; + } + + @Override + public final int getBlue(int pixel) { + return colorMap[pixel] & 0xff; + } + + @Override + public final int getAlpha(int pixel) { + return (colorMap[pixel] >> 24) & 0xff; + } + + @Override + public int[] getComponentSize() { + return bits.clone(); + } + + /** + * Checks if this color model validates pixels. + * + * @return true, if all pixels are valid, otherwise false. + */ + public boolean isValid() { + return (validBits == null); + } + + @Override + public void finalize() { + // TODO: implement + return; + } + + /** + * Gets the index that represents the transparent pixel. + * + * @return the index that represents the transparent pixel. + */ + public final int getTransparentPixel() { + return transparentIndex; + } + + @Override + public int getTransparency() { + return transparency; + } + + /** + * Gets the size of the color map. + * + * @return the map size. + */ + public final int getMapSize() { + return mapSize; + } + + /** + * Creates the color map. + * + * @param size + * the size. + * @param r + * the r. + * @param g + * the g. + * @param b + * the b. + * @param a + * the a. + * @param trans + * the trans. + */ + private void createColorMap(int size, byte r[], byte g[], byte b[], byte a[], int trans) { + if (size < 1) { + // awt.264=Size of the color map is less than 1 + throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$ + } + + mapSize = size; + colorMap = new int[mapSize]; + if (trans >= 0 && trans < mapSize) { + transparency = Transparency.BITMASK; + transparentIndex = trans; + } else { + transparency = Transparency.OPAQUE; + transparentIndex = -1; + } + int alpha = 0; + + for (int i = 0; i < mapSize; i++) { + colorMap[i] = ((r[i] & 0xff) << 16) | ((g[i] & 0xff) << 8) | (b[i] & 0xff); + + if (trans == i) { + continue; + } + + if (a == null) { + colorMap[i] |= 0xff000000; + } else { + alpha = a[i] & 0xff; + if (alpha == 0xff) { + colorMap[i] |= 0xff000000; + } else if (alpha == 0) { + if (transparency == Transparency.OPAQUE) { + transparency = Transparency.BITMASK; + } + if (transparentIndex < 0) { + transparentIndex = i; + } + } else { + colorMap[i] |= (a[i] & 0xff) << 24; + if (transparency != Transparency.TRANSLUCENT) { + transparency = Transparency.TRANSLUCENT; + } + } + } + + } + + } + + /** + * This method checking, if Color Map has Gray palette. + */ + private void checkPalette() { + grayPalette = false; + if (transparency > Transparency.OPAQUE) { + return; + } + int rgb = 0; + + for (int i = 0; i < mapSize; i++) { + rgb = colorMap[i]; + if (((rgb >> 16) & 0xff) != ((rgb >> 8) & 0xff) || ((rgb >> 8) & 0xff) != (rgb & 0xff)) { + return; + } + } + grayPalette = true; + } + + /** + * Construction an array pixel representation. + * + * @param colorMapIdx + * the index into Color Map. + * @param pixel + * the pixel + * @return the pixel representation array. + */ + private Object createDataObject(int colorMapIdx, Object pixel) { + if (pixel == null) { + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte[] ba = new byte[1]; + ba[0] = (byte)colorMapIdx; + pixel = ba; + break; + case DataBuffer.TYPE_USHORT: + short[] sa = new short[1]; + sa[0] = (short)colorMapIdx; + pixel = sa; + break; + default: + // awt.267=The transferType is invalid + throw new UnsupportedOperationException(Messages.getString("awt.267")); //$NON-NLS-1$ + } + } else if (pixel instanceof byte[] && transferType == DataBuffer.TYPE_BYTE) { + byte ba[] = (byte[])pixel; + ba[0] = (byte)colorMapIdx; + pixel = ba; + } else if (pixel instanceof short[] && transferType == DataBuffer.TYPE_USHORT) { + short[] sa = (short[])pixel; + sa[0] = (short)colorMapIdx; + pixel = sa; + } else if (pixel instanceof int[]) { + int ia[] = (int[])pixel; + ia[0] = colorMapIdx; + pixel = ia; + } else { + // awt.268=The pixel is not a primitive array of type transferType + throw new ClassCastException(Messages.getString("awt.268")); //$NON-NLS-1$ + } + return pixel; + } + + /** + * Creates the bits. + * + * @param hasAlpha + * the has alpha. + * @return the int[]. + */ + private static int[] createBits(boolean hasAlpha) { + + int numChannels; + if (hasAlpha) { + numChannels = 4; + } else { + numChannels = 3; + } + + int bits[] = new int[numChannels]; + for (int i = 0; i < numChannels; i++) { + bits[i] = 8; + } + + return bits; + + } + + /** + * Validate transfer type. + * + * @param transferType + * the transfer type. + * @return the int. + */ + private static int validateTransferType(int transferType) { + if (transferType != DataBuffer.TYPE_BYTE && transferType != DataBuffer.TYPE_USHORT) { + // awt.269=The transferType is not one of DataBuffer.TYPE_BYTE or + // DataBuffer.TYPE_USHORT + throw new IllegalArgumentException(Messages.getString("awt.269")); //$NON-NLS-1$ + } + return transferType; + } + + /** + * Checks if is gray palette. + * + * @return true, if is gray palette. + */ + boolean isGrayPallete() { + return grayPalette; + } + +} diff --git a/awt/java/awt/image/Kernel.java b/awt/java/awt/image/Kernel.java new file mode 100644 index 0000000..a59d27a --- /dev/null +++ b/awt/java/awt/image/Kernel.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Sep 28, 2005 + */ + +package java.awt.image; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Kernel class provides a matrix. This matrix is stored as a float array + * which describes how a specified pixel affects the value calculated for the + * pixel's position in the output image of a filtering operation. The X, Y + * origins indicate the kernel matrix element which corresponds to the pixel + * position for which an output value is being calculated. + * + * @since Android 1.0 + */ +public class Kernel implements Cloneable { + + /** + * The x origin. + */ + private final int xOrigin; + + /** + * The y origin. + */ + private final int yOrigin; + + /** + * The width. + */ + private int width; + + /** + * The height. + */ + private int height; + + /** + * The data. + */ + float data[]; + + /** + * Instantiates a new Kernel with the specified float array. The + * width*height elements of the data array are copied. + * + * @param width + * the width of the Kernel. + * @param height + * the height of the Kernel. + * @param data + * the data of Kernel. + */ + public Kernel(int width, int height, float[] data) { + int dataLength = width * height; + if (data.length < dataLength) { + // awt.22B=Length of data should not be less than width*height + throw new IllegalArgumentException(Messages.getString("awt.22B")); //$NON-NLS-1$ + } + + this.width = width; + this.height = height; + + this.data = new float[dataLength]; + System.arraycopy(data, 0, this.data, 0, dataLength); + + xOrigin = (width - 1) / 2; + yOrigin = (height - 1) / 2; + } + + /** + * Gets the width of this Kernel. + * + * @return the width of this Kernel. + */ + public final int getWidth() { + return width; + } + + /** + * Gets the height of this Kernel. + * + * @return the height of this Kernel. + */ + public final int getHeight() { + return height; + } + + /** + * Gets the float data array of this Kernel. + * + * @param data + * the float array where the resulted data will be stored. + * @return the float data array of this Kernel. + */ + public final float[] getKernelData(float[] data) { + if (data == null) { + data = new float[this.data.length]; + } + System.arraycopy(this.data, 0, data, 0, this.data.length); + + return data; + } + + /** + * Gets the X origin of this Kernel. + * + * @return the X origin of this Kernel. + */ + public final int getXOrigin() { + return xOrigin; + } + + /** + * Gets the Y origin of this Kernel. + * + * @return the Y origin of this Kernel. + */ + public final int getYOrigin() { + return yOrigin; + } + + /** + * Returns a copy of this Kernel object. + * + * @return the copy of this Kernel object. + */ + @Override + public Object clone() { + return new Kernel(width, height, data); + } +} diff --git a/awt/java/awt/image/LookupOp.java b/awt/java/awt/image/LookupOp.java new file mode 100644 index 0000000..3362c5c --- /dev/null +++ b/awt/java/awt/image/LookupOp.java @@ -0,0 +1,661 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Oct 14, 2005 + */ + +package java.awt.image; + +import java.awt.*; +import java.awt.geom.Rectangle2D; +import java.awt.geom.Point2D; +import java.util.Arrays; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The LookupOp class performs a lookup operation which transforms a source + * image by filtering each band using a table of data. The table may contain a + * single array or it may contain a different data array for each band of the + * image. + * + * @since Android 1.0 + */ +public class LookupOp implements BufferedImageOp, RasterOp { + + /** + * The lut. + */ + private final LookupTable lut; + + /** + * The hints. + */ + private RenderingHints hints; + + // TODO remove when this field is used + /** + * The can use ipp. + */ + @SuppressWarnings("unused") + private final boolean canUseIpp; + + // We don't create levels/values when it is possible to reuse old + /** + * The cached levels. + */ + private int cachedLevels[]; + + /** + * The cached values. + */ + private int cachedValues[]; + + // Number of channels for which cache is valid. + // If negative number of channels is same as positive but skipAlpha was + // specified + /** + * The valid for channels. + */ + private int validForChannels; + + /** + * The level initializer. + */ + static int levelInitializer[] = new int[0x10000]; + + static { + // TODO + // System.loadLibrary("imageops"); + + for (int i = 1; i <= 0x10000; i++) { + levelInitializer[i - 1] = i; + } + } + + /** + * Instantiates a new LookupOp object from the specified LookupTable object + * and a RenderingHints object. + * + * @param lookup + * the specified LookupTable object. + * @param hints + * the RenderingHints object or null. + */ + public LookupOp(LookupTable lookup, RenderingHints hints) { + if (lookup == null) { + throw new NullPointerException(Messages.getString("awt.01", "lookup")); //$NON-NLS-1$ //$NON-NLS-2$ + } + lut = lookup; + this.hints = hints; + canUseIpp = lut instanceof ByteLookupTable || lut instanceof ShortLookupTable; + } + + /** + * Gets the LookupTable of the specified Object. + * + * @return the LookupTable of the specified Object. + */ + public final LookupTable getTable() { + return lut; + } + + public final RenderingHints getRenderingHints() { + return hints; + } + + public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { + if (dstPt == null) { + dstPt = new Point2D.Float(); + } + + dstPt.setLocation(srcPt); + return dstPt; + } + + public final Rectangle2D getBounds2D(Raster src) { + return src.getBounds(); + } + + public final Rectangle2D getBounds2D(BufferedImage src) { + return getBounds2D(src.getRaster()); + } + + public WritableRaster createCompatibleDestRaster(Raster src) { + return src.createCompatibleWritableRaster(); + } + + public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) { + if (dstCM == null) { + dstCM = src.getColorModel(); + + // Sync transfer type with LUT for component color model + if (dstCM instanceof ComponentColorModel) { + int transferType = dstCM.getTransferType(); + if (lut instanceof ByteLookupTable) { + transferType = DataBuffer.TYPE_BYTE; + } else if (lut instanceof ShortLookupTable) { + transferType = DataBuffer.TYPE_SHORT; + } + + dstCM = new ComponentColorModel(dstCM.cs, dstCM.hasAlpha(), + dstCM.isAlphaPremultiplied, dstCM.transparency, transferType); + } + } + + WritableRaster r = dstCM.isCompatibleSampleModel(src.getSampleModel()) ? src.getRaster() + .createCompatibleWritableRaster(src.getWidth(), src.getHeight()) : dstCM + .createCompatibleWritableRaster(src.getWidth(), src.getHeight()); + + return new BufferedImage(dstCM, r, dstCM.isAlphaPremultiplied(), null); + } + + public final WritableRaster filter(Raster src, WritableRaster dst) { + if (dst == null) { + dst = createCompatibleDestRaster(src); + } else { + if (src.getNumBands() != dst.getNumBands()) { + throw new IllegalArgumentException(Messages.getString("awt.237")); //$NON-NLS-1$ } + } + if (src.getWidth() != dst.getWidth()) { + throw new IllegalArgumentException(Messages.getString("awt.28F")); //$NON-NLS-1$ } + } + if (src.getHeight() != dst.getHeight()) { + throw new IllegalArgumentException(Messages.getString("awt.290")); //$NON-NLS-1$ } + } + } + + if (lut.getNumComponents() != 1 && lut.getNumComponents() != src.getNumBands()) { + // awt.238=The number of arrays in the LookupTable does not meet the + // restrictions + throw new IllegalArgumentException(Messages.getString("awt.238")); //$NON-NLS-1$ + } + + // TODO + // if (!canUseIpp || ippFilter(src, dst, BufferedImage.TYPE_CUSTOM, + // false) != 0) + if (slowFilter(src, dst, false) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + } + + return dst; + } + + public final BufferedImage filter(BufferedImage src, BufferedImage dst) { + ColorModel srcCM = src.getColorModel(); + + if (srcCM instanceof IndexColorModel) { + // awt.220=Source should not have IndexColorModel + throw new IllegalArgumentException(Messages.getString("awt.220")); //$NON-NLS-1$ + } + + // Check if the number of scaling factors matches the number of bands + int nComponents = srcCM.getNumComponents(); + int nLUTComponents = lut.getNumComponents(); + boolean skipAlpha; + if (srcCM.hasAlpha()) { + if (nLUTComponents == 1 || nLUTComponents == nComponents - 1) { + skipAlpha = true; + } else if (nLUTComponents == nComponents) { + skipAlpha = false; + } else { + // awt.229=Number of components in the LUT does not match the + // number of bands + throw new IllegalArgumentException(Messages.getString("awt.229")); //$NON-NLS-1$ + } + } else if (nLUTComponents == 1 || nLUTComponents == nComponents) { + skipAlpha = false; + } else { + // awt.229=Number of components in the LUT does not match the number + // of bands + throw new IllegalArgumentException(Messages.getString("awt.229")); //$NON-NLS-1$ + } + + BufferedImage finalDst = null; + if (dst == null) { + finalDst = dst; + dst = createCompatibleDestImage(src, null); + } else { + if (src.getWidth() != dst.getWidth()) { + throw new IllegalArgumentException(Messages.getString("awt.291")); //$NON-NLS-1$ + } + + if (src.getHeight() != dst.getHeight()) { + throw new IllegalArgumentException(Messages.getString("awt.292")); //$NON-NLS-1$ + } + + if (!srcCM.equals(dst.getColorModel())) { + // Treat BufferedImage.TYPE_INT_RGB and + // BufferedImage.TYPE_INT_ARGB as same + if (!((src.getType() == BufferedImage.TYPE_INT_RGB || src.getType() == BufferedImage.TYPE_INT_ARGB) && (dst + .getType() == BufferedImage.TYPE_INT_RGB || dst.getType() == BufferedImage.TYPE_INT_ARGB))) { + finalDst = dst; + dst = createCompatibleDestImage(src, null); + } + } + } + + // TODO + // if (!canUseIpp || ippFilter(src.getRaster(), dst.getRaster(), + // src.getType(), skipAlpha) != 0) + if (slowFilter(src.getRaster(), dst.getRaster(), skipAlpha) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + } + + if (finalDst != null) { + Graphics2D g = finalDst.createGraphics(); + g.setComposite(AlphaComposite.Src); + g.drawImage(dst, 0, 0, null); + } else { + finalDst = dst; + } + + return dst; + } + + /** + * Slow filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @param skipAlpha + * the skip alpha. + * @return the int. + */ + private final int slowFilter(Raster src, WritableRaster dst, boolean skipAlpha) { + int minSrcX = src.getMinX(); + int minDstX = dst.getMinX(); + int minSrcY = src.getMinY(); + int minDstY = dst.getMinY(); + + int skippingChannels = skipAlpha ? 1 : 0; + int numBands2Process = src.getNumBands() - skippingChannels; + + int numBands = src.getNumBands(); + int srcHeight = src.getHeight(); + int srcWidth = src.getWidth(); + + int[] pixels = null; + int offset = lut.getOffset(); + + if (lut instanceof ByteLookupTable) { + byte[][] byteData = ((ByteLookupTable)lut).getTable(); + pixels = src.getPixels(minSrcX, minSrcY, srcWidth, srcHeight, pixels); + + if (lut.getNumComponents() != 1) { + for (int i = 0; i < pixels.length; i += numBands) { + for (int b = 0; b < numBands2Process; b++) { + pixels[i + b] = byteData[b][pixels[i + b] - offset] & 0xFF; + } + } + } else { + for (int i = 0; i < pixels.length; i += numBands) { + for (int b = 0; b < numBands2Process; b++) { + pixels[i + b] = byteData[0][pixels[i + b] - offset] & 0xFF; + } + } + } + + dst.setPixels(minDstX, minDstY, srcWidth, srcHeight, pixels); + } else if (lut instanceof ShortLookupTable) { + short[][] shortData = ((ShortLookupTable)lut).getTable(); + pixels = src.getPixels(minSrcX, minSrcY, srcWidth, srcHeight, pixels); + + if (lut.getNumComponents() != 1) { + for (int i = 0; i < pixels.length; i += numBands) { + for (int b = 0; b < numBands2Process; b++) { + pixels[i + b] = shortData[b][pixels[i + b] - offset] & 0xFFFF; + } + } + } else { + for (int i = 0; i < pixels.length; i += numBands) { + for (int b = 0; b < numBands2Process; b++) { + pixels[i + b] = shortData[0][pixels[i + b] - offset] & 0xFFFF; + } + } + } + + dst.setPixels(minDstX, minDstY, srcWidth, srcHeight, pixels); + } else { + int pixel[] = new int[src.getNumBands()]; + int maxY = minSrcY + srcHeight; + int maxX = minSrcX + srcWidth; + for (int srcY = minSrcY, dstY = minDstY; srcY < maxY; srcY++, dstY++) { + for (int srcX = minSrcX, dstX = minDstX; srcX < maxX; srcX++, dstX++) { + src.getPixel(srcX, srcY, pixel); + lut.lookupPixel(pixel, pixel); + dst.setPixel(dstX, dstY, pixel); + } + } + } + + return 0; + } + + /** + * Creates the byte levels. + * + * @param channels + * the channels. + * @param skipAlpha + * the skip alpha. + * @param levels + * the levels. + * @param values + * the values. + * @param channelsOrder + * the channels order. + */ + private final void createByteLevels(int channels, boolean skipAlpha, int levels[], + int values[], int channelsOrder[]) { + byte data[][] = ((ByteLookupTable)lut).getTable(); + int nLevels = data[0].length; + int offset = lut.getOffset(); + + // Use one data array for all channels or use several data arrays + int dataIncrement = data.length > 1 ? 1 : 0; + + for (int ch = 0, dataIdx = 0; ch < channels; dataIdx += dataIncrement, ch++) { + int channelOffset = channelsOrder == null ? ch : channelsOrder[ch]; + int channelBase = nLevels * channelOffset; + + // Skip last channel if needed, zero values are OK - + // no changes to the channel information will be done in IPP + if ((channelOffset == channels - 1 && skipAlpha) || (dataIdx >= data.length)) { + continue; + } + + System.arraycopy(levelInitializer, offset, levels, channelBase, nLevels); + for (int from = 0, to = channelBase; from < nLevels; from++, to++) { + values[to] = data[dataIdx][from] & 0xFF; + } + } + } + + /** + * Creates the short levels. + * + * @param channels + * the channels. + * @param skipAlpha + * the skip alpha. + * @param levels + * the levels. + * @param values + * the values. + * @param channelsOrder + * the channels order. + */ + private final void createShortLevels(int channels, boolean skipAlpha, int levels[], + int values[], int channelsOrder[]) { + short data[][] = ((ShortLookupTable)lut).getTable(); + int nLevels = data[0].length; + int offset = lut.getOffset(); + + // Use one data array for all channels or use several data arrays + int dataIncrement = data.length > 1 ? 1 : 0; + + for (int ch = 0, dataIdx = 0; ch < channels; dataIdx += dataIncrement, ch++) { + int channelOffset = channelsOrder == null ? ch : channelsOrder[ch]; + + // Skip last channel if needed, zero values are OK - + // no changes to the channel information will be done in IPP + if ((channelOffset == channels - 1 && skipAlpha) || (dataIdx >= data.length)) { + continue; + } + + int channelBase = nLevels * channelOffset; + System.arraycopy(levelInitializer, offset, levels, channelBase, nLevels); + for (int from = 0, to = channelBase; from < nLevels; from++, to++) { + values[to] = data[dataIdx][from] & 0xFFFF; + } + } + } + + // TODO remove when this method is used + /** + * Ipp filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @param imageType + * the image type. + * @param skipAlpha + * the skip alpha. + * @return the int. + */ + @SuppressWarnings("unused") + private final int ippFilter(Raster src, WritableRaster dst, int imageType, boolean skipAlpha) { + int res; + + int srcStride, dstStride; + int channels; + int offsets[] = null; + int channelsOrder[] = null; + + switch (imageType) { + case BufferedImage.TYPE_INT_ARGB: + case BufferedImage.TYPE_INT_ARGB_PRE: + case BufferedImage.TYPE_INT_RGB: { + channels = 4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; + channelsOrder = new int[] { + 2, 1, 0, 3 + }; + break; + } + + case BufferedImage.TYPE_4BYTE_ABGR: + case BufferedImage.TYPE_4BYTE_ABGR_PRE: + case BufferedImage.TYPE_INT_BGR: { + channels = 4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; + break; + } + + case BufferedImage.TYPE_BYTE_GRAY: { + channels = 1; + srcStride = src.getWidth(); + dstStride = dst.getWidth(); + break; + } + + case BufferedImage.TYPE_3BYTE_BGR: { + channels = 3; + srcStride = src.getWidth() * 3; + dstStride = dst.getWidth() * 3; + channelsOrder = new int[] { + 2, 1, 0 + }; + break; + } + + case BufferedImage.TYPE_USHORT_GRAY: + case BufferedImage.TYPE_USHORT_565_RGB: + case BufferedImage.TYPE_USHORT_555_RGB: + case BufferedImage.TYPE_BYTE_BINARY: { + return slowFilter(src, dst, skipAlpha); + } + + default: { + SampleModel srcSM = src.getSampleModel(); + SampleModel dstSM = dst.getSampleModel(); + + if (srcSM instanceof PixelInterleavedSampleModel + && dstSM instanceof PixelInterleavedSampleModel) { + // Check PixelInterleavedSampleModel + if (srcSM.getDataType() != DataBuffer.TYPE_BYTE + || dstSM.getDataType() != DataBuffer.TYPE_BYTE) { + return slowFilter(src, dst, skipAlpha); + } + + // Have IPP functions for 1, 3 and 4 channels + channels = srcSM.getNumBands(); + if (!(channels == 1 || channels == 3 || channels == 4)) { + return slowFilter(src, dst, skipAlpha); + } + + srcStride = ((ComponentSampleModel)srcSM).getScanlineStride(); + dstStride = ((ComponentSampleModel)dstSM).getScanlineStride(); + + channelsOrder = ((ComponentSampleModel)srcSM).getBandOffsets(); + } else if (srcSM instanceof SinglePixelPackedSampleModel + && dstSM instanceof SinglePixelPackedSampleModel) { + // Check SinglePixelPackedSampleModel + SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)srcSM; + SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel)dstSM; + + channels = sppsm1.getNumBands(); + + // TYPE_INT_RGB, TYPE_INT_ARGB... + if (sppsm1.getDataType() != DataBuffer.TYPE_INT + || sppsm2.getDataType() != DataBuffer.TYPE_INT + || !(channels == 3 || channels == 4)) { + return slowFilter(src, dst, skipAlpha); + } + + // Check compatibility of sample models + if (!Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) + || !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())) { + return slowFilter(src, dst, skipAlpha); + } + + for (int i = 0; i < channels; i++) { + if (sppsm1.getSampleSize(i) != 8) { + return slowFilter(src, dst, skipAlpha); + } + } + + channelsOrder = new int[channels]; + int bitOffsets[] = sppsm1.getBitOffsets(); + for (int i = 0; i < channels; i++) { + channelsOrder[i] = bitOffsets[i] / 8; + } + + if (channels == 3) { // Don't skip channel now, could be + // optimized + channels = 4; + } + + srcStride = sppsm1.getScanlineStride() * 4; + dstStride = sppsm2.getScanlineStride() * 4; + } else { + return slowFilter(src, dst, skipAlpha); + } + + // Fill offsets if there's a child raster + if (src.getParent() != null || dst.getParent() != null) { + if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0 + || dst.getSampleModelTranslateX() != 0 + || dst.getSampleModelTranslateY() != 0) { + offsets = new int[4]; + offsets[0] = -src.getSampleModelTranslateX() + src.getMinX(); + offsets[1] = -src.getSampleModelTranslateY() + src.getMinY(); + offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX(); + offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY(); + } + } + } + } + + int levels[] = null, values[] = null; + int channelMultiplier = skipAlpha ? -1 : 1; + if (channelMultiplier * channels == validForChannels) { // use existing + // levels/values + levels = cachedLevels; + values = cachedValues; + } else { // create new levels/values + if (lut instanceof ByteLookupTable) { + byte data[][] = ((ByteLookupTable)lut).getTable(); + levels = new int[channels * data[0].length]; + values = new int[channels * data[0].length]; + createByteLevels(channels, skipAlpha, levels, values, channelsOrder); + } else if (lut instanceof ShortLookupTable) { + short data[][] = ((ShortLookupTable)lut).getTable(); + levels = new int[channels * data[0].length]; + values = new int[channels * data[0].length]; + createShortLevels(channels, skipAlpha, levels, values, channelsOrder); + } + + // cache levels/values + validForChannels = channelMultiplier * channels; + cachedLevels = levels; + cachedValues = values; + } + + Object srcData, dstData; + AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance(); + try { + srcData = dbAccess.getData(src.getDataBuffer()); + dstData = dbAccess.getData(dst.getDataBuffer()); + } catch (IllegalArgumentException e) { + return -1; // Unknown data buffer type + } + + res = ippLUT(srcData, src.getWidth(), src.getHeight(), srcStride, dstData, dst.getWidth(), + dst.getHeight(), dstStride, levels, values, channels, offsets, false); + + return res; + } + + /** + * Ipp lut. + * + * @param src + * the src. + * @param srcWidth + * the src width. + * @param srcHeight + * the src height. + * @param srcStride + * the src stride. + * @param dst + * the dst. + * @param dstWidth + * the dst width. + * @param dstHeight + * the dst height. + * @param dstStride + * the dst stride. + * @param levels + * the levels. + * @param values + * the values. + * @param channels + * the channels. + * @param offsets + * the offsets. + * @param linear + * the linear. + * @return the int. + */ + final static native int ippLUT(Object src, int srcWidth, int srcHeight, int srcStride, + Object dst, int dstWidth, int dstHeight, int dstStride, int levels[], int values[], + int channels, int offsets[], boolean linear); +} diff --git a/awt/java/awt/image/LookupTable.java b/awt/java/awt/image/LookupTable.java new file mode 100644 index 0000000..e465a54 --- /dev/null +++ b/awt/java/awt/image/LookupTable.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Oct 14, 2005 + */ + +package java.awt.image; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * This abstract LookupTable class represents lookup table which is defined with + * the number of components and offset value. ByteLookupTable and + * ShortLookupTable classes are subclasses of LookupTable which contains byte + * and short data tables as an input arrays for bands or components of image. + * + * @since Android 1.0 + */ +public abstract class LookupTable { + + /** + * The offset. + */ + private int offset; + + /** + * The num components. + */ + private int numComponents; + + /** + * Instantiates a new LookupTable with the specified offset value and number + * of components. + * + * @param offset + * the offset value. + * @param numComponents + * the number of components. + */ + protected LookupTable(int offset, int numComponents) { + if (offset < 0) { + // awt.232=Offset should be not less than zero + throw new IllegalArgumentException(Messages.getString("awt.232")); //$NON-NLS-1$ + } + if (numComponents < 1) { + // awt.233=Number of components should be positive + throw new IllegalArgumentException(Messages.getString("awt.233")); //$NON-NLS-1$ + } + + this.offset = offset; + this.numComponents = numComponents; + } + + /** + * Gets the offset value of this Lookup table. + * + * @return the offset value of this Lookup table. + */ + public int getOffset() { + return offset; + } + + /** + * Gets the number of components of this Lookup table. + * + * @return the number components of this Lookup table. + */ + public int getNumComponents() { + return numComponents; + } + + /** + * Returns an integer array which contains samples of the specified pixel which + * is translated with the lookup table of this LookupTable. The resulted + * array is stored to the dst array. + * + * @param src + * the source array. + * @param dst + * the destination array where the result can be stored. + * @return the integer array of translated samples of a pixel. + */ + public abstract int[] lookupPixel(int[] src, int[] dst); +} diff --git a/awt/java/awt/image/MemoryImageSource.java b/awt/java/awt/image/MemoryImageSource.java new file mode 100644 index 0000000..644fd40 --- /dev/null +++ b/awt/java/awt/image/MemoryImageSource.java @@ -0,0 +1,603 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.util.Hashtable; +import java.util.Vector; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The MemoryImageSource class is used to produces pixels of an image from an + * array. This class can manage a memory image which contains an animation or + * custom rendering. + * + * @since Android 1.0 + */ +public class MemoryImageSource implements ImageProducer { + + /** + * The width. + */ + int width; + + /** + * The height. + */ + int height; + + /** + * The cm. + */ + ColorModel cm; + + /** + * The b data. + */ + byte bData[]; + + /** + * The i data. + */ + int iData[]; + + /** + * The offset. + */ + int offset; + + /** + * The scanline. + */ + int scanline; + + /** + * The properties. + */ + Hashtable<?, ?> properties; + + /** + * The consumers. + */ + Vector<ImageConsumer> consumers; + + /** + * The animated. + */ + boolean animated; + + /** + * The fullbuffers. + */ + boolean fullbuffers; + + /** + * The data type. + */ + int dataType; + + /** + * The Constant DATA_TYPE_BYTE. + */ + static final int DATA_TYPE_BYTE = 0; + + /** + * The Constant DATA_TYPE_INT. + */ + static final int DATA_TYPE_INT = 1; + + /** + * Instantiates a new MemoryImageSource with the specified parameters. + * + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param cm + * the specified ColorModel. + * @param pix + * the pixel array. + * @param off + * the offset in the pixel array. + * @param scan + * the distance from one pixel's row to the next in the pixel + * array. + * @param props + * the set of properties to be used for image processing. + */ + public MemoryImageSource(int w, int h, ColorModel cm, int pix[], int off, int scan, + Hashtable<?, ?> props) { + init(w, h, cm, pix, off, scan, props); + } + + /** + * Instantiates a new MemoryImageSource with the specified parameters. + * + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param cm + * the specified ColorModel. + * @param pix + * the pixel array. + * @param off + * the offset in the pixel array. + * @param scan + * the distance from one pixel's row to the next in the pixel + * array. + * @param props + * the set of properties to be used for image processing. + */ + public MemoryImageSource(int w, int h, ColorModel cm, byte pix[], int off, int scan, + Hashtable<?, ?> props) { + init(w, h, cm, pix, off, scan, props); + } + + /** + * Instantiates a new MemoryImageSource with the specified parameters and + * default RGB ColorModel. + * + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param pix + * the pixel array. + * @param off + * the offset in the pixel array. + * @param scan + * the distance from one pixel's row to the next in the pixel + * array. + * @param props + * the set of properties to be used for image processing. + */ + public MemoryImageSource(int w, int h, int pix[], int off, int scan, Hashtable<?, ?> props) { + init(w, h, ColorModel.getRGBdefault(), pix, off, scan, props); + } + + /** + * Instantiates a new MemoryImageSource with the specified parameters. + * + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param cm + * the specified ColorModel. + * @param pix + * the pixel array. + * @param off + * the offset in the pixel array. + * @param scan + * the distance from one pixel's row to the next in the pixel + * array. + */ + public MemoryImageSource(int w, int h, ColorModel cm, int pix[], int off, int scan) { + init(w, h, cm, pix, off, scan, null); + } + + /** + * Instantiates a new MemoryImageSource with the specified parameters. + * + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param cm + * the specified ColorModel. + * @param pix + * the pixel array. + * @param off + * the offset in the pixel array. + * @param scan + * the distance from one pixel's row to the next in the pixel + * array. + */ + public MemoryImageSource(int w, int h, ColorModel cm, byte pix[], int off, int scan) { + init(w, h, cm, pix, off, scan, null); + } + + /** + * Instantiates a new MemoryImageSource with the specified parameters and + * default RGB ColorModel. + * + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param pix + * the pixels array. + * @param off + * the offset in the pixel array. + * @param scan + * the distance from one pixel's row to the next in the pixel + * array. + */ + public MemoryImageSource(int w, int h, int pix[], int off, int scan) { + init(w, h, ColorModel.getRGBdefault(), pix, off, scan, null); + } + + public synchronized boolean isConsumer(ImageConsumer ic) { + return consumers.contains(ic); + } + + public void startProduction(ImageConsumer ic) { + if (!isConsumer(ic) && ic != null) { + consumers.addElement(ic); + } + try { + setHeader(ic); + setPixels(ic, 0, 0, width, height); + if (animated) { + ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE); + } else { + ic.imageComplete(ImageConsumer.STATICIMAGEDONE); + if (isConsumer(ic)) { + removeConsumer(ic); + } + } + } catch (Exception e) { + if (isConsumer(ic)) { + ic.imageComplete(ImageConsumer.IMAGEERROR); + } + if (isConsumer(ic)) { + removeConsumer(ic); + } + } + } + + public void requestTopDownLeftRightResend(ImageConsumer ic) { + } + + public synchronized void removeConsumer(ImageConsumer ic) { + consumers.removeElement(ic); + } + + public synchronized void addConsumer(ImageConsumer ic) { + if (ic == null || consumers.contains(ic)) { + return; + } + consumers.addElement(ic); + } + + /** + * Replaces the pixel data with a new pixel array for holding the pixels for + * this image. If an animation flag is set to true value by the + * setAnimated() method, the new pixels will be immediately delivered to the + * ImageConsumers. + * + * @param newpix + * the new pixel array. + * @param newmodel + * the new ColorModel. + * @param offset + * the offset in the array. + * @param scansize + * the distance from one row of pixels to the next row in the + * pixel array. + */ + public synchronized void newPixels(int newpix[], ColorModel newmodel, int offset, int scansize) { + this.dataType = DATA_TYPE_INT; + this.iData = newpix; + this.cm = newmodel; + this.offset = offset; + this.scanline = scansize; + newPixels(); + } + + /** + * Replaces the pixel data with a new pixel array for holding the pixels for + * this image. If an animation flag is set to true value by the + * setAnimated() method, the new pixels will be immediately delivered to the + * ImageConsumers. + * + * @param newpix + * the new pixel array. + * @param newmodel + * the new ColorModel. + * @param offset + * the offset in the array. + * @param scansize + * the distance from one row of pixels to the next row in the + * pixel array. + */ + public synchronized void newPixels(byte newpix[], ColorModel newmodel, int offset, int scansize) { + this.dataType = DATA_TYPE_BYTE; + this.bData = newpix; + this.cm = newmodel; + this.offset = offset; + this.scanline = scansize; + newPixels(); + } + + /** + * Sets the full buffer updates flag to true. If this is an animated image, + * the image consumers hints are updated accordingly. + * + * @param fullbuffers + * the true if the pixel buffer should be sent always. + */ + public synchronized void setFullBufferUpdates(boolean fullbuffers) { + if (this.fullbuffers == fullbuffers) { + return; + } + this.fullbuffers = fullbuffers; + if (animated) { + Object consAr[] = consumers.toArray(); + for (Object element : consAr) { + ImageConsumer con = (ImageConsumer)element; + try { + if (fullbuffers) { + con.setHints(ImageConsumer.TOPDOWNLEFTRIGHT + | ImageConsumer.COMPLETESCANLINES); + } else { + con.setHints(ImageConsumer.RANDOMPIXELORDER); + } + } catch (Exception e) { + if (isConsumer(con)) { + con.imageComplete(ImageConsumer.IMAGEERROR); + } + if (isConsumer(con)) { + removeConsumer(con); + } + } + } + } + } + + /** + * Sets the flag that tells whether this memory image has more than one + * frame (for animation): true for multiple frames, false if this class + * represents a single frame image. + * + * @param animated + * whether this image represents an animation. + */ + public synchronized void setAnimated(boolean animated) { + if (this.animated == animated) { + return; + } + Object consAr[] = consumers.toArray(); + for (Object element : consAr) { + ImageConsumer con = (ImageConsumer)element; + try { + con.imageComplete(ImageConsumer.STATICIMAGEDONE); + } catch (Exception e) { + if (isConsumer(con)) { + con.imageComplete(ImageConsumer.IMAGEERROR); + } + } + if (isConsumer(con)) { + removeConsumer(con); + } + } + this.animated = animated; + } + + /** + * Sends the specified rectangular area of the buffer to ImageConsumers and + * notifies them that an animation frame is completed only if the {@code + * framenotify} parameter is true. That works only if the animated flag has + * been set to true by the setAnimated() method. If the full buffer update + * flag has been set to true by the setFullBufferUpdates() method, then the + * entire buffer will always be sent ignoring parameters. + * + * @param x + * the X coordinate of the rectangular area. + * @param y + * the Y coordinate of the rectangular area. + * @param w + * the width of the rectangular area. + * @param h + * the height of the rectangular area. + * @param framenotify + * true if a SINGLEFRAMEDONE notification should be sent to the + * registered consumers, false otherwise. + */ + public synchronized void newPixels(int x, int y, int w, int h, boolean framenotify) { + if (animated) { + if (fullbuffers) { + x = 0; + y = 0; + w = width; + h = height; + } else { + if (x < 0) { + w += x; + x = 0; + } + if (w > width) { + w = width - x; + } + if (y < 0) { + h += y; + y = 0; + } + } + if (h > height) { + h = height - y; + } + Object consAr[] = consumers.toArray(); + for (Object element : consAr) { + ImageConsumer con = (ImageConsumer)element; + try { + if (w > 0 && h > 0) { + setPixels(con, x, y, w, h); + } + if (framenotify) { + con.imageComplete(ImageConsumer.SINGLEFRAMEDONE); + } + } catch (Exception ex) { + if (isConsumer(con)) { + con.imageComplete(ImageConsumer.IMAGEERROR); + } + if (isConsumer(con)) { + removeConsumer(con); + } + } + } + } + } + + /** + * Sends the specified rectangular area of the buffer to the ImageConsumers + * and notifies them that an animation frame is completed if the animated + * flag has been set to true by the setAnimated() method. If the full buffer + * update flag has been set to true by the setFullBufferUpdates() method, + * then the entire buffer will always be sent ignoring parameters. + * + * @param x + * the X coordinate of the rectangular area. + * @param y + * the Y coordinate of the rectangular area. + * @param w + * the width of the rectangular area. + * @param h + * the height of the rectangular area. + */ + public synchronized void newPixels(int x, int y, int w, int h) { + newPixels(x, y, w, h, true); + } + + /** + * Sends a new buffer of pixels to the ImageConsumers and notifies them that + * an animation frame is completed if the animated flag has been set to true + * by the setAnimated() method. + */ + public void newPixels() { + newPixels(0, 0, width, height, true); + } + + /** + * Inits the. + * + * @param width + * the width. + * @param height + * the height. + * @param model + * the model. + * @param pixels + * the pixels. + * @param off + * the off. + * @param scan + * the scan. + * @param prop + * the prop. + */ + private void init(int width, int height, ColorModel model, byte pixels[], int off, int scan, + Hashtable<?, ?> prop) { + + this.width = width; + this.height = height; + this.cm = model; + this.bData = pixels; + this.offset = off; + this.scanline = scan; + this.properties = prop; + this.dataType = DATA_TYPE_BYTE; + this.consumers = new Vector<ImageConsumer>(); + + } + + /** + * Inits the. + * + * @param width + * the width. + * @param height + * the height. + * @param model + * the model. + * @param pixels + * the pixels. + * @param off + * the off. + * @param scan + * the scan. + * @param prop + * the prop. + */ + private void init(int width, int height, ColorModel model, int pixels[], int off, int scan, + Hashtable<?, ?> prop) { + + this.width = width; + this.height = height; + this.cm = model; + this.iData = pixels; + this.offset = off; + this.scanline = scan; + this.properties = prop; + this.dataType = DATA_TYPE_INT; + this.consumers = new Vector<ImageConsumer>(); + } + + /** + * Sets the pixels. + * + * @param con + * the con. + * @param x + * the x. + * @param y + * the y. + * @param w + * the w. + * @param h + * the h. + */ + private void setPixels(ImageConsumer con, int x, int y, int w, int h) { + int pixelOff = scanline * y + offset + x; + + switch (dataType) { + case DATA_TYPE_BYTE: + con.setPixels(x, y, w, h, cm, bData, pixelOff, scanline); + break; + case DATA_TYPE_INT: + con.setPixels(x, y, w, h, cm, iData, pixelOff, scanline); + break; + default: + // awt.22A=Wrong type of pixels array + throw new IllegalArgumentException(Messages.getString("awt.22A")); //$NON-NLS-1$ + } + } + + /** + * Sets the header. + * + * @param con + * the new header. + */ + private synchronized void setHeader(ImageConsumer con) { + con.setDimensions(width, height); + con.setProperties(properties); + con.setColorModel(cm); + con + .setHints(animated ? (fullbuffers ? (ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES) + : ImageConsumer.RANDOMPIXELORDER) + : (ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES + | ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME)); + } + +} diff --git a/awt/java/awt/image/MultiPixelPackedSampleModel.java b/awt/java/awt/image/MultiPixelPackedSampleModel.java new file mode 100644 index 0000000..3dc13d8 --- /dev/null +++ b/awt/java/awt/image/MultiPixelPackedSampleModel.java @@ -0,0 +1,479 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The MultiPixelPackedSampleModel class represents image data with one band. + * This class packs multiple pixels with one sample in one data element and + * supports the following data types: DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT. + * + * @since Android 1.0 + */ +public class MultiPixelPackedSampleModel extends SampleModel { + + /** + * The pixel bit stride. + */ + private int pixelBitStride; + + /** + * The scanline stride. + */ + private int scanlineStride; + + /** + * The data bit offset. + */ + private int dataBitOffset; + + /** + * The bit mask. + */ + private int bitMask; + + /** + * The data element size. + */ + private int dataElementSize; + + /** + * The pixels per data element. + */ + private int pixelsPerDataElement; + + /** + * Instantiates a new MultiPixelPackedSampleModel with the specified + * parameters. + * + * @param dataType + * the data type of the samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param numberOfBits + * the number of bits per pixel. + * @param scanlineStride + * the scanline stride of the of the image data. + * @param dataBitOffset + * the array of the band offsets. + */ + public MultiPixelPackedSampleModel(int dataType, int w, int h, int numberOfBits, + int scanlineStride, int dataBitOffset) { + + super(dataType, w, h, 1); + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.61=Unsupported data type: {0} + throw new IllegalArgumentException(Messages.getString("awt.61", //$NON-NLS-1$ + dataType)); + } + + this.scanlineStride = scanlineStride; + if (numberOfBits == 0) { + // awt.20C=Number of Bits equals to zero + throw new RasterFormatException(Messages.getString("awt.20C")); //$NON-NLS-1$ + } + this.pixelBitStride = numberOfBits; + this.dataElementSize = DataBuffer.getDataTypeSize(dataType); + if (dataElementSize % pixelBitStride != 0) { + // awt.20D=The number of bits per pixel is not a power of 2 or + // pixels span data element boundaries + throw new RasterFormatException(Messages.getString("awt.20D")); //$NON-NLS-1$ + } + + if (dataBitOffset % numberOfBits != 0) { + // awt.20E=Data Bit offset is not a multiple of pixel bit stride + throw new RasterFormatException(Messages.getString("awt.20E")); //$NON-NLS-1$ + } + this.dataBitOffset = dataBitOffset; + + this.pixelsPerDataElement = dataElementSize / pixelBitStride; + this.bitMask = (1 << numberOfBits) - 1; + } + + /** + * Instantiates a new MultiPixelPackedSampleModel with the specified + * parameters. + * + * @param dataType + * the data type of the samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param numberOfBits + * the number of bits per pixel. + */ + public MultiPixelPackedSampleModel(int dataType, int w, int h, int numberOfBits) { + + this(dataType, w, h, numberOfBits, + (numberOfBits * w + DataBuffer.getDataTypeSize(dataType) - 1) + / DataBuffer.getDataTypeSize(dataType), 0); + } + + @Override + public Object getDataElements(int x, int y, Object obj, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + switch (getTransferType()) { + case DataBuffer.TYPE_BYTE: + byte bdata[]; + if (obj == null) { + bdata = new byte[1]; + } else { + bdata = (byte[])obj; + } + bdata[0] = (byte)getSample(x, y, 0, data); + obj = bdata; + break; + case DataBuffer.TYPE_USHORT: + short sdata[]; + if (obj == null) { + sdata = new short[1]; + } else { + sdata = (short[])obj; + } + sdata[0] = (short)getSample(x, y, 0, data); + obj = sdata; + break; + case DataBuffer.TYPE_INT: + int idata[]; + if (obj == null) { + idata = new int[1]; + } else { + idata = (int[])obj; + } + idata[0] = getSample(x, y, 0, data); + obj = idata; + break; + } + + return obj; + } + + @Override + public void setDataElements(int x, int y, Object obj, DataBuffer data) { + setSample(x, y, obj, data, 1, 0); + } + + /** + * Compares this MultiPixelPackedSampleModel object with the specified + * object. + * + * @param o + * the Object to be compared. + * @return true, if the object is a MultiPixelPackedSampleModel with the + * same data parameter values as this MultiPixelPackedSampleModel, + * false otherwise. + */ + @Override + public boolean equals(Object o) { + if ((o == null) || !(o instanceof MultiPixelPackedSampleModel)) { + return false; + } + + MultiPixelPackedSampleModel model = (MultiPixelPackedSampleModel)o; + return this.width == model.width && this.height == model.height + && this.numBands == model.numBands && this.dataType == model.dataType + && this.pixelBitStride == model.pixelBitStride && this.bitMask == model.bitMask + && this.pixelsPerDataElement == model.pixelsPerDataElement + && this.dataElementSize == model.dataElementSize + && this.dataBitOffset == model.dataBitOffset + && this.scanlineStride == model.scanlineStride; + } + + @Override + public SampleModel createSubsetSampleModel(int bands[]) { + if (bands != null && bands.length != 1) { + // awt.20F=Number of bands must be only 1 + throw new RasterFormatException(Messages.getString("awt.20F")); //$NON-NLS-1$ + } + return createCompatibleSampleModel(width, height); + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + return new MultiPixelPackedSampleModel(dataType, w, h, pixelBitStride); + } + + @Override + public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int pixel[]; + if (iArray == null) { + pixel = new int[numBands]; + } else { + pixel = iArray; + } + + pixel[0] = getSample(x, y, 0, data); + return pixel; + } + + @Override + public void setPixel(int x, int y, int iArray[], DataBuffer data) { + setSample(x, y, iArray, data, 2, 0); + } + + @Override + public int getSample(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height || b != 0) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + int bitnum = dataBitOffset + x * pixelBitStride; + int elem = data.getElem(y * scanlineStride + bitnum / dataElementSize); + int shift = dataElementSize - (bitnum & (dataElementSize - 1)) - pixelBitStride; + + return (elem >> shift) & bitMask; + } + + @Override + public void setSample(int x, int y, int b, int s, DataBuffer data) { + if (b != 0) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + setSample(x, y, null, data, 3, s); + } + + @Override + public DataBuffer createDataBuffer() { + DataBuffer dataBuffer = null; + int size = scanlineStride * height; + + switch (dataType) { + case DataBuffer.TYPE_BYTE: + dataBuffer = new DataBufferByte(size + (dataBitOffset + 7) / 8); + break; + case DataBuffer.TYPE_USHORT: + dataBuffer = new DataBufferUShort(size + (dataBitOffset + 15) / 16); + break; + case DataBuffer.TYPE_INT: + dataBuffer = new DataBufferInt(size + (dataBitOffset + 31) / 32); + break; + } + return dataBuffer; + } + + /** + * Gets the offset of the specified pixel in the data array. + * + * @param x + * the X coordinate of the specified pixel. + * @param y + * the Y coordinate of the specified pixel. + * @return the offset of the specified pixel. + */ + public int getOffset(int x, int y) { + return y * scanlineStride + (x * pixelBitStride + dataBitOffset) / dataElementSize; + } + + @Override + public int getSampleSize(int band) { + return pixelBitStride; + } + + /** + * Gets the bit offset in the data element which is stored for the specified + * pixel of a scanline. + * + * @param x + * the pixel. + * @return the bit offset of the pixel in the data element. + */ + public int getBitOffset(int x) { + return (x * pixelBitStride + dataBitOffset) % dataElementSize; + } + + @Override + public int[] getSampleSize() { + int sampleSizes[] = { + pixelBitStride + }; + return sampleSizes; + } + + /** + * Returns a hash code of this MultiPixelPackedSampleModel class. + * + * @return the hash code of this MultiPixelPackedSampleModel class. + */ + @Override + public int hashCode() { + int hash = 0; + int tmp = 0; + + hash = width; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= height; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= numBands; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= dataType; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= scanlineStride; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= pixelBitStride; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= dataBitOffset; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= bitMask; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= dataElementSize; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= pixelsPerDataElement; + return hash; + } + + @Override + public int getTransferType() { + if (pixelBitStride > 16) { + return DataBuffer.TYPE_INT; + } else if (pixelBitStride > 8) { + return DataBuffer.TYPE_USHORT; + } else { + return DataBuffer.TYPE_BYTE; + } + } + + /** + * Gets the scanline stride of this MultiPixelPackedSampleModel. + * + * @return the scanline stride of this MultiPixelPackedSampleModel. + */ + public int getScanlineStride() { + return scanlineStride; + } + + /** + * Gets the pixel bit stride of this MultiPixelPackedSampleModel. + * + * @return the pixel bit stride of this MultiPixelPackedSampleModel. + */ + public int getPixelBitStride() { + return pixelBitStride; + } + + @Override + public int getNumDataElements() { + return 1; + } + + /** + * Gets the data bit offset. + * + * @return the data bit offset. + */ + public int getDataBitOffset() { + return dataBitOffset; + } + + /** + * This method is used by other methods of this class. The behavior of this + * method depends on the method which has been invoke this one. The argument + * methodId is used to choose valid behavior in a particular case. If + * methodId is equal to 1 it means that this method has been invoked by the + * setDataElements() method, 2 - means setPixel(), and setSample() in any + * other cases. + * + * @param x + * the x. + * @param y + * the y. + * @param obj + * the obj. + * @param data + * the data. + * @param methodId + * the method id. + * @param s + * the s. + */ + private void setSample(final int x, final int y, final Object obj, final DataBuffer data, + final int methodId, int s) { + if ((x < 0) || (y < 0) || (x >= this.width) || (y >= this.height)) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + final int bitnum = dataBitOffset + x * pixelBitStride; + final int idx = y * scanlineStride + bitnum / dataElementSize; + final int shift = dataElementSize - (bitnum & (dataElementSize - 1)) - pixelBitStride; + final int mask = ~(bitMask << shift); + int elem = data.getElem(idx); + + switch (methodId) { + case 1: { // Invoked from setDataElements() + switch (getTransferType()) { + case DataBuffer.TYPE_BYTE: + s = ((byte[])obj)[0] & 0xff; + break; + case DataBuffer.TYPE_USHORT: + s = ((short[])obj)[0] & 0xffff; + break; + case DataBuffer.TYPE_INT: + s = ((int[])obj)[0]; + break; + } + break; + } + case 2: { // Invoked from setPixel() + s = ((int[])obj)[0]; + break; + } + } + + elem &= mask; + elem |= (s & bitMask) << shift; + data.setElem(idx, elem); + } +} diff --git a/awt/java/awt/image/PackedColorModel.java b/awt/java/awt/image/PackedColorModel.java new file mode 100644 index 0000000..4d1c2e5 --- /dev/null +++ b/awt/java/awt/image/PackedColorModel.java @@ -0,0 +1,402 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.util.Arrays; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The class PackedColorModel represents a color model where the components are + * just the red, green, and blue bands, plus an alpha band if alpha is + * supported. + * + * @since Android 1.0 + */ +public abstract class PackedColorModel extends ColorModel { + + /** + * The component masks. + */ + int componentMasks[]; + + /** + * The offsets. + */ + int offsets[]; + + /** + * The scales. + */ + float scales[]; + + /** + * Instantiates a new packed color model. + * + * @param space + * the color space. + * @param bits + * the array of component masks. + * @param colorMaskArray + * the array that gives the bitmask corresponding to each color + * band (red, green, and blue). + * @param alphaMask + * the bitmask corresponding to the alpha band. + * @param isAlphaPremultiplied + * whether the alpha is pre-multiplied in this color model. + * @param trans + * the transparency strategy, @see java.awt.Transparency. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + * @throws IllegalArgumentException + * if the number of bits in the combined bitmasks for the color + * bands is less than one or greater than 32. + */ + public PackedColorModel(ColorSpace space, int bits, int colorMaskArray[], int alphaMask, + boolean isAlphaPremultiplied, int trans, int transferType) { + + super(bits, createBits(colorMaskArray, alphaMask), space, (alphaMask == 0 ? false : true), + isAlphaPremultiplied, trans, validateTransferType(transferType)); + + if (pixel_bits < 1 || pixel_bits > 32) { + // awt.236=The bits is less than 1 or greater than 32 + throw new IllegalArgumentException(Messages.getString("awt.236")); //$NON-NLS-1$ + } + + componentMasks = new int[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + componentMasks[i] = colorMaskArray[i]; + } + + if (hasAlpha) { + componentMasks[numColorComponents] = alphaMask; + if (this.bits[numColorComponents] == 1) { + transparency = Transparency.BITMASK; + } + } + + parseComponents(); + } + + /** + * Instantiates a new packed color model. + * + * @param space + * the color space. + * @param bits + * the array of component masks. + * @param rmask + * the bitmask corresponding to the red band. + * @param gmask + * the bitmask corresponding to the green band. + * @param bmask + * the bitmask corresponding to the blue band. + * @param amask + * the bitmask corresponding to the alpha band. + * @param isAlphaPremultiplied + * whether the alpha is pre-multiplied in this color model. + * @param trans + * the transparency strategy, @see java.awt.Transparency. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + * @throws IllegalArgumentException + * if the number of bits in the combined bitmasks for the color + * bands is less than one or greater than 32. + */ + public PackedColorModel(ColorSpace space, int bits, int rmask, int gmask, int bmask, int amask, + boolean isAlphaPremultiplied, int trans, int transferType) { + + super(bits, createBits(rmask, gmask, bmask, amask), space, (amask == 0 ? false : true), + isAlphaPremultiplied, trans, validateTransferType(transferType)); + + if (pixel_bits < 1 || pixel_bits > 32) { + // awt.236=The bits is less than 1 or greater than 32 + throw new IllegalArgumentException(Messages.getString("awt.236")); //$NON-NLS-1$ + } + + if (cs.getType() != ColorSpace.TYPE_RGB) { + // awt.239=The space is not a TYPE_RGB space + throw new IllegalArgumentException(Messages.getString("awt.239")); //$NON-NLS-1$ + } + + for (int i = 0; i < numColorComponents; i++) { + if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) { + // awt.23A=The min/max normalized component values are not + // 0.0/1.0 + throw new IllegalArgumentException(Messages.getString("awt.23A")); //$NON-NLS-1$ + } + } + componentMasks = new int[numComponents]; + componentMasks[0] = rmask; + componentMasks[1] = gmask; + componentMasks[2] = bmask; + + if (hasAlpha) { + componentMasks[3] = amask; + if (this.bits[3] == 1) { + transparency = Transparency.BITMASK; + } + } + + parseComponents(); + } + + @Override + public WritableRaster getAlphaRaster(WritableRaster raster) { + if (!hasAlpha) { + return null; + } + + int x = raster.getMinX(); + int y = raster.getMinY(); + int w = raster.getWidth(); + int h = raster.getHeight(); + int band[] = new int[1]; + band[0] = raster.getNumBands() - 1; + return raster.createWritableChild(x, y, w, h, x, y, band); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (!(obj instanceof PackedColorModel)) { + return false; + } + PackedColorModel cm = (PackedColorModel)obj; + + return (pixel_bits == cm.getPixelSize() && transferType == cm.getTransferType() + && cs.getType() == cm.getColorSpace().getType() && hasAlpha == cm.hasAlpha() + && isAlphaPremultiplied == cm.isAlphaPremultiplied() + && transparency == cm.getTransparency() + && numColorComponents == cm.getNumColorComponents() + && numComponents == cm.getNumComponents() + && Arrays.equals(bits, cm.getComponentSize()) && Arrays.equals(componentMasks, cm + .getMasks())); + } + + @Override + public boolean isCompatibleSampleModel(SampleModel sm) { + if (sm == null) { + return false; + } + if (!(sm instanceof SinglePixelPackedSampleModel)) { + return false; + } + SinglePixelPackedSampleModel esm = (SinglePixelPackedSampleModel)sm; + + return ((esm.getNumBands() == numComponents) && (esm.getTransferType() == transferType) && Arrays + .equals(esm.getBitMasks(), componentMasks)); + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + return new SinglePixelPackedSampleModel(transferType, w, h, componentMasks); + } + + /** + * Gets the bitmask corresponding to the specified color component. + * + * @param index + * the index of the desired color. + * @return the mask. + */ + public final int getMask(int index) { + return componentMasks[index]; + } + + /** + * Gets the bitmasks of the components. + * + * @return the masks. + */ + public final int[] getMasks() { + return (componentMasks.clone()); + } + + /** + * Creates the bits. + * + * @param colorMaskArray + * the color mask array. + * @param alphaMask + * the alpha mask. + * @return the int[]. + */ + private static int[] createBits(int colorMaskArray[], int alphaMask) { + int bits[]; + int numComp; + if (alphaMask == 0) { + numComp = colorMaskArray.length; + } else { + numComp = colorMaskArray.length + 1; + } + + bits = new int[numComp]; + int i = 0; + for (; i < colorMaskArray.length; i++) { + bits[i] = countCompBits(colorMaskArray[i]); + if (bits[i] < 0) { + // awt.23B=The mask of the {0} component is not contiguous + throw new IllegalArgumentException(Messages.getString("awt.23B", i)); //$NON-NLS-1$ + } + } + + if (i < numComp) { + bits[i] = countCompBits(alphaMask); + + if (bits[i] < 0) { + // awt.23C=The mask of the alpha component is not contiguous + throw new IllegalArgumentException(Messages.getString("awt.23C")); //$NON-NLS-1$ + } + } + + return bits; + } + + /** + * Creates the bits. + * + * @param rmask + * the rmask. + * @param gmask + * the gmask. + * @param bmask + * the bmask. + * @param amask + * the amask. + * @return the int[]. + */ + private static int[] createBits(int rmask, int gmask, int bmask, int amask) { + + int numComp; + if (amask == 0) { + numComp = 3; + } else { + numComp = 4; + } + int bits[] = new int[numComp]; + + bits[0] = countCompBits(rmask); + if (bits[0] < 0) { + // awt.23D=The mask of the red component is not contiguous + throw new IllegalArgumentException(Messages.getString("awt.23D")); //$NON-NLS-1$ + } + + bits[1] = countCompBits(gmask); + if (bits[1] < 0) { + // awt.23E=The mask of the green component is not contiguous + throw new IllegalArgumentException(Messages.getString("awt.23E")); //$NON-NLS-1$ + } + + bits[2] = countCompBits(bmask); + if (bits[2] < 0) { + // awt.23F=The mask of the blue component is not contiguous + throw new IllegalArgumentException(Messages.getString("awt.23F")); //$NON-NLS-1$ + } + + if (amask != 0) { + bits[3] = countCompBits(amask); + if (bits[3] < 0) { + // awt.23C=The mask of the alpha component is not contiguous + throw new IllegalArgumentException(Messages.getString("awt.23C")); //$NON-NLS-1$ + } + } + + return bits; + } + + /** + * Count comp bits. + * + * @param compMask + * the comp mask. + * @return the int. + */ + private static int countCompBits(int compMask) { + int bits = 0; + if (compMask != 0) { + // Deleting final zeros + while ((compMask & 1) == 0) { + compMask >>>= 1; + } + // Counting component bits + while ((compMask & 1) == 1) { + compMask >>>= 1; + bits++; + } + } + + if (compMask != 0) { + return -1; + } + + return bits; + } + + /** + * Validate transfer type. + * + * @param transferType + * the transfer type. + * @return the int. + */ + private static int validateTransferType(int transferType) { + if (transferType != DataBuffer.TYPE_BYTE && transferType != DataBuffer.TYPE_USHORT + && transferType != DataBuffer.TYPE_INT) { + // awt.240=The transferType not is one of DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT or DataBuffer.TYPE_INT + throw new IllegalArgumentException(Messages.getString("awt.240")); //$NON-NLS-1$ + } + return transferType; + } + + /** + * Parses the components. + */ + private void parseComponents() { + offsets = new int[numComponents]; + scales = new float[numComponents]; + for (int i = 0; i < numComponents; i++) { + int off = 0; + int mask = componentMasks[i]; + while ((mask & 1) == 0) { + mask >>>= 1; + off++; + } + offsets[i] = off; + if (bits[i] == 0) { + scales[i] = 256.0f; // May be any value different from zero, + // because will dividing by zero + } else { + scales[i] = 255.0f / maxValues[i]; + } + } + + } + +} diff --git a/awt/java/awt/image/PixelGrabber.java b/awt/java/awt/image/PixelGrabber.java new file mode 100644 index 0000000..cecd5c8 --- /dev/null +++ b/awt/java/awt/image/PixelGrabber.java @@ -0,0 +1,408 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import java.awt.Image; +import java.util.Hashtable; + +import org.apache.harmony.awt.internal.nls.Messages; + +public class PixelGrabber implements ImageConsumer { + + int width; + int height; + int X; + int Y; + int offset; + int scanline; + ImageProducer producer; + + byte bData[]; + int iData[]; + ColorModel cm; + + private int grabberStatus; + private int dataType; + private boolean isGrabbing; + private boolean isRGB; + + + private static final int DATA_TYPE_BYTE = 0; + private static final int DATA_TYPE_INT = 1; + private static final int DATA_TYPE_UNDEFINED = 2; + + private static final int ALL_BITS = (ImageObserver.FRAMEBITS | + ImageObserver.ALLBITS); + + private static final int GRABBING_STOP = ALL_BITS | ImageObserver.ERROR; + + + + public PixelGrabber(ImageProducer ip, int x, int y, int w, int h, int[] pix, + int off, int scansize) { + initialize(ip, x, y, w, h, pix, off, scansize, true); + } + + public PixelGrabber(Image img, int x, int y, int w, int h, int[] pix, + int off, int scansize) { + initialize(img.getSource(), x, y, w, h, pix, off, scansize, true); + } + + public PixelGrabber(Image img, int x, int y, int w, int h, boolean forceRGB) { + initialize(img.getSource(), x, y, w, h, null, 0, 0, forceRGB); + } + + public void setProperties(Hashtable<?, ?> props) { + return; + } + + public synchronized Object getPixels() { + switch(dataType){ + case DATA_TYPE_BYTE: + return bData; + case DATA_TYPE_INT: + return iData; + default: + return null; + } + } + + public void setColorModel(ColorModel model) { + return; + } + + public void setPixels(int srcX, int srcY, int srcW, int srcH, + ColorModel model, byte[] pixels, int srcOff, int srcScan) { + if(srcY < Y){ + int delta = Y - srcY; + if(delta >= height) { + return; + } + srcY += delta; + srcH -= delta; + srcOff += srcScan * delta; + } + + if(srcY + srcH > Y + height){ + srcH = Y + height - srcY; + if(srcH <= 0) { + return; + } + } + + if(srcX < X){ + int delta = X - srcX; + if(delta >= width) { + return; + } + srcW -= delta; + srcX += delta; + srcOff += delta; + } + + if(srcX + srcW > X + width){ + srcW = X + width - srcX; + if(srcW <= 0) { + return; + } + } + if(scanline == 0) { + scanline = width; + } + int realOff = offset + (srcY - Y) * scanline + (srcX - X); + switch(dataType){ + case DATA_TYPE_UNDEFINED: + cm = model; + if(model != ColorModel.getRGBdefault()){ + bData = new byte[width * height]; + isRGB = false; + dataType = DATA_TYPE_BYTE; + }else{ + iData = new int[width * height]; + isRGB = true; + dataType = DATA_TYPE_INT; + } + case DATA_TYPE_BYTE: + if(!isRGB && cm == model){ + for(int y = 0; y < srcH; y++){ + System.arraycopy(pixels, srcOff, bData, realOff, srcW); + srcOff += srcScan; + realOff += scanline; + } + break; + } + forceToRGB(); + case DATA_TYPE_INT: + for(int y = 0; y < srcH; y++){ + for(int x = 0; x < srcW; x++){ + iData[realOff + x] = cm.getRGB(pixels[srcOff + x] & 0xff); + } + srcOff += srcScan; + realOff += scanline; + } + } + + return; + } + + public void setPixels(int srcX, int srcY, int srcW, int srcH, + ColorModel model, int[] pixels, int srcOff, int srcScan) { + + if(srcY < Y){ + int delta = Y - srcY; + if(delta >= height) { + return; + } + srcY += delta; + srcH -= delta; + srcOff += srcScan * delta; + } + + if(srcY + srcH > Y + height){ + srcH = Y + height - srcY; + if(srcH <= 0) { + return; + } + } + + if(srcX < X){ + int delta = X - srcX; + if(delta >= width) { + return; + } + srcW -= delta; + srcX += delta; + srcOff += delta; + } + + if(srcX + srcW > X + width){ + srcW = X + width - srcX; + if(srcW <= 0) { + return; + } + } + if(scanline == 0) { + scanline = width; + } + int realOff = offset + (srcY - Y) * scanline + (srcX - X); + + int mask = 0xFF; + + switch(dataType){ + case DATA_TYPE_UNDEFINED: + cm = model; + iData = new int[width * height]; + dataType = DATA_TYPE_INT; + isRGB = (cm == ColorModel.getRGBdefault()); + + case DATA_TYPE_INT: + if(cm == model){ + for(int y = 0; y < srcH; y++){ + System.arraycopy(pixels, srcOff, iData, realOff, srcW); + srcOff += srcScan; + realOff += scanline; + } + break; + } + mask = 0xFFFFFFFF; + + case DATA_TYPE_BYTE: + forceToRGB(); + for(int y = 0; y < srcH; y++){ + for(int x = 0; x < srcW; x++){ + iData[realOff+x] = cm.getRGB(pixels[srcOff+x] & mask); + } + srcOff += srcScan; + realOff += scanline; + } + } + } + + public synchronized ColorModel getColorModel() { + return cm; + } + + public synchronized boolean grabPixels(long ms) + throws InterruptedException { + if((grabberStatus & GRABBING_STOP) != 0){ + return ((grabberStatus & ALL_BITS) != 0); + } + + long start = System.currentTimeMillis(); + + if(!isGrabbing){ + isGrabbing = true; + grabberStatus &= ~ImageObserver.ABORT; + producer.startProduction(this); + } + while((grabberStatus & GRABBING_STOP) == 0){ + if(ms != 0){ + ms = start + ms - System.currentTimeMillis(); + if(ms <= 0) { + break; + } + } + wait(ms); + } + + return ((grabberStatus & ALL_BITS) != 0); + } + + public void setDimensions(int w, int h) { + if(width < 0) { + width = w - X; + } + if(height < 0) { + height = h - Y; + } + + grabberStatus |= ImageObserver.WIDTH | ImageObserver.HEIGHT; + + if(width <=0 || height <=0){ + imageComplete(STATICIMAGEDONE); + return; + } + + if(isRGB && dataType == DATA_TYPE_UNDEFINED){ + iData = new int[width * height]; + dataType = DATA_TYPE_INT; + scanline = width; + } + } + + public void setHints(int hints) { + return; + } + + public synchronized void imageComplete(int status) { + switch(status){ + case IMAGEABORTED: + grabberStatus |= ImageObserver.ABORT; + break; + case IMAGEERROR: + grabberStatus |= ImageObserver.ERROR | ImageObserver.ABORT; + break; + case SINGLEFRAMEDONE: + grabberStatus |= ImageObserver.FRAMEBITS; + break; + case STATICIMAGEDONE: + grabberStatus |= ImageObserver.ALLBITS; + break; + default: + // awt.26A=Incorrect ImageConsumer completion status + throw new IllegalArgumentException(Messages.getString("awt.26A")); //$NON-NLS-1$ + } + isGrabbing = false; + producer.removeConsumer(this); + notifyAll(); + } + + public boolean grabPixels() throws InterruptedException { + return grabPixels(0); + } + + public synchronized void startGrabbing() { + if((grabberStatus & GRABBING_STOP) != 0){ + return; + } + if(!isGrabbing){ + isGrabbing = true; + grabberStatus &= ~ImageObserver.ABORT; + producer.startProduction(this); + } + } + + public synchronized void abortGrabbing() { + imageComplete(IMAGEABORTED); + } + + public synchronized int status() { + return grabberStatus; + } + + public synchronized int getWidth() { + if(width < 0) { + return -1; + } + return width; + } + + public synchronized int getStatus() { + return grabberStatus; + } + + public synchronized int getHeight() { + if(height < 0) { + return -1; + } + return height; + } + + private void initialize(ImageProducer ip, int x, int y, int w, int h, + int pixels[], int off, int scansize, boolean forceRGB){ + + producer = ip; + X = x; + Y = y; + width = w; + height = h; + iData = pixels; + dataType = (pixels == null) ? DATA_TYPE_UNDEFINED : DATA_TYPE_INT; + offset = off; + scanline = scansize; + if(forceRGB){ + cm = ColorModel.getRGBdefault(); + isRGB = true; + } + } + + /** + * Force pixels to INT RGB mode + */ + private void forceToRGB(){ + if (isRGB) + return; + + switch(dataType){ + case DATA_TYPE_BYTE: + iData = new int[width * height]; + for(int i = 0; i < iData.length; i++){ + iData[i] = cm.getRGB(bData[i] & 0xff); + } + dataType = DATA_TYPE_INT; + bData = null; + break; + + case DATA_TYPE_INT: + int buff[] = new int[width * height]; + for(int i = 0; i < iData.length; i++){ + buff[i] = cm.getRGB(iData[i]); + } + iData = buff; + break; + } + offset = 0; + scanline = width; + cm = ColorModel.getRGBdefault(); + isRGB = true; + } + +} diff --git a/awt/java/awt/image/PixelInterleavedSampleModel.java b/awt/java/awt/image/PixelInterleavedSampleModel.java new file mode 100644 index 0000000..8e646f8 --- /dev/null +++ b/awt/java/awt/image/PixelInterleavedSampleModel.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The PixelInterleavedSampleModel class represents image data as represented as + * interleaved pixels and for which each sample of a pixel takes one data + * element of the DataBuffer. + * + * @since Android 1.0 + */ +public class PixelInterleavedSampleModel extends ComponentSampleModel { + + /** + * Instantiates a new PixelInterleavedSampleModel with the specified + * parameters. + * + * @param dataType + * the data type of the samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param pixelStride + * the pixel stride of the image data. + * @param scanlineStride + * the scanline stride of the of the image data. + * @param bandOffsets + * the array of the band offsets. + */ + public PixelInterleavedSampleModel(int dataType, int w, int h, int pixelStride, + int scanlineStride, int bandOffsets[]) { + + super(dataType, w, h, pixelStride, scanlineStride, bandOffsets); + + int maxOffset = bandOffsets[0]; + int minOffset = bandOffsets[0]; + for (int i = 1; i < bandOffsets.length; i++) { + if (bandOffsets[i] > maxOffset) { + maxOffset = bandOffsets[i]; + } + if (bandOffsets[i] < minOffset) { + minOffset = bandOffsets[i]; + } + } + + maxOffset -= minOffset; + + if (maxOffset > scanlineStride) { + // awt.241=Any offset between bands is greater than the Scanline + // stride + throw new IllegalArgumentException(Messages.getString("awt.241")); //$NON-NLS-1$ + } + + if (maxOffset > pixelStride) { + // awt.242=Pixel stride is less than any offset between bands + throw new IllegalArgumentException(Messages.getString("awt.242")); //$NON-NLS-1$ + } + + if (pixelStride * w > scanlineStride) { + // awt.243=Product of Pixel stride and w is greater than Scanline + // stride + throw new IllegalArgumentException(Messages.getString("awt.243")); //$NON-NLS-1$ + } + + } + + @Override + public SampleModel createSubsetSampleModel(int bands[]) { + int newOffsets[] = new int[bands.length]; + for (int i = 0; i < bands.length; i++) { + newOffsets[i] = bandOffsets[bands[i]]; + } + + return new PixelInterleavedSampleModel(dataType, width, height, pixelStride, + scanlineStride, newOffsets); + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + int newOffsets[]; + int minOffset = bandOffsets[0]; + + for (int i = 1; i < numBands; i++) { + if (bandOffsets[i] < minOffset) { + minOffset = bandOffsets[i]; + } + } + + if (minOffset > 0) { + newOffsets = new int[numBands]; + for (int i = 0; i < numBands; i++) { + newOffsets[i] = bandOffsets[i] - minOffset; + } + } else { + newOffsets = bandOffsets; + } + + return new PixelInterleavedSampleModel(dataType, w, h, pixelStride, pixelStride * w, + newOffsets); + } + + @Override + public int hashCode() { + int hash = super.hashCode(); + int tmp = hash >>> 8; + hash <<= 8; + hash |= tmp; + + return hash ^ 0x66; + } + +} diff --git a/awt/java/awt/image/RGBImageFilter.java b/awt/java/awt/image/RGBImageFilter.java new file mode 100644 index 0000000..f5fe5d9 --- /dev/null +++ b/awt/java/awt/image/RGBImageFilter.java @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +/** + * The RGBImageFilter class represents a filter which modifies pixels of an + * image in the default RGB ColorModel. + * + * @since Android 1.0 + */ +public abstract class RGBImageFilter extends ImageFilter { + + /** + * The original model is the ColorModel to be replaced by the new model when + * substituteColorModel is called. + */ + protected ColorModel origmodel; + + /** + * The new model is the ColorModel with which to replace the original model + * when substituteColorModel is called. + */ + protected ColorModel newmodel; + + /** + * The canFilterIndexColorModel indicates if it is acceptable to apply the + * color filtering of the filterRGB method to the color table entries of an + * IndexColorModel object. + */ + protected boolean canFilterIndexColorModel; + + /** + * Instantiates a new RGBImageFilter. + */ + public RGBImageFilter() { + } + + /** + * Filters an IndexColorModel object by calling filterRGB function for each + * entry of IndexColorModel. + * + * @param icm + * the IndexColorModel to be filtered. + * @return the IndexColorModel. + */ + public IndexColorModel filterIndexColorModel(IndexColorModel icm) { + int transferType = icm.getTransferType(); + int bits = icm.getPixelSize(); + int mapSize = icm.getMapSize(); + int colorMap[] = new int[mapSize]; + int filteredColorMap[] = new int[mapSize]; + icm.getRGBs(colorMap); + int trans = -1; + boolean hasAlpha = false; + for (int i = 0; i < mapSize; i++) { + filteredColorMap[i] = filterRGB(-1, -1, colorMap[i]); + int alpha = filteredColorMap[i] >>> 24; + if (alpha != 0xff) { + if (!hasAlpha) { + hasAlpha = true; + } + if (alpha == 0 && trans < 0) { + trans = i; + } + } + } + + return new IndexColorModel(bits, mapSize, filteredColorMap, 0, hasAlpha, trans, + transferType); + } + + /** + * Replaces the original color model and the new one. + * + * @param oldcm + * the old ColorModel. + * @param newcm + * the new ColorModel. + */ + public void substituteColorModel(ColorModel oldcm, ColorModel newcm) { + origmodel = oldcm; + newmodel = newcm; + } + + @Override + public void setColorModel(ColorModel model) { + if (model instanceof IndexColorModel && canFilterIndexColorModel) { + IndexColorModel icm = (IndexColorModel)model; + ColorModel filteredModel = filterIndexColorModel(icm); + substituteColorModel(model, filteredModel); + consumer.setColorModel(filteredModel); + } else { + consumer.setColorModel(ColorModel.getRGBdefault()); + } + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize) { + + if (model == null || model == origmodel) { + consumer.setPixels(x, y, w, h, newmodel, pixels, off, scansize); + } else { + int rgbPixels[] = new int[w]; + for (int sy = y, pixelsOff = off; sy < y + h; sy++, pixelsOff += scansize) { + + for (int sx = x, idx = 0; sx < x + w; sx++, idx++) { + rgbPixels[idx] = model.getRGB(pixels[pixelsOff + idx]); + } + filterRGBPixels(x, sy, w, 1, rgbPixels, 0, w); + } + } + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize) { + + if (model == null || model == origmodel) { + consumer.setPixels(x, y, w, h, newmodel, pixels, off, scansize); + } else { + int rgbPixels[] = new int[w]; + for (int sy = y, pixelsOff = off; sy < y + h; sy++, pixelsOff += scansize) { + + for (int sx = x, idx = 0; sx < x + w; sx++, idx++) { + rgbPixels[idx] = model.getRGB(pixels[pixelsOff + idx] & 0xff); + } + filterRGBPixels(x, sy, w, 1, rgbPixels, 0, w); + } + } + } + + /** + * Filters a region of pixels in the default RGB ColorModel by calling the + * filterRGB method for them. + * + * @param x + * the X coordinate of region. + * @param y + * the Y coordinate of region. + * @param w + * the width of region. + * @param h + * the height of region. + * @param pixels + * the pixels array. + * @param off + * the offset of array. + * @param scansize + * the distance between rows of pixels in the array. + */ + public void filterRGBPixels(int x, int y, int w, int h, int[] pixels, int off, int scansize) { + + for (int sy = y, lineOff = off; sy < y + h; sy++, lineOff += scansize) { + for (int sx = x, idx = 0; sx < x + w; sx++, idx++) { + pixels[lineOff + idx] = filterRGB(sx, sy, pixels[lineOff + idx]); + } + } + consumer.setPixels(x, y, w, h, ColorModel.getRGBdefault(), pixels, off, scansize); + } + + /** + * Converts a single input pixel in the default RGB ColorModel to a single + * output pixel. + * + * @param x + * the X pixel's coordinate. + * @param y + * the Y pixel's coordinate. + * @param rgb + * a pixel in the default RGB color model. + * @return a filtered pixel in the default RGB color model. + */ + public abstract int filterRGB(int x, int y, int rgb); + +} diff --git a/awt/java/awt/image/Raster.java b/awt/java/awt/image/Raster.java new file mode 100644 index 0000000..6749fde --- /dev/null +++ b/awt/java/awt/image/Raster.java @@ -0,0 +1,1515 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.Point; +import java.awt.Rectangle; + +import org.apache.harmony.awt.gl.image.OrdinaryWritableRaster; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Raster class represents a rectangular area of pixels. This class is + * defined by DataBuffer and SampleModel objects. The DataBuffer object stores + * sample values and DSampleModel defines the location of sample in this + * DataBuffer. + * + * @since Android 1.0 + */ +public class Raster { + + /** + * The DataBuffer of this Raster. + */ + protected DataBuffer dataBuffer; + + /** + * The height of this Raster. + */ + protected int height; + + /** + * The X coordinate of the upper left pixel in this Raster. + */ + protected int minX; + + /** + * The Y coordinate of the upper left pixel in this Raster. + */ + protected int minY; + + /** + * The number of bands in this Raster. + */ + protected int numBands; + + /** + * The number of data elements. + */ + protected int numDataElements; + + /** + * The parent of this Raster. + */ + protected Raster parent; + + /** + * The SampleModel of this Raster. + */ + protected SampleModel sampleModel; + + /** + * The X translation from the coordinate space of the SampleModel of this + * Raster. + */ + protected int sampleModelTranslateX; + + /** + * The Y translation from the coordinate space of the SampleModel of this + * Raster. + */ + protected int sampleModelTranslateY; + + /** + * The width of this Raster. + */ + protected int width; + + /** + * Creates a Raster object with a BandedSampleModel and the specified + * DataBuffer. The number of bands is defined by the length of bandOffsets + * or bankIndices arrays. + * + * @param dataBuffer + * the specified DataBuffer. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param bankIndices + * the bank indices of bands. + * @param bandOffsets + * the band offsets of bands. + * @param location + * the location which defines the upper left corner of Raster. + * @return the WritableRaster object. + */ + public static WritableRaster createBandedRaster(DataBuffer dataBuffer, int w, int h, + int scanlineStride, int bankIndices[], int bandOffsets[], Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (bankIndices == null || bandOffsets == null) { + // awt.277=bankIndices or bandOffsets is null + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.277")); //$NON-NLS-1$ + } + + if (dataBuffer == null) { + // awt.278=dataBuffer is null + throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$ + } + + int dataType = dataBuffer.getDataType(); + + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + BandedSampleModel sampleModel = new BandedSampleModel(dataType, w, h, scanlineStride, + bankIndices, bandOffsets); + + return new OrdinaryWritableRaster(sampleModel, dataBuffer, location); + } + + /** + * Creates a Raster object with a BandedSampleModel and the specified data + * type. The Data type can be one of the following values: TYPE_BYTE, + * TYPE_USHORT, or TYPE_INT. + * + * @param dataType + * the data type of the samples: TYPE_BYTE, TYPE_USHORT, or + * TYPE_INT. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param bankIndices + * the bank indices of bands. + * @param bandOffsets + * the band offsets of bands. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster object. + */ + public static WritableRaster createBandedRaster(int dataType, int w, int h, int scanlineStride, + int bankIndices[], int bandOffsets[], Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (bankIndices == null || bandOffsets == null) { + // awt.277=bankIndices or bandOffsets is null + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.277")); //$NON-NLS-1$ + } + + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + int maxOffset = bandOffsets[0]; + int maxBank = bankIndices[0]; + + for (int i = 0; i < bankIndices.length; i++) { + if (bandOffsets[i] > maxOffset) { + maxOffset = bandOffsets[i]; + } + if (bankIndices[i] > maxBank) { + maxBank = bankIndices[i]; + } + } + + int numBanks = maxBank + 1; + int dataSize = scanlineStride * (h - 1) + w + maxOffset; + + DataBuffer data = null; + + switch (dataType) { + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(dataSize, numBanks); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(dataSize, numBanks); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(dataSize, numBanks); + break; + } + return createBandedRaster(data, w, h, scanlineStride, bankIndices, bandOffsets, location); + } + + /** + * Creates a Raster object with a BandedSampleModel and the specified data + * type. The Data type can be one of the following values: TYPE_BYTE, + * TYPE_USHORT, or TYPE_INT. + * + * @param dataType + * the data type of the samples: TYPE_BYTE, TYPE_USHORT, or + * TYPE_INT. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param bands + * the number of bands. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster object. + */ + public static WritableRaster createBandedRaster(int dataType, int w, int h, int bands, + Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (bands < 1) { + // awt.279=bands is less than 1 + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.279")); //$NON-NLS-1$ + } + + int bandOffsets[] = new int[bands]; + int bankIndices[] = new int[bands]; + + for (int i = 0; i < bands; i++) { + bandOffsets[i] = 0; + bankIndices[i] = i; + } + return createBandedRaster(dataType, w, h, w, bankIndices, bandOffsets, location); + } + + /** + * Creates a Raster object with a PixelInterleavedSampleModel and the + * specified DataBuffer. + * + * @param dataBuffer + * the DataBuffer. + * @param w + * the width of image data. + * @param h + * the height of image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param pixelStride + * the pixel stride of image data. + * @param bandOffsets + * the band offsets of bands. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster object. + */ + public static WritableRaster createInterleavedRaster(DataBuffer dataBuffer, int w, int h, + int scanlineStride, int pixelStride, int bandOffsets[], Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (dataBuffer == null) { + // awt.278=dataBuffer is null + throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$ + } + + int dataType = dataBuffer.getDataType(); + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + if (dataBuffer.getNumBanks() > 1) { + // awt.27A=dataBuffer has more than one bank + throw new RasterFormatException(Messages.getString("awt.27A")); //$NON-NLS-1$ + } + + if (bandOffsets == null) { + // awt.27B=bandOffsets is null + throw new NullPointerException(Messages.getString("awt.27B")); //$NON-NLS-1$ + } + + PixelInterleavedSampleModel sampleModel = new PixelInterleavedSampleModel(dataType, w, h, + pixelStride, scanlineStride, bandOffsets); + + return new OrdinaryWritableRaster(sampleModel, dataBuffer, location); + + } + + /** + * Creates a Raster object with a PixelInterleavedSampleModel and the + * specified data type. The Data type can be one of the following values: + * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * + * @param dataType + * the data type of the samples: TYPE_BYTE, TYPE_USHORT, or + * TYPE_INT. + * @param w + * the width of image data. + * @param h + * the height of image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param pixelStride + * the pixel stride of image data. + * @param bandOffsets + * the band offsets of bands. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster object. + */ + public static WritableRaster createInterleavedRaster(int dataType, int w, int h, + int scanlineStride, int pixelStride, int bandOffsets[], Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + if (bandOffsets == null) { + // awt.27B=bandOffsets is null + throw new NullPointerException(Messages.getString("awt.27B")); //$NON-NLS-1$ + } + + int minOffset = bandOffsets[0]; + for (int i = 1; i < bandOffsets.length; i++) { + if (bandOffsets[i] < minOffset) { + minOffset = bandOffsets[i]; + } + } + int size = (h - 1) * scanlineStride + w * pixelStride + minOffset; + DataBuffer data = null; + + switch (dataType) { + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(size); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(size); + break; + } + + return createInterleavedRaster(data, w, h, scanlineStride, pixelStride, bandOffsets, + location); + } + + /** + * Creates a Raster object with a PixelInterleavedSampleModel and the + * specified data type. The Data type can be one of the following values: + * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * + * @param dataType + * the data type of samples: TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * @param w + * the width of image data. + * @param h + * the height of image data. + * @param bands + * the number of bands. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster. + */ + public static WritableRaster createInterleavedRaster(int dataType, int w, int h, int bands, + Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + int bandOffsets[] = new int[bands]; + for (int i = 0; i < bands; i++) { + bandOffsets[i] = i; + } + + return createInterleavedRaster(dataType, w, h, w * bands, bands, bandOffsets, location); + } + + /** + * Creates a Raster object with a SinglePixelPackedSampleModel and the + * specified DataBuffer. + * + * @param dataBuffer + * the DataBuffer. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param bandMasks + * the band masks. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster. + */ + public static WritableRaster createPackedRaster(DataBuffer dataBuffer, int w, int h, + int scanlineStride, int bandMasks[], Point location) { + if (dataBuffer == null) { + // awt.278=dataBuffer is null + throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$ + } + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (bandMasks == null) { + // awt.27C=bandMasks is null + throw new RasterFormatException(Messages.getString("awt.27C")); //$NON-NLS-1$ + } + + if (dataBuffer.getNumBanks() > 1) { + // awt.27A=dataBuffer has more than one bank + throw new RasterFormatException(Messages.getString("awt.27A")); //$NON-NLS-1$ + } + + int dataType = dataBuffer.getDataType(); + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + SinglePixelPackedSampleModel sampleModel = new SinglePixelPackedSampleModel(dataType, w, h, + scanlineStride, bandMasks); + + return new OrdinaryWritableRaster(sampleModel, dataBuffer, location); + } + + /** + * Creates a Raster object with a MultiPixelPackedSampleModel and the + * specified DataBuffer. + * + * @param dataBuffer + * the DataBuffer. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param bitsPerPixel + * the number of bits per pixel. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster. + */ + public static WritableRaster createPackedRaster(DataBuffer dataBuffer, int w, int h, + int bitsPerPixel, Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (dataBuffer == null) { + // awt.278=dataBuffer is null + throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$ + } + + if (dataBuffer.getNumBanks() > 1) { + // awt.27A=dataBuffer has more than one bank + throw new RasterFormatException(Messages.getString("awt.27A")); //$NON-NLS-1$ + } + + int dataType = dataBuffer.getDataType(); + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + MultiPixelPackedSampleModel sampleModel = new MultiPixelPackedSampleModel(dataType, w, h, + bitsPerPixel); + + return new OrdinaryWritableRaster(sampleModel, dataBuffer, location); + + } + + /** + * Creates a Raster object with a MultiPixelPackedSampleModel and the + * specified DataBuffer. + * + * @param dataType + * the data type of samples: TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param bands + * the number of bands. + * @param bitsPerBand + * the number of bits per band. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster. + */ + public static WritableRaster createPackedRaster(int dataType, int w, int h, int bands, + int bitsPerBand, Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (bands < 1 || bitsPerBand < 1) { + // awt.27D=bitsPerBand or bands is not greater than zero + throw new IllegalArgumentException(Messages.getString("awt.27D")); //$NON-NLS-1$ + } + + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + if (bitsPerBand * bands > DataBuffer.getDataTypeSize(dataType)) { + // awt.27E=The product of bitsPerBand and bands is greater than the + // number of bits held by dataType + throw new IllegalArgumentException(Messages.getString("awt.27E")); //$NON-NLS-1$ + } + + if (bands > 1) { + + int bandMasks[] = new int[bands]; + int mask = (1 << bitsPerBand) - 1; + + for (int i = 0; i < bands; i++) { + bandMasks[i] = mask << (bitsPerBand * (bands - 1 - i)); + } + + return createPackedRaster(dataType, w, h, bandMasks, location); + } + DataBuffer data = null; + int size = ((bitsPerBand * w + DataBuffer.getDataTypeSize(dataType) - 1) / DataBuffer + .getDataTypeSize(dataType)) + * h; + + switch (dataType) { + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(size); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(size); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(size); + break; + } + return createPackedRaster(data, w, h, bitsPerBand, location); + } + + /** + * Creates a Raster object with a SinglePixelPackedSampleModel and the + * specified DataBuffer. + * + * @param dataType + * the data type of samples: TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param bandMasks + * the band masks. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster. + */ + public static WritableRaster createPackedRaster(int dataType, int w, int h, int bandMasks[], + Point location) { + + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (bandMasks == null) { + // awt.27C=bandMasks is null + throw new NullPointerException(Messages.getString("awt.27C")); //$NON-NLS-1$ + } + + DataBuffer data = null; + + switch (dataType) { + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(w * h); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(w * h); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(w * h); + break; + } + + return createPackedRaster(data, w, h, w, bandMasks, location); + } + + /** + * Creates a Raster object with the specified DataBuffer and SampleModel. + * + * @param sm + * the specified SampleModel. + * @param db + * the specified DataBuffer. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the Raster. + */ + public static Raster createRaster(SampleModel sm, DataBuffer db, Point location) { + + if (sm == null || db == null) { + // awt.27F=SampleModel or DataBuffer is null + throw new NullPointerException(Messages.getString("awt.27F")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + return new Raster(sm, db, location); + } + + /** + * Creates a WritableRaster with the specified SampleModel and DataBuffer. + * + * @param sm + * the specified SampleModel. + * @param db + * the specified DataBuffer. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster. + */ + public static WritableRaster createWritableRaster(SampleModel sm, DataBuffer db, Point location) { + + if (sm == null || db == null) { + // awt.27F=SampleModel or DataBuffer is null + throw new NullPointerException(Messages.getString("awt.27F")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + return new OrdinaryWritableRaster(sm, db, location); + } + + /** + * Creates a WritableRaster with the specified SampleModel. + * + * @param sm + * the specified SampleModel. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster. + */ + public static WritableRaster createWritableRaster(SampleModel sm, Point location) { + + if (sm == null) { + // awt.280=SampleModel is null + throw new NullPointerException(Messages.getString("awt.280")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + return createWritableRaster(sm, sm.createDataBuffer(), location); + } + + /** + * Instantiates a new Raster object with the specified SampleModel and + * DataBuffer. + * + * @param sampleModel + * the specified SampleModel. + * @param dataBuffer + * the specified DataBuffer. + * @param origin + * the specified origin. + */ + protected Raster(SampleModel sampleModel, DataBuffer dataBuffer, Point origin) { + + this(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y, sampleModel.getWidth(), + sampleModel.getHeight()), origin, null); + } + + /** + * Instantiates a new Raster object with the specified SampleModel, + * DataBuffer, rectangular region and parent Raster. + * + * @param sampleModel + * the specified SampleModel. + * @param dataBuffer + * the specified DataBuffer. + * @param aRegion + * the a rectangular region which defines the new image bounds. + * @param sampleModelTranslate + * this point defines the translation point from the SampleModel + * coordinates to the new Raster coordinates. + * @param parent + * the parent of this Raster. + */ + protected Raster(SampleModel sampleModel, DataBuffer dataBuffer, Rectangle aRegion, + Point sampleModelTranslate, Raster parent) { + + if (sampleModel == null || dataBuffer == null || aRegion == null + || sampleModelTranslate == null) { + // awt.281=sampleModel, dataBuffer, aRegion or sampleModelTranslate + // is null + throw new NullPointerException(Messages.getString("awt.281")); //$NON-NLS-1$ + } + + if (aRegion.width <= 0 || aRegion.height <= 0) { + // awt.282=aRegion has width or height less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.282")); //$NON-NLS-1$ + } + + if ((long)aRegion.x + (long)aRegion.width > Integer.MAX_VALUE) { + // awt.283=Overflow X coordinate of Raster + throw new RasterFormatException(Messages.getString("awt.283")); //$NON-NLS-1$ + } + + if ((long)aRegion.y + (long)aRegion.height > Integer.MAX_VALUE) { + // awt.284=Overflow Y coordinate of Raster + throw new RasterFormatException(Messages.getString("awt.284")); //$NON-NLS-1$ + } + + if (sampleModel instanceof ComponentSampleModel) { + validateDataBuffer(dataBuffer, aRegion.width, aRegion.height, + ((ComponentSampleModel)sampleModel).getScanlineStride()); + } else if (sampleModel instanceof MultiPixelPackedSampleModel) { + validateDataBuffer(dataBuffer, aRegion.width, aRegion.height, + ((MultiPixelPackedSampleModel)sampleModel).getScanlineStride()); + } else if (sampleModel instanceof SinglePixelPackedSampleModel) { + validateDataBuffer(dataBuffer, aRegion.width, aRegion.height, + ((SinglePixelPackedSampleModel)sampleModel).getScanlineStride()); + } + + this.sampleModel = sampleModel; + this.dataBuffer = dataBuffer; + this.minX = aRegion.x; + this.minY = aRegion.y; + this.width = aRegion.width; + this.height = aRegion.height; + this.sampleModelTranslateX = sampleModelTranslate.x; + this.sampleModelTranslateY = sampleModelTranslate.y; + this.parent = parent; + this.numBands = sampleModel.getNumBands(); + this.numDataElements = sampleModel.getNumDataElements(); + + } + + /** + * Instantiates a new Raster with the specified SampleModel. + * + * @param sampleModel + * the specified SampleModel. + * @param origin + * the origin. + */ + protected Raster(SampleModel sampleModel, Point origin) { + this(sampleModel, sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, + sampleModel.getWidth(), sampleModel.getHeight()), origin, null); + } + + /** + * Creates the child of this Raster by sharing the specified rectangular + * area in this raster. The parentX, parentY, width and height parameters + * specify the rectangular area to be shared. + * + * @param parentX + * the X coordinate of the upper left corner of this Raster. + * @param parentY + * the Y coordinate of the upper left corner of this Raster. + * @param width + * the width of the child area. + * @param height + * the height of the child area. + * @param childMinX + * the X coordinate of child area mapped to the parentX + * coordinate. + * @param childMinY + * the Y coordinate of child area mapped to the parentY + * coordinate. + * @param bandList + * the array of band indices. + * @return the Raster. + */ + public Raster createChild(int parentX, int parentY, int width, int height, int childMinX, + int childMinY, int bandList[]) { + if (width <= 0 || height <= 0) { + // awt.285=Width or Height of child Raster is less than or equal to + // zero + throw new RasterFormatException(Messages.getString("awt.285")); //$NON-NLS-1$ + } + + if (parentX < this.minX || parentX + width > this.minX + this.width) { + // awt.286=parentX disposes outside Raster + throw new RasterFormatException(Messages.getString("awt.286")); //$NON-NLS-1$ + } + + if (parentY < this.minY || parentY + height > this.minY + this.height) { + // awt.287=parentY disposes outside Raster + throw new RasterFormatException(Messages.getString("awt.287")); //$NON-NLS-1$ + } + + if ((long)parentX + width > Integer.MAX_VALUE) { + // awt.288=parentX + width results in integer overflow + throw new RasterFormatException(Messages.getString("awt.288")); //$NON-NLS-1$ + } + + if ((long)parentY + height > Integer.MAX_VALUE) { + // awt.289=parentY + height results in integer overflow + throw new RasterFormatException(Messages.getString("awt.289")); //$NON-NLS-1$ + } + + if ((long)childMinX + width > Integer.MAX_VALUE) { + // awt.28A=childMinX + width results in integer overflow + throw new RasterFormatException(Messages.getString("awt.28A")); //$NON-NLS-1$ + } + + if ((long)childMinY + height > Integer.MAX_VALUE) { + // awt.28B=childMinY + height results in integer overflow + throw new RasterFormatException(Messages.getString("awt.28B")); //$NON-NLS-1$ + } + + SampleModel childModel; + + if (bandList == null) { + childModel = sampleModel; + } else { + childModel = sampleModel.createSubsetSampleModel(bandList); + } + + int childTranslateX = childMinX - parentX; + int childTranslateY = childMinY - parentY; + + return new Raster(childModel, dataBuffer, + new Rectangle(childMinX, childMinY, width, height), new Point(childTranslateX + + sampleModelTranslateX, childTranslateY + sampleModelTranslateY), this); + } + + /** + * Create a compatible WritableRaster with the same parameters as this + * Raster. + * + * @return the WritableRaster. + */ + public WritableRaster createCompatibleWritableRaster() { + return new OrdinaryWritableRaster(sampleModel, new Point(0, 0)); + } + + /** + * Create a compatible WritableRaster with the same parameters as this + * Raster and the specified size. + * + * @param w + * the width of the new WritableRaster. + * @param h + * the height of the new WritableRaster. + * @return the WritableRaster. + */ + public WritableRaster createCompatibleWritableRaster(int w, int h) { + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + SampleModel sm = sampleModel.createCompatibleSampleModel(w, h); + + return new OrdinaryWritableRaster(sm, new Point(0, 0)); + } + + /** + * Create a compatible WritableRaster with the same parameters as this + * Raster and the specified size and location. + * + * @param x + * the X coordinate of the new WritableRaster. + * @param y + * the Y coordinate of the new WritableRaster. + * @param w + * the width of the new WritableRaster. + * @param h + * the height of the new WritableRaster. + * @return the WritableRaster. + */ + public WritableRaster createCompatibleWritableRaster(int x, int y, int w, int h) { + + WritableRaster raster = createCompatibleWritableRaster(w, h); + + return raster.createWritableChild(0, 0, w, h, x, y, null); + } + + /** + * Create a compatible WritableRaster with the same parameters as this + * Raster and the specified rectangle which determines new WritableRaster's + * location and size. + * + * @param rect + * the specified Rectangle. + * @return the WritableRaster. + */ + public WritableRaster createCompatibleWritableRaster(Rectangle rect) { + if (rect == null) { + // awt.28C=Rect is null + throw new NullPointerException(Messages.getString("awt.28C")); //$NON-NLS-1$ + } + + return createCompatibleWritableRaster(rect.x, rect.y, rect.width, rect.height); + } + + /** + * Creates the translated child of this Raster. The New Raster object is a + * reference to the this Raster with a different location. + * + * @param childMinX + * the X coordinate of the new Raster. + * @param childMinY + * the Y coordinate of the new Raster. + * @return the Raster. + */ + public Raster createTranslatedChild(int childMinX, int childMinY) { + return createChild(minX, minY, width, height, childMinX, childMinY, null); + } + + /** + * Gets the bounds of this Raster as a rectangle. + * + * @return the bounds of this Raster. + */ + public Rectangle getBounds() { + return new Rectangle(minX, minY, width, height); + } + + /** + * Gets the DataBuffer associated with this Raster. + * + * @return the DataBuffer associated with this Raster. + */ + public DataBuffer getDataBuffer() { + return dataBuffer; + } + + /** + * Gets the data elements which represent the pixel data of the specified + * rectangle area as a primitive array. The following image data types are + * supported: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or + * DataBuffer.TYPE_DOUBLE. + * + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of the area of pixels. + * @param h + * the height of the area of pixels. + * @param outData + * the resulting array. + * @return the data elements of the specified area of this Raster. + */ + public Object getDataElements(int x, int y, int w, int h, Object outData) { + return sampleModel.getDataElements(x - sampleModelTranslateX, y - sampleModelTranslateY, w, + h, outData, dataBuffer); + } + + /** + * Gets the data elements which represent the specified pixel of this Raster + * as a primitive array. The following image data types are supported: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, + * DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param outData + * the resulting data. + * @return the data elements of the specified pixel of this Raster. + */ + public Object getDataElements(int x, int y, Object outData) { + return sampleModel.getDataElements(x - sampleModelTranslateX, y - sampleModelTranslateY, + outData, dataBuffer); + } + + /** + * Gets the height of this Raster. + * + * @return the height of this Raster. + */ + public final int getHeight() { + return height; + } + + /** + * Gets the minimum X coordinate of this Raster. + * + * @return the minimum X coordinate of this Raster. + */ + public final int getMinX() { + return minX; + } + + /** + * Gets the minimum Y coordinate of this Raster. + * + * @return the minimum Y coordinate of this Raster. + */ + public final int getMinY() { + return minY; + } + + /** + * Gets the number of bands in this Raster. + * + * @return the number of bands in this Raster. + */ + public final int getNumBands() { + return numBands; + } + + /** + * Gets the number of data elements for one pixel. + * + * @return the number of data elements for one pixel. + */ + public final int getNumDataElements() { + return numDataElements; + } + + /** + * Gets the parent Raster for this Raster object. + * + * @return the parent Raster for this Raster object. + */ + public Raster getParent() { + return parent; + } + + /** + * Gets a double array of samples for the specified pixel in this Raster. + * + * @param x + * the pixel's X coordinate. + * @param y + * the pixel's Y coordinate. + * @param dArray + * the double array where result array will be stored. + * @return the double array of samples for the specified pixel in this + * Raster. + */ + public double[] getPixel(int x, int y, double dArray[]) { + return sampleModel.getPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, dArray, + dataBuffer); + } + + /** + * Gets a float array of samples for the specified pixel in this Raster. + * + * @param x + * the pixel's X coordinate. + * @param y + * the pixel's Y coordinate. + * @param fArray + * the float array where the result array will be stored. + * @return the float array of samples for the specified pixel in this + * Raster. + */ + public float[] getPixel(int x, int y, float fArray[]) { + return sampleModel.getPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, fArray, + dataBuffer); + } + + /** + * Gets an integer array of samples for the specified pixel in this Raster. + * + * @param x + * the pixel's X coordinate. + * @param y + * the pixel's Y coordinate. + * @param iArray + * the integer array where the result array will be stored. + * @return the integer array of samples for the specified pixel in this + * Raster. + */ + public int[] getPixel(int x, int y, int iArray[]) { + return sampleModel.getPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, iArray, + dataBuffer); + } + + /** + * Gets an double array of samples for the specified rectangular area of + * pixels in this Raster. + * + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of the area of pixels. + * @param h + * the height of the area of pixels. + * @param dArray + * the resulting array. + * @return the double array of samples for the specified rectangular area of + * pixels in this Raster. + */ + public double[] getPixels(int x, int y, int w, int h, double dArray[]) { + return sampleModel.getPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + dArray, dataBuffer); + } + + /** + * Gets an float array of samples for the specified rectangular area of + * pixels in this Raster. + * + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of the area of pixels. + * @param h + * the height of the area of pixels. + * @param fArray + * the resulting array. + * @return the float array of samples for the specified rectangular area of + * pixels in this Raster. + */ + public float[] getPixels(int x, int y, int w, int h, float fArray[]) { + return sampleModel.getPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + fArray, dataBuffer); + } + + /** + * Gets an integer array of samples for the specified rectangular area of + * pixels in this raster. + * + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of pixel's the area of pixels. + * @param h + * the height of pixel's the area of pixels. + * @param iArray + * the resulting array. + * @return the integer array of samples for the specified rectangular area + * of pixels in this Raster. + */ + public int[] getPixels(int x, int y, int w, int h, int iArray[]) { + return sampleModel.getPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + iArray, dataBuffer); + } + + /** + * Gets the sample for the specified band of the specified pixel as an + * integer. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the band. + * @return the sample for the specified band of the specified pixel as an + * integer. + */ + public int getSample(int x, int y, int b) { + return sampleModel.getSample(x - sampleModelTranslateX, y - sampleModelTranslateY, b, + dataBuffer); + } + + /** + * Gets the sample for the specified band of the specified pixel as a + * double. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the band. + * @return the sample for the specified band of the specified pixel as a + * double. + */ + public double getSampleDouble(int x, int y, int b) { + return sampleModel.getSampleDouble(x - sampleModelTranslateX, y - sampleModelTranslateY, b, + dataBuffer); + } + + /** + * Gets the sample for the specified band of the specified pixel as a float. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the band. + * @return the sample for the specified band of the specified pixel as a + * float. + */ + public float getSampleFloat(int x, int y, int b) { + return sampleModel.getSampleFloat(x - sampleModelTranslateX, y - sampleModelTranslateY, b, + dataBuffer); + } + + /** + * Gets the SampleModel associated with this Raster. + * + * @return the SampleModel associated with this Raster. + */ + public SampleModel getSampleModel() { + return sampleModel; + } + + /** + * Gets the translation of the X coordinate from the SampleModel coordinate + * system to the Rasters's coordinate system. + * + * @return the value of the translation of the X coordinate from the + * SampleModel coordinate system to the Rasters's coordinate system. + */ + public final int getSampleModelTranslateX() { + return sampleModelTranslateX; + } + + /** + * Gets the translation of the Y coordinate from the SampleModel coordinate + * system to the Rasters's coordinate system. + * + * @return the value of the translation of the Y coordinate from the + * SampleModel coordinate system to the Rasters's coordinate system. + */ + public final int getSampleModelTranslateY() { + return sampleModelTranslateY; + } + + /** + * Gets the double array of samples for the specified band of the specified + * rectangular area of pixels in this Raster as a double array. + * + * @param x + * the X coordinate of the rectangular area of pixels. + * @param y + * the Y coordinate of the rectangular area of pixels. + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param b + * the band. + * @param dArray + * the resulting double array. + * @return the double array of samples for the specified band of the + * specified rectangular area of pixels. + */ + public double[] getSamples(int x, int y, int w, int h, int b, double dArray[]) { + + return sampleModel.getSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + b, dArray, dataBuffer); + } + + /** + * Gets the float array of samples for the specified band of the specified + * rectangular area of pixels in this Raster as a float array. + * + * @param x + * the X coordinate of the rectangular area of pixels. + * @param y + * the Y coordinate of the rectangular area of pixels. + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param b + * the band. + * @param fArray + * the resulting float array. + * @return the float array of samples for the specified band of the + * specified rectangular area of pixels. + */ + public float[] getSamples(int x, int y, int w, int h, int b, float fArray[]) { + + return sampleModel.getSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + b, fArray, dataBuffer); + } + + /** + * Gets the integer array of samples for the specified band of the specified + * rectangular area of pixels in this Raster as a integer array. + * + * @param x + * the X coordinate of the rectangular area of pixels. + * @param y + * the Y coordinate of the rectangular area of pixels. + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param b + * the band. + * @param iArray + * the resulting integer array. + * @return the integer array of samples for the specified band of the + * specified rectangular area of pixels. + */ + public int[] getSamples(int x, int y, int w, int h, int b, int iArray[]) { + return sampleModel.getSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + b, iArray, dataBuffer); + } + + /** + * Gets the transfer type for pixels of this Raster. + * + * @see SampleModel#getTransferType() + * @return the transfer type for pixels of this Raster. + */ + public final int getTransferType() { + return sampleModel.getTransferType(); + } + + /** + * Gets the width of this Raster. + * + * @return the width of this Raster. + */ + public final int getWidth() { + return width; + } + + /** + * Validate data buffer. + * + * @param dataBuffer + * the data buffer. + * @param w + * the w. + * @param h + * the h. + * @param scanlineStride + * the scanline stride. + */ + private static void validateDataBuffer(final DataBuffer dataBuffer, final int w, final int h, + final int scanlineStride) { + if (dataBuffer.getSize() < (scanlineStride * (h - 1) + w - 1)) { + // awt.298=dataBuffer is too small + throw new RasterFormatException(Messages.getString("awt.298")); //$NON-NLS-1$ + } + } +} diff --git a/awt/java/awt/image/RasterFormatException.java b/awt/java/awt/image/RasterFormatException.java new file mode 100644 index 0000000..c667141 --- /dev/null +++ b/awt/java/awt/image/RasterFormatException.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +/** + * The RasterFormatException class represents the exception that is thrown when + * there's an invalid layout in the Raster. + * + * @since Android 1.0 + */ +public class RasterFormatException extends RuntimeException { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 96598996116164315L; + + /** + * Instantiates a new RasterFormatException with the specified detail + * message. + * + * @param s + * the detail message. + */ + public RasterFormatException(String s) { + super(s); + } + +} diff --git a/awt/java/awt/image/RasterOp.java b/awt/java/awt/image/RasterOp.java new file mode 100644 index 0000000..19a84c9 --- /dev/null +++ b/awt/java/awt/image/RasterOp.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.RenderingHints; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * The RasterOp interface provides methods for performing transformations from + * source data to destination data for Raster objects. The source and + * destination objects should contain the appropriate number of bands for the + * particular classes which implement this interface. + * + * @since Android 1.0 + */ +public interface RasterOp { + + /** + * Creates a destination WritableRaster with the specified Raster; this + * destination image data is empty and has the correct size and number of + * bands. + * + * @param src + * the source Raster. + * @return the WritableRaster. + */ + public WritableRaster createCompatibleDestRaster(Raster src); + + /** + * Performs a filter operation on the source Raster and stores the resulting + * image data to the destination WritableRaster. + * + * @param src + * the source Raster. + * @param dst + * the destination WritableRaster, where the result is stored. + * @return the filtered WritableRaster. + */ + public WritableRaster filter(Raster src, WritableRaster dst); + + /** + * Gets the bounds of the filtered Raster. + * + * @param src + * the source Raster to be filtered. + * @return the rectangle bounds of the filtered Raster. + */ + public Rectangle2D getBounds2D(Raster src); + + /** + * Gets the point of the destination image which corresponds to the + * specified point in the source raster. + * + * @param srcPoint + * the point of the source raster. + * @param dstPoint + * the point where the result will be stored. + * @return the destination point. + */ + public Point2D getPoint2D(Point2D srcPoint, Point2D dstPoint); + + /** + * Gets the RenderingHints of the RasterOp. + * + * @return the RenderingHints of the RasterOp. + */ + public RenderingHints getRenderingHints(); +} diff --git a/awt/java/awt/image/RenderedImage.java b/awt/java/awt/image/RenderedImage.java new file mode 100644 index 0000000..5eafa64 --- /dev/null +++ b/awt/java/awt/image/RenderedImage.java @@ -0,0 +1,198 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.Rectangle; +import java.util.Vector; + +/** + * The RenderedImage interface should be implemented by all objects which + * contains image data. The image data is represented as a single tile or an + * array of tiles. + * + * @since Android 1.0 + */ +public interface RenderedImage { + + /** + * Gets the property with the specified name from the property set of this + * RenderedImage. + * + * @param name + * the property's name. + * @return the property value corresponded to this property's name. + */ + public Object getProperty(String name); + + /** + * Copies the region of this RenderedImage to the specified WritableRaster. + * The bounds of the region are the bounds of the WritableRaster. + * + * @param raster + * the WritableRaster. + * @return the created WritableRaster. + */ + public WritableRaster copyData(WritableRaster raster); + + /** + * Gets the image data of the image's region as one tile. + * + * @param rect + * the rectangular region of RenderedImage. + * @return the image data of the image's region as one tile. + */ + public Raster getData(Rectangle rect); + + /** + * Gets all RenderedImage objects which are the source of this RenderedImage + * object. + * + * @return a Vector of RenderedImage objects which are the source of this + * RenderedImage object or null, if there is no information about + * them. + */ + public Vector<RenderedImage> getSources(); + + /** + * Gets the set of all property names for this RenderedImage. + * + * @return the array of all property names for this RenderedImage. + */ + public String[] getPropertyNames(); + + /** + * Gets the SampleModel of this RenderedImage. + * + * @return the SampleModel of this RenderedImage. + */ + public SampleModel getSampleModel(); + + /** + * Gets the tile corresponded to the specified indices in the tile array. + * + * @param tileX + * the X index of the tile. + * @param tileY + * the Y index of the tile. + * @return the tile corresponded to the specified indices in the tile array. + */ + public Raster getTile(int tileX, int tileY); + + /** + * Gets the image data of this image as one tile. + * + * @return the image data of this image as one tile. + */ + public Raster getData(); + + /** + * Gets the ColorModel of this RenderedImage. + * + * @return the ColorModel of this RenderedImage. + */ + public ColorModel getColorModel(); + + /** + * Gets the width of the RenderedImage. + * + * @return the width of the RenderedImage. + */ + public int getWidth(); + + /** + * Gets the tile width. + * + * @return the tile width in pixels. + */ + public int getTileWidth(); + + /** + * Gets the tile height. + * + * @return the tile height in pixels. + */ + public int getTileHeight(); + + /** + * Gets the Y offset of the tile grid. + * + * @return the Y offset of the tile grid. + */ + public int getTileGridYOffset(); + + /** + * Gets the X offset of the tile grid. + * + * @return the X offset of the tile grid. + */ + public int getTileGridXOffset(); + + /** + * Gets the number of tiles along Y direction. + * + * @return the number of tiles along Y direction. + */ + public int getNumYTiles(); + + /** + * Gets the number of tiles along X direction. + * + * @return the number of tiles along X direction. + */ + public int getNumXTiles(); + + /** + * Gets the minimum Y coordinate of this RenderedImage. + * + * @return the minimum Y coordinate of this RenderedImage. + */ + public int getMinY(); + + /** + * Gets the minimum X coordinate of this RenderedImage. + * + * @return the minimum X coordinate of this RenderedImage. + */ + public int getMinX(); + + /** + * Gets the minimum tile's index along the Y direction. + * + * @return the minimum tile's index along the Y direction. + */ + public int getMinTileY(); + + /** + * Gets the minimum tile's index along the X direction. + * + * @return the minimum tile's index along the X direction. + */ + public int getMinTileX(); + + /** + * Gets the height of the RenderedImage. + * + * @return the height of the RenderedImage. + */ + public int getHeight(); + +} diff --git a/awt/java/awt/image/ReplicateScaleFilter.java b/awt/java/awt/image/ReplicateScaleFilter.java new file mode 100644 index 0000000..51c0f49 --- /dev/null +++ b/awt/java/awt/image/ReplicateScaleFilter.java @@ -0,0 +1,225 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.util.Hashtable; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The ReplicateScaleFilter class scales an source image by replicating rows and + * columns of pixels to scale up or omitting rows and columns of pixels to scale + * down. + * + * @since Android 1.0 + */ +public class ReplicateScaleFilter extends ImageFilter { + + /** + * The width of a source image. + */ + protected int srcWidth; + + /** + * The height of a source image. + */ + protected int srcHeight; + + /** + * The width of a destination image. + */ + protected int destWidth; + + /** + * The height of a destination image. + */ + protected int destHeight; + + /** + * The integer array of source rows. + */ + protected int[] srcrows; + + /** + * The integer array of source columns. + */ + protected int[] srccols; + + /** + * An Object (byte array with a destination width) provides a row of pixel + * data to the ImageConsumer. + */ + protected Object outpixbuf; + + /** + * Instantiates a new ReplicateScaleFilter that filters the image with the + * specified width and height. + * + * @param width + * the width of scaled image. + * @param height + * the height of scaled image. + */ + public ReplicateScaleFilter(int width, int height) { + if (width == 0 || height == 0) { + // awt.234=Width or Height equals zero + throw new IllegalArgumentException(Messages.getString("awt.234")); //$NON-NLS-1$ + } + + this.destWidth = width; + this.destHeight = height; + } + + @SuppressWarnings("unchecked") + @Override + public void setProperties(Hashtable<?, ?> props) { + Hashtable<Object, Object> fprops; + if (props == null) { + fprops = new Hashtable<Object, Object>(); + } else { + fprops = (Hashtable<Object, Object>)props.clone(); + } + String propName = "Rescale Filters"; //$NON-NLS-1$ + String prop = "destWidth=" + destWidth + "; " + //$NON-NLS-1$ //$NON-NLS-2$ + "destHeight=" + destHeight; //$NON-NLS-1$ + Object o = fprops.get(propName); + if (o != null) { + if (o instanceof String) { + prop = (String)o + "; " + prop; //$NON-NLS-1$ + } else { + prop = o.toString() + "; " + prop; //$NON-NLS-1$ + } + } + fprops.put(propName, prop); + consumer.setProperties(fprops); + } + + // setPixels methods produce pixels according to Java API Spacification + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize) { + + if (srccols == null) { + initArrays(); + } + int buff[]; + if (outpixbuf == null || !(outpixbuf instanceof int[])) { + buff = new int[destWidth]; + outpixbuf = buff; + } else { + buff = (int[])outpixbuf; + } + + int wa = (srcWidth - 1) >>> 1; + int ha = (srcHeight - 1) >>> 1; + int dstX = (x * destWidth + wa) / srcWidth; + int dstY = (y * destHeight + ha) / srcHeight; + + int sx, sy, dx, dy; + dy = dstY; + while ((dy < destHeight) && ((sy = srcrows[dy]) < y + h)) { + dx = dstX; + int srcOff = off + (sy - y) * scansize; + while ((dx < destWidth) && ((sx = srccols[dx]) < x + w)) { + buff[dx] = pixels[srcOff + (sx - x)]; + dx++; + } + + consumer.setPixels(dstX, dy, dx - dstX, 1, model, buff, dstX, destWidth); + dy++; + } + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize) { + + if (srccols == null) { + initArrays(); + } + byte buff[]; + if (outpixbuf == null || !(outpixbuf instanceof byte[])) { + buff = new byte[destWidth]; + outpixbuf = buff; + } else { + buff = (byte[])outpixbuf; + } + + int wa = (srcWidth - 1) >>> 1; + int ha = (srcHeight - 1) >>> 1; + int dstX = (x * destWidth + wa) / srcWidth; + int dstY = (y * destHeight + ha) / srcHeight; + + int sx, sy, dx, dy; + dy = dstY; + while ((dy < destHeight) && ((sy = srcrows[dy]) < y + h)) { + dx = dstX; + int srcOff = off + (sy - y) * scansize; + while ((dx < destWidth) && ((sx = srccols[dx]) < x + w)) { + buff[dx] = pixels[srcOff + (sx - x)]; + dx++; + } + + consumer.setPixels(dstX, dy, dx - dstX, 1, model, buff, dstX, destWidth); + dy++; + } + } + + @Override + public void setDimensions(int w, int h) { + srcWidth = w; + srcHeight = h; + + if (destWidth < 0 && destHeight < 0) { + destWidth = srcWidth; + destHeight = srcHeight; + } else if (destWidth < 0) { + destWidth = destHeight * srcWidth / srcHeight; + } else if (destHeight < 0) { + destHeight = destWidth * srcHeight / srcWidth; + } + consumer.setDimensions(destWidth, destHeight); + } + + /** + * Initialization of srccols and srcrows arrays. + */ + private void initArrays() { + if ((destWidth < 0) || (destHeight < 0)) { + throw new IndexOutOfBoundsException(); + } + + srccols = new int[destWidth]; + int ca = srcWidth >>> 1; + for (int i = 0; i < destWidth; i++) { + srccols[i] = (i * srcWidth + ca) / destWidth; + } + + srcrows = new int[destHeight]; + int ra = srcHeight >>> 1; + for (int i = 0; i < destHeight; i++) { + srcrows[i] = (i * srcHeight + ra) / destHeight; + } + } + +} diff --git a/awt/java/awt/image/RescaleOp.java b/awt/java/awt/image/RescaleOp.java new file mode 100644 index 0000000..d7e2bd7 --- /dev/null +++ b/awt/java/awt/image/RescaleOp.java @@ -0,0 +1,659 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Oct 6, 2005 + */ + +package java.awt.image; + +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.*; +import java.util.Arrays; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class RescaleOp performs rescaling of the source image data by + * multiplying the pixel values with a scale factor and then adding an offset. + * + * @since Android 1.0 + */ +public class RescaleOp implements BufferedImageOp, RasterOp { + + /** + * The scale factors. + */ + private float scaleFactors[]; + + /** + * The offsets. + */ + private float offsets[]; + + /** + * The hints. + */ + private RenderingHints hints; + + static { + // TODO + // System.loadLibrary("imageops"); + } + + /** + * Instantiates a new RescaleOp object with the specified scale factors and + * offsets. + * + * @param scaleFactors + * the array of scale factor values. + * @param offsets + * the array of offset values. + * @param hints + * the RenderingHints or null. + */ + public RescaleOp(float[] scaleFactors, float[] offsets, RenderingHints hints) { + int numFactors = Math.min(scaleFactors.length, offsets.length); + + this.scaleFactors = new float[numFactors]; + this.offsets = new float[numFactors]; + + System.arraycopy(scaleFactors, 0, this.scaleFactors, 0, numFactors); + System.arraycopy(offsets, 0, this.offsets, 0, numFactors); + + this.hints = hints; + } + + /** + * Instantiates a new RescaleOp object with the specified scale factor and + * offset. + * + * @param scaleFactor + * the scale factor. + * @param offset + * the offset. + * @param hints + * the RenderingHints or null. + */ + public RescaleOp(float scaleFactor, float offset, RenderingHints hints) { + scaleFactors = new float[1]; + offsets = new float[1]; + + scaleFactors[0] = scaleFactor; + offsets[0] = offset; + + this.hints = hints; + } + + /** + * Gets the number of scaling factors. + * + * @return the number of scaling factors. + */ + public final int getNumFactors() { + return scaleFactors.length; + } + + public final RenderingHints getRenderingHints() { + return hints; + } + + /** + * Gets the scale factors of this RescaleOp. + * + * @param scaleFactors + * the desired scale factors array will be copied to this array. + * @return the scale factors array. + */ + public final float[] getScaleFactors(float[] scaleFactors) { + if (scaleFactors == null) { + scaleFactors = new float[this.scaleFactors.length]; + } + + int minLength = Math.min(scaleFactors.length, this.scaleFactors.length); + System.arraycopy(this.scaleFactors, 0, scaleFactors, 0, minLength); + return scaleFactors; + } + + /** + * Gets the offsets array of this RescaleOp. + * + * @param offsets + * the desired offsets array will be copied to this array. + * @return the offsets array of this RescaleOp. + */ + public final float[] getOffsets(float[] offsets) { + if (offsets == null) { + offsets = new float[this.offsets.length]; + } + + int minLength = Math.min(offsets.length, this.offsets.length); + System.arraycopy(this.offsets, 0, offsets, 0, minLength); + return offsets; + } + + public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { + if (dstPt == null) { + dstPt = new Point2D.Float(); + } + + dstPt.setLocation(srcPt); + return dstPt; + } + + public final Rectangle2D getBounds2D(Raster src) { + return src.getBounds(); + } + + public final Rectangle2D getBounds2D(BufferedImage src) { + return getBounds2D(src.getRaster()); + } + + public WritableRaster createCompatibleDestRaster(Raster src) { + return src.createCompatibleWritableRaster(); + } + + public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) { + if (dstCM == null) { + dstCM = src.getColorModel(); + } + + if (dstCM instanceof IndexColorModel) { + dstCM = ColorModel.getRGBdefault(); + } + + WritableRaster r = dstCM.isCompatibleSampleModel(src.getSampleModel()) ? src.getRaster() + .createCompatibleWritableRaster(src.getWidth(), src.getHeight()) : dstCM + .createCompatibleWritableRaster(src.getWidth(), src.getHeight()); + + return new BufferedImage(dstCM, r, dstCM.isAlphaPremultiplied(), null); + } + + public final WritableRaster filter(Raster src, WritableRaster dst) { + if (dst == null) { + dst = createCompatibleDestRaster(src); + } else { + if (src.getNumBands() != dst.getNumBands()) { + // awt.21D=Number of src bands ({0}) does not match number of + // dst bands ({1}) + throw new IllegalArgumentException(Messages.getString("awt.21D", //$NON-NLS-1$ + src.getNumBands(), dst.getNumBands())); + } + } + + if (this.scaleFactors.length != 1 && this.scaleFactors.length != src.getNumBands()) { + // awt.21E=Number of scaling constants is not equal to the number of + // bands + throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$ + } + + // TODO + // if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM, false) != 0) + if (slowFilter(src, dst, false) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + } + + return dst; + } + + /** + * Slow filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @param skipAlpha + * the skip alpha. + * @return the int. + */ + private final int slowFilter(Raster src, WritableRaster dst, boolean skipAlpha) { + SampleModel sm = src.getSampleModel(); + + int numBands = src.getNumBands(); + int srcHeight = src.getHeight(); + int srcWidth = src.getWidth(); + + int srcMinX = src.getMinX(); + int srcMinY = src.getMinY(); + int dstMinX = dst.getMinX(); + int dstMinY = dst.getMinY(); + + int[] maxValues = new int[numBands]; + int[] masks = new int[numBands]; + int[] sampleSizes = sm.getSampleSize(); + + for (int i = 0; i < numBands; i++) { + maxValues[i] = (1 << sampleSizes[i]) - 1; + masks[i] = ~(maxValues[i]); + } + + // Processing bounds + float[] pixels = null; + pixels = src.getPixels(srcMinX, srcMinY, srcWidth, srcHeight, pixels); + + // Cycle over pixels to be calculated + if (skipAlpha) { // Always suppose that alpha channel is the last band + if (scaleFactors.length > 1) { + for (int i = 0; i < pixels.length;) { + for (int bandIdx = 0; bandIdx < numBands - 1; bandIdx++, i++) { + pixels[i] = pixels[i] * scaleFactors[bandIdx] + offsets[bandIdx]; + // Check for overflow now + if (((int)pixels[i] & masks[bandIdx]) != 0) { + if (pixels[i] < 0) { + pixels[i] = 0; + } else { + pixels[i] = maxValues[bandIdx]; + } + } + } + + i++; + } + } else { + for (int i = 0; i < pixels.length;) { + for (int bandIdx = 0; bandIdx < numBands - 1; bandIdx++, i++) { + pixels[i] = pixels[i] * scaleFactors[0] + offsets[0]; + // Check for overflow now + if (((int)pixels[i] & masks[bandIdx]) != 0) { + if (pixels[i] < 0) { + pixels[i] = 0; + } else { + pixels[i] = maxValues[bandIdx]; + } + } + } + + i++; + } + } + } else { + if (scaleFactors.length > 1) { + for (int i = 0; i < pixels.length;) { + for (int bandIdx = 0; bandIdx < numBands; bandIdx++, i++) { + pixels[i] = pixels[i] * scaleFactors[bandIdx] + offsets[bandIdx]; + // Check for overflow now + if (((int)pixels[i] & masks[bandIdx]) != 0) { + if (pixels[i] < 0) { + pixels[i] = 0; + } else { + pixels[i] = maxValues[bandIdx]; + } + } + } + } + } else { + for (int i = 0; i < pixels.length;) { + for (int bandIdx = 0; bandIdx < numBands; bandIdx++, i++) { + pixels[i] = pixels[i] * scaleFactors[0] + offsets[0]; + // Check for overflow now + if (((int)pixels[i] & masks[bandIdx]) != 0) { + if (pixels[i] < 0) { + pixels[i] = 0; + } else { + pixels[i] = maxValues[bandIdx]; + } + } + } + } + } + } + + dst.setPixels(dstMinX, dstMinY, srcWidth, srcHeight, pixels); + + return 0; + } + + public final BufferedImage filter(BufferedImage src, BufferedImage dst) { + ColorModel srcCM = src.getColorModel(); + + if (srcCM instanceof IndexColorModel) { + // awt.220=Source should not have IndexColorModel + throw new IllegalArgumentException(Messages.getString("awt.220")); //$NON-NLS-1$ + } + + // Check if the number of scaling factors matches the number of bands + int nComponents = srcCM.getNumComponents(); + boolean skipAlpha; + if (srcCM.hasAlpha()) { + if (scaleFactors.length == 1 || scaleFactors.length == nComponents - 1) { + skipAlpha = true; + } else if (scaleFactors.length == nComponents) { + skipAlpha = false; + } else { + // awt.21E=Number of scaling constants is not equal to the + // number of bands + throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$ + } + } else if (scaleFactors.length == 1 || scaleFactors.length == nComponents) { + skipAlpha = false; + } else { + // awt.21E=Number of scaling constants is not equal to the number of + // bands + throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$ + } + + BufferedImage finalDst = null; + if (dst == null) { + finalDst = dst; + dst = createCompatibleDestImage(src, srcCM); + } else if (!srcCM.equals(dst.getColorModel())) { + // Treat BufferedImage.TYPE_INT_RGB and BufferedImage.TYPE_INT_ARGB + // as same + if (!((src.getType() == BufferedImage.TYPE_INT_RGB || src.getType() == BufferedImage.TYPE_INT_ARGB) && (dst + .getType() == BufferedImage.TYPE_INT_RGB || dst.getType() == BufferedImage.TYPE_INT_ARGB))) { + finalDst = dst; + dst = createCompatibleDestImage(src, srcCM); + } + } + + // TODO + // if (ippFilter(src.getRaster(), dst.getRaster(), src.getType(), + // skipAlpha) != 0) + if (slowFilter(src.getRaster(), dst.getRaster(), skipAlpha) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + } + + if (finalDst != null) { + Graphics2D g = finalDst.createGraphics(); + g.setComposite(AlphaComposite.Src); + g.drawImage(dst, 0, 0, null); + } else { + finalDst = dst; + } + + return finalDst; + } + + // Don't forget to pass allocated arrays for levels and values, size should + // be numBands*4 + /** + * Creates the levels. + * + * @param sm + * the sm. + * @param numBands + * the num bands. + * @param skipAlpha + * the skip alpha. + * @param levels + * the levels. + * @param values + * the values. + * @param channelsOrder + * the channels order. + */ + private final void createLevels(SampleModel sm, int numBands, boolean skipAlpha, int levels[], + int values[], int channelsOrder[]) { + // Suppose same sample size for all channels, otherwise use slow filter + int maxValue = (1 << sm.getSampleSize(0)) - 1; + + // For simplicity introduce these arrays + float extScaleFactors[] = new float[numBands]; + float extOffsets[] = new float[numBands]; + + if (scaleFactors.length != 1) { + System.arraycopy(scaleFactors, 0, extScaleFactors, 0, scaleFactors.length); + System.arraycopy(offsets, 0, extOffsets, 0, scaleFactors.length); + } else { + for (int i = 0; i < numBands; i++) { + extScaleFactors[i] = scaleFactors[0]; + extOffsets[i] = offsets[0]; + } + } + + if (skipAlpha) { + extScaleFactors[numBands - 1] = 1; + extOffsets[numBands - 1] = 0; + } + + // Create a levels + for (int i = 0; i < numBands; i++) { + if (extScaleFactors[i] == 0) { + levels[i * 4] = 0; + levels[i * 4 + 1] = 0; + levels[i * 4 + 2] = maxValue + 1; + levels[i * 4 + 3] = maxValue + 1; + } + + float minLevel = -extOffsets[i] / extScaleFactors[i]; + float maxLevel = (maxValue - extOffsets[i]) / extScaleFactors[i]; + + if (minLevel < 0) { + minLevel = 0; + } else if (minLevel > maxValue) { + minLevel = maxValue; + } + + if (maxLevel < 0) { + maxLevel = 0; + } else if (maxLevel > maxValue) { + maxLevel = maxValue; + } + + levels[i * 4] = 0; + if (minLevel > maxLevel) { + levels[i * 4 + 1] = (int)maxLevel; + levels[i * 4 + 2] = (int)minLevel; + } else { + levels[i * 4 + 1] = (int)minLevel; + levels[i * 4 + 2] = (int)maxLevel; + } + levels[i * 4 + 3] = maxValue + 1; + + // Fill values + for (int k = 0; k < 4; k++) { + int idx = i * 4 + k; + values[idx] = (int)(extScaleFactors[i] * levels[idx] + extOffsets[i]); + if (values[idx] < 0) { + values[idx] = 0; + } else if (values[idx] > maxValue) { + values[idx] = maxValue; + } + } + } + + // Reorder data if channels are stored in different order + if (channelsOrder != null) { + int len = numBands * 4; + int savedLevels[] = new int[len]; + int savedValues[] = new int[len]; + System.arraycopy(levels, 0, savedLevels, 0, len); + System.arraycopy(values, 0, savedValues, 0, len); + for (int i = 0; i < channelsOrder.length; i++) { + System.arraycopy(savedLevels, i * 4, levels, channelsOrder[i] * 4, 4); + System.arraycopy(savedValues, i * 4, values, channelsOrder[i] * 4, 4); + } + } + } + + // TODO remove when this method is used + /** + * Ipp filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @param imageType + * the image type. + * @param skipAlpha + * the skip alpha. + * @return the int. + */ + @SuppressWarnings("unused") + private final int ippFilter(Raster src, WritableRaster dst, int imageType, boolean skipAlpha) { + int res; + + int srcStride, dstStride; + int channels; + int offsets[] = null; + int channelsOrder[] = null; + + switch (imageType) { + case BufferedImage.TYPE_INT_ARGB: + case BufferedImage.TYPE_INT_ARGB_PRE: + case BufferedImage.TYPE_INT_RGB: { + channels = 4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; + channelsOrder = new int[] { + 2, 1, 0, 3 + }; + break; + } + + case BufferedImage.TYPE_4BYTE_ABGR: + case BufferedImage.TYPE_4BYTE_ABGR_PRE: + case BufferedImage.TYPE_INT_BGR: { + channels = 4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; + break; + } + + case BufferedImage.TYPE_BYTE_GRAY: { + channels = 1; + srcStride = src.getWidth(); + dstStride = dst.getWidth(); + break; + } + + case BufferedImage.TYPE_3BYTE_BGR: { + channels = 3; + srcStride = src.getWidth() * 3; + dstStride = dst.getWidth() * 3; + channelsOrder = new int[] { + 2, 1, 0 + }; + break; + } + + case BufferedImage.TYPE_USHORT_GRAY: + case BufferedImage.TYPE_USHORT_565_RGB: + case BufferedImage.TYPE_USHORT_555_RGB: + case BufferedImage.TYPE_BYTE_BINARY: { + return slowFilter(src, dst, skipAlpha); + } + + default: { + SampleModel srcSM = src.getSampleModel(); + SampleModel dstSM = dst.getSampleModel(); + + if (srcSM instanceof PixelInterleavedSampleModel + && dstSM instanceof PixelInterleavedSampleModel) { + // Check PixelInterleavedSampleModel + if (srcSM.getDataType() != DataBuffer.TYPE_BYTE + || dstSM.getDataType() != DataBuffer.TYPE_BYTE) { + return slowFilter(src, dst, skipAlpha); + } + + channels = srcSM.getNumBands(); // Have IPP functions for 1, + // 3 and 4 channels + if (!(channels == 1 || channels == 3 || channels == 4)) { + return slowFilter(src, dst, skipAlpha); + } + + srcStride = ((ComponentSampleModel)srcSM).getScanlineStride(); + dstStride = ((ComponentSampleModel)dstSM).getScanlineStride(); + + channelsOrder = ((ComponentSampleModel)srcSM).getBandOffsets(); + } else if (srcSM instanceof SinglePixelPackedSampleModel + && dstSM instanceof SinglePixelPackedSampleModel) { + // Check SinglePixelPackedSampleModel + SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)srcSM; + SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel)dstSM; + + channels = sppsm1.getNumBands(); + + // TYPE_INT_RGB, TYPE_INT_ARGB... + if (sppsm1.getDataType() != DataBuffer.TYPE_INT + || sppsm2.getDataType() != DataBuffer.TYPE_INT + || !(channels == 3 || channels == 4)) { + return slowFilter(src, dst, skipAlpha); + } + + // Check compatibility of sample models + if (!Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) + || !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())) { + return slowFilter(src, dst, skipAlpha); + } + + for (int i = 0; i < channels; i++) { + if (sppsm1.getSampleSize(i) != 8) { + return slowFilter(src, dst, skipAlpha); + } + } + + channelsOrder = new int[channels]; + int bitOffsets[] = sppsm1.getBitOffsets(); + for (int i = 0; i < channels; i++) { + channelsOrder[i] = bitOffsets[i] / 8; + } + + if (channels == 3) { // Don't skip channel now, could be + // optimized + channels = 4; + } + + srcStride = sppsm1.getScanlineStride() * 4; + dstStride = sppsm2.getScanlineStride() * 4; + } else { + return slowFilter(src, dst, skipAlpha); + } + + // Fill offsets if there's a child raster + if (src.getParent() != null || dst.getParent() != null) { + if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0 + || dst.getSampleModelTranslateX() != 0 + || dst.getSampleModelTranslateY() != 0) { + offsets = new int[4]; + offsets[0] = -src.getSampleModelTranslateX() + src.getMinX(); + offsets[1] = -src.getSampleModelTranslateY() + src.getMinY(); + offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX(); + offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY(); + } + } + } + } + + int levels[] = new int[4 * channels]; + int values[] = new int[4 * channels]; + + createLevels(src.getSampleModel(), channels, skipAlpha, levels, values, channelsOrder); + + Object srcData, dstData; + AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance(); + try { + srcData = dbAccess.getData(src.getDataBuffer()); + dstData = dbAccess.getData(dst.getDataBuffer()); + } catch (IllegalArgumentException e) { + return -1; // Unknown data buffer type + } + + res = LookupOp.ippLUT(srcData, src.getWidth(), src.getHeight(), srcStride, dstData, dst + .getWidth(), dst.getHeight(), dstStride, levels, values, channels, offsets, true); + + return res; + } +} diff --git a/awt/java/awt/image/SampleModel.java b/awt/java/awt/image/SampleModel.java new file mode 100644 index 0000000..c967fa6 --- /dev/null +++ b/awt/java/awt/image/SampleModel.java @@ -0,0 +1,1166 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The SampleModel class is abstract class for retrieving pixel's samples in the + * data of an image. Each pixel contains several samples. A sample is the set of + * values of the bands for single pixel. For example, each pixel in the RGB + * model contains three samples and there are three corresponding bands in the + * image data of such pixels representing red, green and blue components. + * <p> + * The image data is represented as a Raster with a DataBuffer and a + * SampleModel. The SampleModel allows access to the samples in the DataBuffer. + * + * @since Android 1.0 + */ +public abstract class SampleModel { + + /** + * The width of the image data which this SampleModel describes. + */ + protected int width; + + /** + * The height of the image data which this SampleModel describes. + */ + protected int height; + + /** + * The number of bands of image data which this SampleModel describes. + */ + protected int numBands; + + /** + * The data type of the image data which this SampleModel describes. + */ + protected int dataType; + + /** + * Instantiates a new SampleModel with the specified data type, width, + * height and number of bands. + * + * @param dataType + * the data type of the image data. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param numBands + * the number of bands of the image data. + */ + public SampleModel(int dataType, int w, int h, int numBands) { + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new IllegalArgumentException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + double squre = ((double)w) * ((double)h); + if (squre >= Integer.MAX_VALUE) { + // awt.22F=The product of w and h is greater than Integer.MAX_VALUE + throw new IllegalArgumentException(Messages.getString("awt.22F")); //$NON-NLS-1$ + } + + if (dataType < DataBuffer.TYPE_BYTE || dataType > DataBuffer.TYPE_DOUBLE + && dataType != DataBuffer.TYPE_UNDEFINED) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + if (numBands < 1) { + // awt.231=Number of bands must be more then 0 + throw new IllegalArgumentException(Messages.getString("awt.231")); //$NON-NLS-1$ + } + + this.dataType = dataType; + this.width = w; + this.height = h; + this.numBands = numBands; + + } + + /** + * Gets the data array for the specified pixel of the specified DataBuffer + * with one of the following types: DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param obj + * the Object is a data where the result will be stored. + * @param data + * the image data. + * @return the data array for the specified pixel of the specified + * DataBuffer. + */ + public abstract Object getDataElements(int x, int y, Object obj, DataBuffer data); + + /** + * Gets the array of pixel data for the specified rectangular area of pixels + * of the specified DataBuffer with one of the following types: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, + * DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * + * @param x + * the X coordinate of the rectangular pixel area. + * @param y + * the Y coordinate of the rectangular pixel area. + * @param w + * the width of the rectangular pixel area. + * @param h + * the height of the rectangular pixel area. + * @param obj + * the Object is an array with the primitive type, where the + * result array will be stored. + * @param data + * the image data. + * @return the array of pixel data for the specified rectangular area of + * pixels of the specified DataBuffer object. + */ + public Object getDataElements(int x, int y, int w, int h, Object obj, DataBuffer data) { + int numDataElements = getNumDataElements(); + int idx = 0; + + switch (getTransferType()) { + case DataBuffer.TYPE_BYTE: + byte bdata[]; + byte bbuf[] = null; + + if (obj == null) { + bdata = new byte[numDataElements * w * h]; + } else { + bdata = (byte[])obj; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + bbuf = (byte[])getDataElements(j, i, bbuf, data); + for (int n = 0; n < numDataElements; n++) { + bdata[idx++] = bbuf[n]; + } + } + } + obj = bdata; + break; + + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short sdata[]; + short sbuf[] = null; + + if (obj == null) { + sdata = new short[numDataElements * w * h]; + } else { + sdata = (short[])obj; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + sbuf = (short[])getDataElements(j, i, sbuf, data); + for (int n = 0; n < numDataElements; n++) { + sdata[idx++] = sbuf[n]; + } + } + } + obj = sdata; + break; + + case DataBuffer.TYPE_INT: + int idata[]; + int ibuf[] = null; + + if (obj == null) { + idata = new int[numDataElements * w * h]; + } else { + idata = (int[])obj; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + ibuf = (int[])getDataElements(j, i, ibuf, data); + for (int n = 0; n < numDataElements; n++) { + idata[idx++] = ibuf[n]; + } + } + } + obj = idata; + break; + + case DataBuffer.TYPE_FLOAT: + float fdata[]; + float fbuf[] = null; + + if (obj == null) { + fdata = new float[numDataElements * w * h]; + } else { + fdata = (float[])obj; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + fbuf = (float[])getDataElements(j, i, fbuf, data); + for (int n = 0; n < numDataElements; n++) { + fdata[idx++] = fbuf[n]; + } + } + } + obj = fdata; + break; + + case DataBuffer.TYPE_DOUBLE: + double ddata[]; + double dbuf[] = null; + + if (obj == null) { + ddata = new double[numDataElements * w * h]; + } else { + ddata = (double[])obj; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + dbuf = (double[])getDataElements(j, i, dbuf, data); + for (int n = 0; n < numDataElements; n++) { + ddata[idx++] = dbuf[n]; + } + } + } + obj = ddata; + break; + + } + + return obj; + } + + /** + * Sets the data for a single pixel in the specified DataBuffer from a + * primitive array with one of the following types: DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param obj + * the Object - the array of primitive pixel data to be set. + * @param data + * the image data. + */ + public abstract void setDataElements(int x, int y, Object obj, DataBuffer data); + + /** + * Sets the data elements for a rectangular area of pixels in the specified + * DataBuffer from a primitive array with one of the following types: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, + * DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * + * @param x + * the X coordinate of the specified rectangular area. + * @param y + * the Y coordinate of the specified rectangular area. + * @param w + * the width of rectangle. + * @param h + * the height of rectangle. + * @param obj + * the Object - the array of primitive pixel data to be set. + * @param data + * the image data. + */ + public void setDataElements(int x, int y, int w, int h, Object obj, DataBuffer data) { + int numDataElements = getNumDataElements(); + int idx = 0; + + switch (getTransferType()) { + case DataBuffer.TYPE_BYTE: + byte bbuf[] = new byte[numDataElements]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numDataElements; n++) { + bbuf[n] = ((byte[])obj)[idx++]; + } + setDataElements(j, i, bbuf, data); + } + } + + break; + + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short sbuf[] = new short[numDataElements]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numDataElements; n++) { + sbuf[n] = ((short[])obj)[idx++]; + } + setDataElements(j, i, sbuf, data); + } + } + break; + + case DataBuffer.TYPE_INT: + int ibuf[] = new int[numDataElements]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numDataElements; n++) { + ibuf[n] = ((int[])obj)[idx++]; + } + setDataElements(j, i, ibuf, data); + } + } + break; + + case DataBuffer.TYPE_FLOAT: + float fbuf[] = new float[numDataElements]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numDataElements; n++) { + fbuf[n] = ((float[])obj)[idx++]; + } + setDataElements(j, i, fbuf, data); + } + } + break; + + case DataBuffer.TYPE_DOUBLE: + double dbuf[] = new double[numDataElements]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numDataElements; n++) { + dbuf[n] = ((double[])obj)[idx++]; + } + setDataElements(j, i, dbuf, data); + } + } + break; + + } + } + + /** + * Creates a new SampleModel with the specified bands of this SampleModel. + * + * @param bands + * the array of bands from this SampleModel. + * @return the SampleModel with the specified bands of this SampleModel. + */ + public abstract SampleModel createSubsetSampleModel(int bands[]); + + /** + * Creates the SampleModel which has the same data as in this SampleModel + * with a different width and height. + * + * @param a0 + * the width of the image data. + * @param a1 + * the height of the image data. + * @return the SampleModel which has the same data as in this SampleModel + * with a different width and height. + */ + public abstract SampleModel createCompatibleSampleModel(int a0, int a1); + + /** + * Gets the samples of the specified pixel as an integer array. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param iArray + * the integer array where result will be stored. + * @param data + * the image data. + * @return the integer array with the samples of the specified pixel. + */ + public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int pixel[]; + + if (iArray == null) { + pixel = new int[numBands]; + } else { + pixel = iArray; + } + + for (int i = 0; i < numBands; i++) { + pixel[i] = getSample(x, y, i, data); + } + + return pixel; + } + + /** + * Sets a pixel of the DataBuffer from a integer array of samples. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param iArray + * the integer array. + * @param data + * the image data. + */ + public void setPixel(int x, int y, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, iArray[i], data); + } + } + + /** + * Gets the samples of the specified pixel as a float array. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param fArray + * the float array where result will be stored. + * @param data + * the image data. + * @return the float array with the samples of the specified pixel. + */ + public float[] getPixel(int x, int y, float fArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + float pixel[]; + + if (fArray == null) { + pixel = new float[numBands]; + } else { + pixel = fArray; + } + + for (int i = 0; i < numBands; i++) { + pixel[i] = getSampleFloat(x, y, i, data); + } + + return pixel; + } + + /** + * Sets a pixel of the DataBuffer from a float array of samples. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param fArray + * the float array. + * @param data + * the image data. + */ + public void setPixel(int x, int y, float fArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, fArray[i], data); + } + } + + /** + * Gets the samples of the specified pixel as a double array. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param dArray + * the double array where result will be stored. + * @param data + * the image data. + * @return the double array with the samples of the specified pixel. + */ + public double[] getPixel(int x, int y, double dArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + double pixel[]; + + if (dArray == null) { + pixel = new double[numBands]; + } else { + pixel = dArray; + } + + for (int i = 0; i < numBands; i++) { + pixel[i] = getSampleDouble(x, y, i, data); + } + + return pixel; + } + + /** + * Sets a pixel of the DataBuffer from a double array of samples. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param dArray + * the double array. + * @param data + * the image data. + */ + public void setPixel(int x, int y, double dArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, dArray[i], data); + } + } + + /** + * Gets the sample of a specified band for the specified pixel as an + * integer. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param b + * the specified band. + * @param data + * the image data. + * @return the sample of a specified band for the specified pixel. + */ + public abstract int getSample(int x, int y, int b, DataBuffer data); + + /** + * Gets the sample of a specified band for the specified pixel as a float. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param b + * the specified band. + * @param data + * the image data. + * @return the sample of a specified band for the specified pixel. + */ + public float getSampleFloat(int x, int y, int b, DataBuffer data) { + return getSample(x, y, b, data); + } + + /** + * Gets the sample of a specified band for the specified pixel as a double. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param b + * the specified band. + * @param data + * the image data. + * @return the sample of a specified band for the specified pixel. + */ + public double getSampleDouble(int x, int y, int b, DataBuffer data) { + return getSample(x, y, b, data); + } + + /** + * Gets the samples of the specified rectangular area of pixels as an + * integer array. + * + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param iArray + * the integer array where result will be stored. + * @param data + * the image data. + * @return the integer array with the samples of the specified rectangular + * area of pixels. + */ + public int[] getPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int pixels[]; + int idx = 0; + + if (iArray == null) { + pixels = new int[w * h * numBands]; + } else { + pixels = iArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + pixels[idx++] = getSample(j, i, n, data); + } + } + } + return pixels; + } + + /** + * Sets all of the samples for a rectangular area of pixels of the + * DataBuffer from an integer array. + * + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param iArray + * the integer array. + * @param data + * the image data. + */ + public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + setSample(j, i, n, iArray[idx++], data); + } + } + } + } + + /** + * Gets the samples of the specified rectangular area of pixels as a float + * array. + * + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param fArray + * the float array where result will be stored. + * @param data + * the image data. + * @return the float array with the samples of the specified rectangular + * area of pixels. + */ + public float[] getPixels(int x, int y, int w, int h, float fArray[], DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + float pixels[]; + int idx = 0; + + if (fArray == null) { + pixels = new float[w * h * numBands]; + } else { + pixels = fArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + pixels[idx++] = getSampleFloat(j, i, n, data); + } + } + } + return pixels; + } + + /** + * Sets all of the samples for a rectangular area of pixels of the + * DataBuffer from a float array. + * + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param fArray + * the float array. + * @param data + * the image data. + */ + public void setPixels(int x, int y, int w, int h, float fArray[], DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + setSample(j, i, n, fArray[idx++], data); + } + } + } + } + + /** + * Gets the samples of the specified rectangular area of pixels as a double + * array. + * + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param dArray + * the double array where result will be stored. + * @param data + * the image data. + * @return the double array with the samples of the specified rectangular + * area of pixels. + */ + public double[] getPixels(int x, int y, int w, int h, double dArray[], DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + double pixels[]; + int idx = 0; + + if (dArray == null) { + pixels = new double[w * h * numBands]; + } else { + pixels = dArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + pixels[idx++] = getSampleDouble(j, i, n, data); + } + } + } + return pixels; + } + + /** + * Sets all of the samples for a rectangular area of pixels of the + * DataBuffer from a double array. + * + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param dArray + * the double array. + * @param data + * the image data. + */ + public void setPixels(int x, int y, int w, int h, double dArray[], DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + setSample(j, i, n, dArray[idx++], data); + } + } + } + } + + /** + * Sets a sample of the specified band for the specified pixel in the + * DataBuffer as integer value. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the specified band. + * @param s + * the sample as an integer value. + * @param data + * the image data. + */ + public abstract void setSample(int x, int y, int b, int s, DataBuffer data); + + /** + * Gets the samples of a specified band for a specified rectangular area of + * pixels as a integer array. + * + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param w + * the width of the rectangle. + * @param h + * the height of the rectangle. + * @param b + * the specified band. + * @param iArray + * the integer array where result will be stored. + * @param data + * the image data. + * @return the samples of a specified band for a specified rectangular area + * of pixels. + */ + public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { + int samples[]; + int idx = 0; + + if (iArray == null) { + samples = new int[w * h]; + } else { + samples = iArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + samples[idx++] = getSample(j, i, b, data); + } + } + + return samples; + } + + /** + * Sets the samples from an integer array in the specified band for the + * specified rectangle of pixels. + * + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param w + * the width of the rectangle. + * @param h + * the height of the rectangle. + * @param b + * the specified band. + * @param iArray + * the integer array. + * @param data + * the image data. + */ + public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + setSample(j, i, b, iArray[idx++], data); + } + } + } + + /** + * Gets the samples of a specified band for a specified rectangular area of + * pixels as a float array. + * + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param w + * the width of the rectangle. + * @param h + * the height of the rectangle. + * @param b + * the specified band. + * @param fArray + * the float array where result will be stored. + * @param data + * the image data. + * @return the samples of a specified band for a specified rectangular area + * of pixels. + */ + public float[] getSamples(int x, int y, int w, int h, int b, float fArray[], DataBuffer data) { + float samples[]; + int idx = 0; + + if (fArray == null) { + samples = new float[w * h]; + } else { + samples = fArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + samples[idx++] = getSampleFloat(j, i, b, data); + } + } + + return samples; + } + + /** + * Sets the samples from an float array in the specified band for the + * specified rectangle of pixels. + * + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param w + * the width of the rectangle. + * @param h + * the height of the rectangle. + * @param b + * the specified band. + * @param fArray + * the float array. + * @param data + * the image data. + */ + public void setSamples(int x, int y, int w, int h, int b, float fArray[], DataBuffer data) { + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + setSample(j, i, b, fArray[idx++], data); + } + } + } + + /** + * Gets the samples of a specified band for a specified rectangular area of + * pixels as a double array. + * + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param w + * the width of the rectangle. + * @param h + * the height of the rectangle. + * @param b + * the specified band. + * @param dArray + * the double array where result will be stored. + * @param data + * the image data. + * @return the samples of a specified band for a specified rectangular area + * of pixels. + */ + public double[] getSamples(int x, int y, int w, int h, int b, double dArray[], DataBuffer data) { + double samples[]; + int idx = 0; + + if (dArray == null) { + samples = new double[w * h]; + } else { + samples = dArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + samples[idx++] = getSampleDouble(j, i, b, data); + } + } + + return samples; + } + + /** + * Sets the samples from an double array in the specified band for the + * specified rectangle of pixels. + * + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param w + * the width of the rectangle. + * @param h + * the height of the rectangle. + * @param b + * the specified band. + * @param dArray + * the double array. + * @param data + * the image data. + */ + public void setSamples(int x, int y, int w, int h, int b, double dArray[], DataBuffer data) { + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + setSample(j, i, b, dArray[idx++], data); + } + } + } + + /** + * Sets a sample of the specified band for the specified pixel in the + * DataBuffer as float value. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the specified band. + * @param s + * the sample as float value. + * @param data + * the image data. + */ + public void setSample(int x, int y, int b, float s, DataBuffer data) { + setSample(x, y, b, (int)s, data); + } + + /** + * Sets a sample of the specified band for the specified pixel in the + * DataBuffer as double value. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the specified band. + * @param s + * the sample as double value. + * @param data + * the image data. + */ + public void setSample(int x, int y, int b, double s, DataBuffer data) { + setSample(x, y, b, (int)s, data); + } + + /** + * Creates a DataBuffer object which corresponds to the SampleModel. + * + * @return the DataBuffer object which corresponds to the SampleModel. + */ + public abstract DataBuffer createDataBuffer(); + + /** + * Gets the sample size in bits for the specified band. + * + * @param band + * the specified band. + * @return the sample size in bits for the specified band. + */ + public abstract int getSampleSize(int band); + + /** + * Gets an array of the sample size in bits for all bands. + * + * @return an array of the sample size in bits for all bands. + */ + public abstract int[] getSampleSize(); + + /** + * Gets the width of the image data of this SampleModel object. + * + * @return the width of the image data of this SampleModel object. + */ + public final int getWidth() { + return width; + } + + /** + * Gets the transfer type used to transfer pixels via the getDataElements + * and setDataElements methods. Transfer type value can be one of the + * predefined type from DataBuffer class or not. + * + * @return the transfer type. + */ + public int getTransferType() { + return dataType; + } + + /** + * Returns the number of data elements for pixel transferring via the + * getDataElements and setDataElements methods. + * + * @return the number of data elements for pixel transferring via the + * getDataElements and setDataElements methods. + */ + public abstract int getNumDataElements(); + + /** + * Gets the number of bands in the image data of this SampleModel object. + * + * @return the number of bands in the image data of this SampleModel object. + */ + public final int getNumBands() { + return numBands; + } + + /** + * Gets the height of the image data of this SampleModel object. + * + * @return the height of the image data of this SampleModel object. + */ + public final int getHeight() { + return height; + } + + /** + * Gets the data type of image data of this SampleModel object. + * + * @return the data type of image data of this SampleModel object. + */ + public final int getDataType() { + return dataType; + } + +} diff --git a/awt/java/awt/image/ShortLookupTable.java b/awt/java/awt/image/ShortLookupTable.java new file mode 100644 index 0000000..4319d58 --- /dev/null +++ b/awt/java/awt/image/ShortLookupTable.java @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Oct 14, 2005 + */ + +package java.awt.image; + +/** + * The ShortLookupTable class provides provides functionality for lookup + * operations, and is defined by an input short array for bands or components of + * image and an offset value. The offset value will be subtracted from the input + * values before indexing the input arrays. The output of a lookup operation is + * represented as an unsigned short array. + * + * @since Android 1.0 + */ +public class ShortLookupTable extends LookupTable { + + /** + * The data. + */ + private short data[][]; + + /** + * Instantiates a new ShortLookupTable with the specified offset value and + * the specified short array which represents lookup table for all bands. + * + * @param offset + * the offset value. + * @param data + * the data array. + */ + public ShortLookupTable(int offset, short[] data) { + super(offset, 1); + this.data = new short[1][data.length]; + // The data array stored as a reference + this.data[0] = data; + } + + /** + * Instantiates a new ShortLookupTable with the specified offset value and + * the specified short array of arrays which represents lookup table for + * each band. + * + * @param offset + * the offset value. + * @param data + * the data array of arrays for each band. + */ + public ShortLookupTable(int offset, short[][] data) { + super(offset, data.length); + this.data = new short[data.length][data[0].length]; + for (int i = 0; i < data.length; i++) { + // The data array for each band stored as a reference + this.data[i] = data[i]; + } + } + + /** + * Gets the lookup table of this ShortLookupTable object. If this + * ShortLookupTable object has one short array for all bands, the returned + * array length is one. + * + * @return the lookup table of this ShortLookupTable object. + */ + public final short[][] getTable() { + return data; + } + + /** + * Returns a short array which contains samples of the specified pixel which + * is translated with the lookup table of this ShortLookupTable object. The + * resulted array is stored to the dst array. + * + * @param src + * the source array. + * @param dst + * the destination array where the result can be stored. + * @return the short array of translated samples of a pixel. + */ + public short[] lookupPixel(short[] src, short[] dst) { + if (dst == null) { + dst = new short[src.length]; + } + + int offset = getOffset(); + if (getNumComponents() == 1) { + for (int i = 0; i < src.length; i++) { + dst[i] = data[0][src[i] - offset]; + } + } else { + for (int i = 0; i < getNumComponents(); i++) { + dst[i] = data[i][src[i] - offset]; + } + } + + return dst; + } + + @Override + public int[] lookupPixel(int[] src, int[] dst) { + if (dst == null) { + dst = new int[src.length]; + } + + int offset = getOffset(); + if (getNumComponents() == 1) { + for (int i = 0; i < src.length; i++) { + dst[i] = data[0][src[i] - offset]; + } + } else { + for (int i = 0; i < getNumComponents(); i++) { + dst[i] = data[i][src[i] - offset]; + } + } + + return dst; + } +} diff --git a/awt/java/awt/image/SinglePixelPackedSampleModel.java b/awt/java/awt/image/SinglePixelPackedSampleModel.java new file mode 100644 index 0000000..69f3353 --- /dev/null +++ b/awt/java/awt/image/SinglePixelPackedSampleModel.java @@ -0,0 +1,519 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.util.Arrays; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The SinglePixelPackedSampleModel class represents pixel data where several + * samples combine to create a single pixel and are stored in a single data + * array element. This class supports TYPE_BYTE, TYPE_USHORT, TYPE_INT data + * types. + * + * @since Android 1.0 + */ +public class SinglePixelPackedSampleModel extends SampleModel { + + /** + * The bit masks. + */ + private int bitMasks[]; + + /** + * The bit offsets. + */ + private int bitOffsets[]; + + /** + * The bit sizes. + */ + private int bitSizes[]; + + /** + * The scanline stride. + */ + private int scanlineStride; + + /** + * The max bit size. + */ + private int maxBitSize; + + /** + * Instantiates a new SinglePixelPackedSampleModel with the specified + * parameters. + * + * @param dataType + * the data type of samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param bitMasks + * the bit masks for all the bands. + */ + public SinglePixelPackedSampleModel(int dataType, int w, int h, int bitMasks[]) { + this(dataType, w, h, w, bitMasks); + } + + /** + * Instantiates a new SinglePixelPackedSampleModel with the specified + * parameters. + * + * @param dataType + * the data type of the samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param bitMasks + * the bit masks for all the bands. + */ + public SinglePixelPackedSampleModel(int dataType, int w, int h, int scanlineStride, + int bitMasks[]) { + + super(dataType, w, h, bitMasks.length); + + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.61=Unsupported data type: {0} + throw new IllegalArgumentException(Messages.getString("awt.61", //$NON-NLS-1$ + dataType)); + } + + this.scanlineStride = scanlineStride; + this.bitMasks = bitMasks.clone(); + this.bitOffsets = new int[this.numBands]; + this.bitSizes = new int[this.numBands]; + + this.maxBitSize = 0; + + for (int i = 0; i < this.numBands; i++) { + int offset = 0; + int size = 0; + int mask = bitMasks[i]; + + if (mask != 0) { + while ((mask & 1) == 0) { + mask >>>= 1; + offset++; + } + + while ((mask & 1) == 1) { + mask >>>= 1; + size++; + } + + if (mask != 0) { + // awt.62=Wrong mask : {0} + throw new IllegalArgumentException(Messages.getString("awt.62", bitMasks[i])); //$NON-NLS-1$ + } + } + + this.bitOffsets[i] = offset; + this.bitSizes[i] = size; + + if (this.maxBitSize < size) { + this.maxBitSize = size; + } + + } + + } + + @Override + public Object getDataElements(int x, int y, Object obj, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + switch (getTransferType()) { + case DataBuffer.TYPE_BYTE: + byte bdata[]; + if (obj == null) { + bdata = new byte[1]; + } else { + bdata = (byte[])obj; + } + + bdata[0] = (byte)data.getElem(y * scanlineStride + x); + obj = bdata; + break; + case DataBuffer.TYPE_USHORT: + short sdata[]; + if (obj == null) { + sdata = new short[1]; + } else { + sdata = (short[])obj; + } + + sdata[0] = (short)data.getElem(y * scanlineStride + x); + obj = sdata; + break; + case DataBuffer.TYPE_INT: + int idata[]; + if (obj == null) { + idata = new int[1]; + } else { + idata = (int[])obj; + } + + idata[0] = data.getElem(y * scanlineStride + x); + obj = idata; + break; + } + return obj; + } + + @Override + public void setDataElements(int x, int y, Object obj, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + switch (getTransferType()) { + case DataBuffer.TYPE_BYTE: + data.setElem(y * scanlineStride + x, ((byte[])obj)[0] & 0xff); + break; + case DataBuffer.TYPE_USHORT: + data.setElem(y * scanlineStride + x, ((short[])obj)[0] & 0xffff); + break; + case DataBuffer.TYPE_INT: + data.setElem(y * scanlineStride + x, ((int[])obj)[0]); + break; + } + } + + /** + * Compares this SinglePixelPackedSampleModel object with the specified + * object. + * + * @param o + * the Object to be compared. + * @return true, if this SinglePixelPackedSampleModel object is equal to the + * specified object, false otherwise. + */ + @Override + public boolean equals(Object o) { + if ((o == null) || !(o instanceof SinglePixelPackedSampleModel)) { + return false; + } + + SinglePixelPackedSampleModel model = (SinglePixelPackedSampleModel)o; + return this.width == model.width && this.height == model.height + && this.numBands == model.numBands && this.dataType == model.dataType + && Arrays.equals(this.bitMasks, model.bitMasks) + && Arrays.equals(this.bitOffsets, model.bitOffsets) + && Arrays.equals(this.bitSizes, model.bitSizes) + && this.scanlineStride == model.scanlineStride; + } + + @Override + public SampleModel createSubsetSampleModel(int bands[]) { + if (bands.length > this.numBands) { + // awt.64=The number of the bands in the subset is greater than the + // number of bands in the sample model + throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$ + } + + int masks[] = new int[bands.length]; + for (int i = 0; i < bands.length; i++) { + masks[i] = this.bitMasks[bands[i]]; + } + return new SinglePixelPackedSampleModel(this.dataType, this.width, this.height, + this.scanlineStride, masks); + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + return new SinglePixelPackedSampleModel(this.dataType, w, h, this.bitMasks); + } + + @Override + public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int pixel[]; + if (iArray == null) { + pixel = new int[this.numBands]; + } else { + pixel = iArray; + } + + for (int i = 0; i < this.numBands; i++) { + pixel[i] = getSample(x, y, i, data); + } + + return pixel; + } + + @Override + public void setPixel(int x, int y, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + for (int i = 0; i < this.numBands; i++) { + setSample(x, y, i, iArray[i], data); + } + } + + @Override + public int getSample(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int sample = data.getElem(y * scanlineStride + x); + return ((sample & this.bitMasks[b]) >>> this.bitOffsets[b]); + } + + @Override + public int[] getPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { + if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width) + || ((long)y + (long)h > this.height)) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + int pixels[]; + + if (iArray == null) { + pixels = new int[w * h * this.numBands]; + } else { + pixels = iArray; + } + + int idx = 0; + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < this.numBands; n++) { + pixels[idx++] = getSample(j, i, n, data); + } + } + } + return pixels; + } + + @Override + public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { + if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width) + || ((long)y + (long)h > this.height)) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + int idx = 0; + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < this.numBands; n++) { + setSample(j, i, n, iArray[idx++], data); + } + } + } + } + + @Override + public void setSample(int x, int y, int b, int s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int tmp = data.getElem(y * scanlineStride + x); + tmp &= ~this.bitMasks[b]; + tmp |= (s << this.bitOffsets[b]) & this.bitMasks[b]; + data.setElem(y * scanlineStride + x, tmp); + } + + @Override + public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { + if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width) + || ((long)y + (long)h > this.height)) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + int samples[]; + int idx = 0; + + if (iArray == null) { + samples = new int[w * h]; + } else { + samples = iArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + samples[idx++] = getSample(j, i, b, data); + } + } + + return samples; + } + + @Override + public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { + if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width) + || ((long)y + (long)h > this.height)) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + setSample(x + j, y + i, b, iArray[idx++], data); + } + } + } + + @Override + public DataBuffer createDataBuffer() { + DataBuffer data = null; + int size = (this.height - 1) * scanlineStride + width; + + switch (this.dataType) { + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(size); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(size); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(size); + break; + } + return data; + } + + /** + * Gets the offset of the specified pixel in the data array. + * + * @param x + * the X coordinate of the specified pixel. + * @param y + * the Y coordinate of the specified pixel. + * @return the offset of the specified pixel. + */ + public int getOffset(int x, int y) { + return (y * scanlineStride + x); + } + + @Override + public int getSampleSize(int band) { + return bitSizes[band]; + } + + @Override + public int[] getSampleSize() { + return bitSizes.clone(); + } + + /** + * Gets an array of the bit offsets of the data array elements. + * + * @return an array of the bit offsets. + */ + public int[] getBitOffsets() { + return bitOffsets.clone(); + } + + /** + * Gets an array of the bit masks for all bands. + * + * @return an array of the bit masks for all bands. + */ + public int[] getBitMasks() { + return bitMasks.clone(); + } + + /** + * Returns a hash code of this MultiPixelPackedSampleModel class. + * + * @return the hash code of this MultiPixelPackedSampleModel class. + */ + @Override + public int hashCode() { + int hash = 0; + int tmp = 0; + + hash = width; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= height; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= numBands; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= dataType; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + for (int element : bitMasks) { + hash ^= element; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + } + for (int element : bitOffsets) { + hash ^= element; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + } + for (int element : bitSizes) { + hash ^= element; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + } + hash ^= scanlineStride; + return hash; + } + + /** + * Gets the scanline stride. + * + * @return the scanline stride + */ + public int getScanlineStride() { + return this.scanlineStride; + } + + @Override + public int getNumDataElements() { + return 1; + } + +} diff --git a/awt/java/awt/image/TileObserver.java b/awt/java/awt/image/TileObserver.java new file mode 100644 index 0000000..7dd97e2 --- /dev/null +++ b/awt/java/awt/image/TileObserver.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +/** + * An asynchronous update interface for receiving notifications about tile + * information when tiles of a WritableRenderedImage become modifiable or + * unmodifiable. + * + * @since Android 1.0 + */ +public interface TileObserver { + + /** + * This method is called when information about a tile update is available. + * + * @param source + * the source image. + * @param tileX + * the X index of the tile. + * @param tileY + * the Y index of the tile. + * @param willBeWritable + * parameter which indicates whether the tile will be grabbed for + * writing or be released. + */ + public void tileUpdate(WritableRenderedImage source, int tileX, int tileY, + boolean willBeWritable); + +} diff --git a/awt/java/awt/image/VolatileImage.java b/awt/java/awt/image/VolatileImage.java new file mode 100644 index 0000000..f24e866 --- /dev/null +++ b/awt/java/awt/image/VolatileImage.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.ImageCapabilities; +import java.awt.Transparency; + +/** + * The VolatileImage abstract class represents an image which can lose its + * contents at any point. VolatileImage objects are device specific. This class + * provides methods for checking if operation of this image are compatible for + * the GraphicsConfiguration. + * + * @since Android 1.0 + */ +public abstract class VolatileImage extends Image +// Volatile image implements Transparency since 1.5 + implements Transparency { + + /** + * The Constant IMAGE_INCOMPATIBLE indicates that this VolatileImage is not + * applicable for the GraphicsConfiguration object. + */ + public static final int IMAGE_INCOMPATIBLE = 2; + + /** + * The Constant IMAGE_OK indicates that VolatileImage is ready for using. + */ + public static final int IMAGE_OK = 0; + + /** + * The Constant IMAGE_RESTORED indicates that VolatileImage will be ready to + * use after restoring. + */ + public static final int IMAGE_RESTORED = 1; + + /** + * The transparency value of this image. + */ + protected int transparency = OPAQUE; + + /** + * Instantiates a new VolatileImage object. + */ + public VolatileImage() { + super(); + } + + /** + * Returns true if rendering data is lost during validating. This method + * should be called after rendering operation of image. + * + * @return true, if contents lost during validating, false otherwise. + */ + + public abstract boolean contentsLost(); + + /** + * Creates a Graphics2D used to draw in this VolatileImage. + * + * @return the Graphics2D object. + */ + public abstract Graphics2D createGraphics(); + + /** + * Gets the ImageCapabilities of this VolatileImage. + * + * @return the ImageCapabilities of this VolatileImage. + */ + public abstract ImageCapabilities getCapabilities(); + + /** + * Gets the height of this VolatileImage. + * + * @return the height of this VolatileImage. + */ + public abstract int getHeight(); + + /** + * Gets a BufferedImage representation of current VolatileImage that won't + * be affected by any changes to this VolatileImage. + * + * @return a BufferedImage representation of current VolatileImage. + */ + public abstract BufferedImage getSnapshot(); + + /** + * Gets the width of this VolatileImage. + * + * @return the width of this VolatileImage. + */ + public abstract int getWidth(); + + /** + * Validates the drawing surface of the image if the surface had been lost + * and if the specified GraphicsConfiguration object is applicable to this + * image. + * + * @param gc + * the GraphicsConfiguration object. + * @return one of the image status constants: IMAGE_OK, IMAGE_RESTORED or + * IMAGE_INCOMPATIBLE. + */ + public abstract int validate(GraphicsConfiguration gc); + + @Override + public void flush() { + } + + @Override + public Graphics getGraphics() { + return createGraphics(); + } + + @Override + public ImageProducer getSource() { + return getSnapshot().getSource(); + } + + public int getTransparency() { + return transparency; + } +} diff --git a/awt/java/awt/image/WritableRaster.java b/awt/java/awt/image/WritableRaster.java new file mode 100644 index 0000000..51366ee --- /dev/null +++ b/awt/java/awt/image/WritableRaster.java @@ -0,0 +1,592 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.Point; +import java.awt.Rectangle; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The WritableRaster class provides functionality for writing samples and pixel + * capabilities to the Raster. + * + * @since Android 1.0 + */ +public class WritableRaster extends Raster { + + /** + * Instantiates a new WritableRaster object with the specified SampleModel, + * DataBuffer, rectangular region and parent WritableRaster. + * + * @param sampleModel + * the specified SampleModel. + * @param dataBuffer + * the specified DataBuffer. + * @param aRegion + * the rectangular region which defines the new image bounds. + * @param sampleModelTranslate + * this point defines the translation point from the SampleModel + * to the new WritableRaster coordinates. + * @param parent + * the parent of this WritableRaster. + */ + protected WritableRaster(SampleModel sampleModel, DataBuffer dataBuffer, Rectangle aRegion, + Point sampleModelTranslate, WritableRaster parent) { + super(sampleModel, dataBuffer, aRegion, sampleModelTranslate, parent); + } + + /** + * Instantiates a new WritableRaster object with the specified SampleModel + * which defines a layout of this WritableRaster and DataBuffer objects + * which defines the image data. + * + * @param sampleModel + * the specified SampleModel. + * @param dataBuffer + * the specified DataBuffer. + * @param origin + * the point of origin. + */ + protected WritableRaster(SampleModel sampleModel, DataBuffer dataBuffer, Point origin) { + this(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y, sampleModel.width, + sampleModel.height), origin, null); + } + + /** + * Instantiates a new WritableRaster with the specified SampleModel. + * + * @param sampleModel + * the specified SampleModel. + * @param origin + * the origin. + */ + protected WritableRaster(SampleModel sampleModel, Point origin) { + this(sampleModel, sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, + sampleModel.width, sampleModel.height), origin, null); + } + + /** + * Sets the data for a single pixel from an input Object which represents an + * array of primitive types: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or + * DataBuffer.TYPE_DOUBLE. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param inData + * the input data. + */ + public void setDataElements(int x, int y, Object inData) { + sampleModel.setDataElements(x - sampleModelTranslateX, y - sampleModelTranslateY, inData, + dataBuffer); + } + + /** + * Sets the data elements which represent pixel data to the specified + * rectangle area as a primitive array. The following image data types are + * supported: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or + * DataBuffer.TYPE_DOUBLE. + * + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param inData + * the array of primitive type data to be set to the specified + * area. + */ + public void setDataElements(int x, int y, int w, int h, Object inData) { + sampleModel.setDataElements(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + inData, dataBuffer); + } + + /** + * Creates the child of this WritableRaster by sharing the specified + * rectangular area in this WritableRaster. The parentX, parentY, width and + * height parameters specify rectangular area to be shared. + * + * @param parentX + * the X coordinate of the upper left corner of the shared + * rectangle with respect to this WritableRaster' coordinates. + * @param parentY + * the Y coordinate of the upper left corner of the shared + * rectangle with respect to this WritableRaster' coordinates. + * @param w + * the width of the child area. + * @param h + * the height of the child area. + * @param childMinX + * the X coordinate of child area mapped to the parentX + * coordinate. + * @param childMinY + * the Y coordinate of child area mapped to the parentY + * coordinate. + * @param bandList + * the array of band indices. + * @return the child WritableRaster. + */ + public WritableRaster createWritableChild(int parentX, int parentY, int w, int h, + int childMinX, int childMinY, int bandList[]) { + if (w <= 0 || h <= 0) { + // awt.244=Width or Height of child Raster is less than or equal to + // zero + throw new RasterFormatException(Messages.getString("awt.244")); //$NON-NLS-1$ + } + + if (parentX < this.minX || parentX + w > this.minX + this.width) { + // awt.245=parentX disposes outside Raster + throw new RasterFormatException(Messages.getString("awt.245")); //$NON-NLS-1$ + } + + if (parentY < this.minY || parentY + h > this.minY + this.height) { + // awt.246=parentY disposes outside Raster + throw new RasterFormatException(Messages.getString("awt.246")); //$NON-NLS-1$ + } + + if ((long)parentX + w > Integer.MAX_VALUE) { + // awt.247=parentX + w results in integer overflow + throw new RasterFormatException(Messages.getString("awt.247")); //$NON-NLS-1$ + } + + if ((long)parentY + h > Integer.MAX_VALUE) { + // awt.248=parentY + h results in integer overflow + throw new RasterFormatException(Messages.getString("awt.248")); //$NON-NLS-1$ + } + + if ((long)childMinX + w > Integer.MAX_VALUE) { + // awt.249=childMinX + w results in integer overflow + throw new RasterFormatException(Messages.getString("awt.249")); //$NON-NLS-1$ + } + + if ((long)childMinY + h > Integer.MAX_VALUE) { + // awt.24A=childMinY + h results in integer overflow + throw new RasterFormatException(Messages.getString("awt.24A")); //$NON-NLS-1$ + } + + SampleModel childModel; + + if (bandList == null) { + childModel = sampleModel; + } else { + childModel = sampleModel.createSubsetSampleModel(bandList); + } + + int childTranslateX = childMinX - parentX; + int childTranslateY = childMinY - parentY; + + return new WritableRaster(childModel, dataBuffer, + new Rectangle(childMinX, childMinY, w, h), new Point(childTranslateX + + sampleModelTranslateX, childTranslateY + sampleModelTranslateY), this); + } + + /** + * Creates the translated child of this WritableRaster. New WritableRaster + * object is a reference to the this WritableRaster and with different + * location. + * + * @param childMinX + * the X coordinate of the new WritableRaster. + * @param childMinY + * the Y coordinate of the new WritableRaster. + * @return the WritableRaster. + */ + public WritableRaster createWritableTranslatedChild(int childMinX, int childMinY) { + return createWritableChild(minX, minY, width, height, childMinX, childMinY, null); + } + + /** + * Gets the parent WritableRaster for this WritableRaster object. + * + * @return the parent WritableRaster for this WritableRaster object. + */ + public WritableRaster getWritableParent() { + return (WritableRaster)parent; + } + + /** + * Sets pixels from the specified source Raster srcRaster to this + * WritableRaster. + * + * @param srcRaster + * the source Raster. + */ + public void setRect(Raster srcRaster) { + setRect(0, 0, srcRaster); + } + + /** + * Sets pixels from the specified source Raster srcRaster to this + * WritableRaster. Each pixel with (x, y) coordinates from the source Raster + * is copied to pixel with (x+dx, y+dy) coordinates in this WritableRaster. + * The pixels with (x+dx, y+dy) coordinates which are out the bounds of this + * raster are ignored. + * + * @param dx + * the distance the pixel's X coordinate in the source Raster is + * translated when writtien to this WritableRaster. + * @param dy + * the distance the pixel's Y coordinate in the source Raster is + * translated when writtien to this WritableRaster. + * @param srcRaster + * the source Raster. + */ + public void setRect(int dx, int dy, Raster srcRaster) { + int w = srcRaster.getWidth(); + int h = srcRaster.getHeight(); + + int srcX = srcRaster.getMinX(); + int srcY = srcRaster.getMinY(); + + int dstX = srcX + dx; + int dstY = srcY + dy; + + if (dstX < this.minX) { + int minOffX = this.minX - dstX; + w -= minOffX; + dstX = this.minX; + srcX += minOffX; + } + + if (dstY < this.minY) { + int minOffY = this.minY - dstY; + h -= minOffY; + dstY = this.minY; + srcY += minOffY; + } + + if (dstX + w > this.minX + this.width) { + int maxOffX = (dstX + w) - (this.minX + this.width); + w -= maxOffX; + } + + if (dstY + h > this.minY + this.height) { + int maxOffY = (dstY + h) - (this.minY + this.height); + h -= maxOffY; + } + + if (w <= 0 || h <= 0) { + return; + } + + switch (sampleModel.getDataType()) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + int iPixelsLine[] = null; + for (int i = 0; i < h; i++) { + iPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1, iPixelsLine); + setPixels(dstX, dstY + i, w, 1, iPixelsLine); + } + break; + + case DataBuffer.TYPE_FLOAT: + float fPixelsLine[] = null; + for (int i = 0; i < h; i++) { + fPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1, fPixelsLine); + setPixels(dstX, dstY + i, w, 1, fPixelsLine); + } + break; + + case DataBuffer.TYPE_DOUBLE: + double dPixelsLine[] = null; + for (int i = 0; i < h; i++) { + dPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1, dPixelsLine); + setPixels(dstX, dstY + i, w, 1, dPixelsLine); + } + break; + } + } + + /** + * Sets the data for a rectangle of pixels from an input Raster to this + * WritableRaster. + * + * @param x + * the X coordinate of the point where the data of the input + * Raster is to be written. + * @param y + * the Y coordinate of the point where the data of the input + * Raster is to be written. + * @param inRaster + * the input Raster. + */ + public void setDataElements(int x, int y, Raster inRaster) { + int dstX = x + inRaster.getMinX(); + int dstY = y + inRaster.getMinY(); + + int w = inRaster.getWidth(); + int h = inRaster.getHeight(); + + if (dstX < this.minX || dstX + w > this.minX + this.width || dstY < this.minY + || dstY + h > this.minY + this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + int srcX = inRaster.getMinX(); + int srcY = inRaster.getMinY(); + Object line = null; + + for (int i = 0; i < h; i++) { + line = inRaster.getDataElements(srcX, srcY + i, w, 1, line); + setDataElements(dstX, dstY + i, w, 1, line); + } + } + + /** + * Sets an integer array of samples for the specified pixel in this + * WritableRaster. + * + * @param x + * the pixel's X coordinate. + * @param y + * the pixel's Y coordinate. + * @param iArray + * the integer array of samples. + */ + public void setPixel(int x, int y, int iArray[]) { + sampleModel.setPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, iArray, + dataBuffer); + } + + /** + * Sets a float array of samples for the specified pixel in this + * WritableRaster. + * + * @param x + * the pixel's X coordinate. + * @param y + * the pixel's Y coordinate. + * @param fArray + * the float array of samples. + */ + public void setPixel(int x, int y, float fArray[]) { + sampleModel.setPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, fArray, + dataBuffer); + } + + /** + * Sets a double array of samples for the specified pixel in this + * WritableRaster. + * + * @param x + * the pixel's X coordinate. + * @param y + * the pixel's Y coordinate. + * @param dArray + * the double array of samples. + */ + public void setPixel(int x, int y, double dArray[]) { + sampleModel.setPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, dArray, + dataBuffer); + } + + /** + * Sets a integer array of samples for the specified rectangular area of + * pixels in this WritableRaster. + * + * @param x + * the X coordinate of rectangular area. + * @param y + * the Y coordinate of rectangular area. + * @param w + * the width of rectangular area. + * @param h + * the height of rectangular area. + * @param iArray + * the integer array of samples. + */ + public void setPixels(int x, int y, int w, int h, int iArray[]) { + sampleModel.setPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, iArray, + dataBuffer); + } + + /** + * Sets a float array of samples for the specified rectangular area of + * pixels in this WritableRaster. + * + * @param x + * the X coordinate of rectangular area. + * @param y + * the Y coordinate of rectangular area. + * @param w + * the width of rectangular area. + * @param h + * the height of rectangular area. + * @param fArray + * the float array of samples. + */ + public void setPixels(int x, int y, int w, int h, float fArray[]) { + sampleModel.setPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, fArray, + dataBuffer); + } + + /** + * Sets a double array of samples for the specified rectangular area of + * pixels in this WritableRaster. + * + * @param x + * the X coordinate of rectangular area. + * @param y + * the Y coordinate of rectangular area. + * @param w + * the width of rectangular area. + * @param h + * the height of rectangular area. + * @param dArray + * the double array of samples. + */ + public void setPixels(int x, int y, int w, int h, double dArray[]) { + sampleModel.setPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, dArray, + dataBuffer); + } + + /** + * Sets the samples for the specified band and the specified rectangular + * area of pixels with an integer array of samples. + * + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of the area of pixels. + * @param h + * the height of the area of pixels. + * @param b + * the specified band. + * @param iArray + * the integer array of samples. + */ + public void setSamples(int x, int y, int w, int h, int b, int iArray[]) { + sampleModel.setSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, b, + iArray, dataBuffer); + } + + /** + * Sets the samples for the specified band and the specified rectangular + * area of pixels with a float array of samples. + * + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of the area of pixels. + * @param h + * the height of the area of pixels. + * @param b + * the specified band. + * @param fArray + * the float array of samples. + */ + public void setSamples(int x, int y, int w, int h, int b, float fArray[]) { + sampleModel.setSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, b, + fArray, dataBuffer); + } + + /** + * Sets the samples for the specified band and the specified rectangular + * area of pixels with a double array of samples. + * + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of the area of pixels. + * @param h + * the height of the area of pixels. + * @param b + * the specified band. + * @param dArray + * the double array of samples. + */ + public void setSamples(int x, int y, int w, int h, int b, double dArray[]) { + sampleModel.setSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, b, + dArray, dataBuffer); + } + + /** + * Sets the sample for the specified band and the specified pixel with an + * integer sample. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the specified band. + * @param s + * the sample to be set. + */ + public void setSample(int x, int y, int b, int s) { + sampleModel.setSample(x - sampleModelTranslateX, y - sampleModelTranslateY, b, s, + dataBuffer); + } + + /** + * Sets the sample for the specified band and the specified pixel with a + * float sample. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the specified band. + * @param s + * the sample to be set. + */ + public void setSample(int x, int y, int b, float s) { + sampleModel.setSample(x - sampleModelTranslateX, y - sampleModelTranslateY, b, s, + dataBuffer); + } + + /** + * Sets the sample for the specified band and the specified pixel with an + * integer sample. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the specified band. + * @param s + * the sample to be set. + */ + public void setSample(int x, int y, int b, double s) { + sampleModel.setSample(x - sampleModelTranslateX, y - sampleModelTranslateY, b, s, + dataBuffer); + } + +} diff --git a/awt/java/awt/image/WritableRenderedImage.java b/awt/java/awt/image/WritableRenderedImage.java new file mode 100644 index 0000000..052353b --- /dev/null +++ b/awt/java/awt/image/WritableRenderedImage.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.Point; + +/** + * The WriteableRenderedImage interface is interface for objects which contains + * Raster data of one or several tiles. This interface provides notification + * mechanism for obtaining tile's writing status. + * + * @since Android 1.0 + */ +public interface WritableRenderedImage extends RenderedImage { + + /** + * Gets and checks out the writable tile for writing. + * + * @param tileX + * the X index of the tile. + * @param tileY + * the Y index of the tile. + * @return the WritableRaster. + */ + public WritableRaster getWritableTile(int tileX, int tileY); + + /** + * Removes the registered TileObserver. + * + * @param to + * the TileObserver which is registered for this + * WritableRenderedImage. + */ + public void removeTileObserver(TileObserver to); + + /** + * Adds the specified TileObserver to this WritableRenderedImage. + * + * @param to + * the TileObserver object to be added. + */ + public void addTileObserver(TileObserver to); + + /** + * Sets this image to the contents of the specified Raster. + * + * @param r + * the specified Raster. + */ + public void setData(Raster r); + + /** + * Gets the array of points which represent indices of tiles which are check + * out for writing. + * + * @return the array of points. + */ + public Point[] getWritableTileIndices(); + + /** + * Checks if the specified tile is writable or not. + * + * @param tileX + * the X index of tile. + * @param tileY + * the Y index of tile. + * @return true, if the specified tile is writable, false otherwise. + */ + public boolean isTileWritable(int tileX, int tileY); + + /** + * Release the specified writable tile. This method removes the writer from + * the tile. + * + * @param tileX + * the X index of the tile. + * @param tileY + * the Y index of the tile. + */ + public void releaseWritableTile(int tileX, int tileY); + + /** + * Checks if there is a tile which is checked out for writing. + * + * @return true, if any tile is checked out for writing, false if there is + * no such tile. + */ + public boolean hasTileWriters(); + +} diff --git a/awt/java/awt/image/package.html b/awt/java/awt/image/package.html new file mode 100644 index 0000000..b4d6ef0 --- /dev/null +++ b/awt/java/awt/image/package.html @@ -0,0 +1,8 @@ +<html> + <body> + <p> + This package contains classes and interfaces that allow to modify existing images or to create a new image rather than loading it from a file. + </p> + @since Android 1.0 + </body> +</html> diff --git a/awt/java/awt/image/renderable/ContextualRenderedImageFactory.java b/awt/java/awt/image/renderable/ContextualRenderedImageFactory.java new file mode 100644 index 0000000..1881a0c --- /dev/null +++ b/awt/java/awt/image/renderable/ContextualRenderedImageFactory.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image.renderable; + +import java.awt.geom.Rectangle2D; +import java.awt.image.RenderedImage; + +/** + * A factory for creating ContextualRenderedImage objects with utilities for + * manipulating the properties in the parameter block. + * + * @since Android 1.0 + */ +public interface ContextualRenderedImageFactory extends RenderedImageFactory { + + /** + * Maps a render context to a parameter block and a renderable image. + * + * @param a0 + * the index. + * @param a1 + * the RenderContext. + * @param a2 + * the ParameterBlock. + * @param a3 + * the RenderableImage. + * @return the render context. + */ + public RenderContext mapRenderContext(int a0, RenderContext a1, ParameterBlock a2, + RenderableImage a3); + + /** + * Gets the value of the property from the parameter block. + * + * @param a0 + * the parameter block to examine to find the property. + * @param a1 + * the name of the property. + * @return the value of the property. + */ + public Object getProperty(ParameterBlock a0, String a1); + + /** + * Creates the rendered image determined by the render context and parameter + * block. + * + * @param a0 + * the RenderContext. + * @param a1 + * the ParameterBlock. + * @return the rendered image. + */ + public RenderedImage create(RenderContext a0, ParameterBlock a1); + + /** + * Gets the bounding rectangle from the parameter block. + * + * @param a0 + * the parameter block to read the bounds from. + * @return the bounding rectangle. + */ + public Rectangle2D getBounds2D(ParameterBlock a0); + + /** + * Gets the names of all of the supported properties. + * + * @return the property names. + */ + public String[] getPropertyNames(); + + /** + * Checks if this image factory is dynamic. + * + * @return true, if this image factory is dynamic. + */ + public boolean isDynamic(); + +} diff --git a/awt/java/awt/image/renderable/ParameterBlock.java b/awt/java/awt/image/renderable/ParameterBlock.java new file mode 100644 index 0000000..7dde73a --- /dev/null +++ b/awt/java/awt/image/renderable/ParameterBlock.java @@ -0,0 +1,568 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image.renderable; + +import java.awt.image.RenderedImage; +import java.io.Serializable; +import java.util.Vector; + +/** + * The class ParameterBlock groups an indexed set of parameter data with a set + * of renderable (source) images. The mapping between the indexed parameters and + * their property names is provided by a {@link ContextualRenderedImageFactory}. + * + * @since Android 1.0 + */ +public class ParameterBlock implements Cloneable, Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -7577115551785240750L; + + /** + * The sources (renderable images). + */ + protected Vector<Object> sources = new Vector<Object>(); + + /** + * The parameters. + */ + protected Vector<Object> parameters = new Vector<Object>(); + + /** + * Instantiates a new parameter block. + * + * @param sources + * the vector of source images. + * @param parameters + * the vector of parameters. + */ + public ParameterBlock(Vector<Object> sources, Vector<Object> parameters) { + setSources(sources); + setParameters(parameters); + } + + /** + * Instantiates a new parameter block with no parameters. + * + * @param sources + * the vector of source images. + */ + public ParameterBlock(Vector<Object> sources) { + setSources(sources); + } + + /** + * Instantiates a new parameter block with no image or parameter vectors. + */ + public ParameterBlock() { + } + + /** + * Sets the source image at the specified index. + * + * @param source + * the source image. + * @param index + * the index where the source will be placed. + * @return this parameter block. + */ + public ParameterBlock setSource(Object source, int index) { + if (sources.size() < index + 1) { + sources.setSize(index + 1); + } + sources.setElementAt(source, index); + return this; + } + + /** + * Sets the parameter value object at the specified index. + * + * @param obj + * the parameter value to place at the desired index. + * @param index + * the index where the object is to be placed in the vector of + * parameters. + * @return this parameter block. + */ + public ParameterBlock set(Object obj, int index) { + if (parameters.size() < index + 1) { + parameters.setSize(index + 1); + } + parameters.setElementAt(obj, index); + return this; + } + + /** + * Adds a source to the vector of sources. + * + * @param source + * the source to add. + * @return this parameter block. + */ + public ParameterBlock addSource(Object source) { + sources.addElement(source); + return this; + } + + /** + * Adds the object to the vector of parameter values + * + * @param obj + * the obj to add. + * @return this parameter block. + */ + public ParameterBlock add(Object obj) { + parameters.addElement(obj); + return this; + } + + /** + * Sets the vector of sources, replacing the existing vector of sources, if + * any. + * + * @param sources + * the new sources. + */ + public void setSources(Vector<Object> sources) { + this.sources = sources; + } + + /** + * Sets the vector of parameters, replacing the existing vector of + * parameters, if any. + * + * @param parameters + * the new parameters. + */ + public void setParameters(Vector<Object> parameters) { + this.parameters = parameters; + } + + /** + * Gets the vector of sources. + * + * @return the sources. + */ + public Vector<Object> getSources() { + return sources; + } + + /** + * Gets the vector of parameters. + * + * @return the parameters. + */ + public Vector<Object> getParameters() { + return parameters; + } + + /** + * Gets the source at the specified index. + * + * @param index + * the index. + * @return the source object found at the specified index. + */ + public Object getSource(int index) { + return sources.elementAt(index); + } + + /** + * Gets the object parameter found at the specified index. + * + * @param index + * the index. + * @return the parameter object found at the specified index. + */ + public Object getObjectParameter(int index) { + return parameters.elementAt(index); + } + + /** + * Shallow clone (clones using the superclass clone method). + * + * @return the clone of this object. + */ + public Object shallowClone() { + try { + return super.clone(); + } catch (Exception e) { + return null; + } + } + + /** + * Returns a copy of this ParameterBlock instance. + * + * @return the identical copy of this instance. + */ + @SuppressWarnings("unchecked") + @Override + public Object clone() { + ParameterBlock replica; + try { + replica = (ParameterBlock)super.clone(); + } catch (Exception e) { + return null; + } + if (sources != null) { + replica.setSources((Vector<Object>)(sources.clone())); + } + if (parameters != null) { + replica.setParameters((Vector<Object>)(parameters.clone())); + } + return replica; + } + + /** + * Gets an array of classes corresponding to all of the parameter values + * found in the array of parameters, in order. + * + * @return the parameter classes. + */ + public Class[] getParamClasses() { + int count = parameters.size(); + Class paramClasses[] = new Class[count]; + + for (int i = 0; i < count; i++) { + paramClasses[i] = parameters.elementAt(i).getClass(); + } + return paramClasses; + } + + /** + * Gets the renderable source image found at the specified index in the + * source array. + * + * @param index + * the index. + * @return the renderable source image. + */ + public RenderableImage getRenderableSource(int index) { + return (RenderableImage)sources.elementAt(index); + } + + /** + * Wraps the short value in a Short and places it in the parameter block at + * the specified index. + * + * @param s + * the short value of the parameter. + * @param index + * the index. + * @return this parameter block. + */ + public ParameterBlock set(short s, int index) { + return set(new Short(s), index); + } + + /** + * Wraps the short value in a Short and adds it to the parameter block. + * + * @param s + * the short value of the parameter. + * @return this parameter block. + */ + public ParameterBlock add(short s) { + return add(new Short(s)); + } + + /** + * Wraps the long value in a Long and places it in the parameter block at + * the specified index. + * + * @param l + * the long value of the parameter. + * @param index + * the index. + * @return this parameter block. + */ + public ParameterBlock set(long l, int index) { + return set(new Long(l), index); + } + + /** + * Wraps the long value in a Long and adds it to the parameter block. + * + * @param l + * the long value of the parameter. + * @return this parameter block. + */ + public ParameterBlock add(long l) { + return add(new Long(l)); + } + + /** + * Wraps the integer value in an Integer and places it in the parameter + * block at the specified index. + * + * @param i + * the integer value of the parameter. + * @param index + * the index. + * @return this parameter block. + */ + public ParameterBlock set(int i, int index) { + return set(new Integer(i), index); + } + + /** + * Wraps the integer value in an Integer and adds it to the parameter block. + * + * @param i + * the integer value of the parameter. + * @return this parameter block. + */ + public ParameterBlock add(int i) { + return add(new Integer(i)); + } + + /** + * Wraps the float value in a Float and places it in the parameter block at + * the specified index. + * + * @param f + * the float value of the parameter. + * @param index + * the index. + * @return this parameter block. + */ + public ParameterBlock set(float f, int index) { + return set(new Float(f), index); + } + + /** + * Wraps the float value in a Float and adds it to the parameter block. + * + * @param f + * the float value of the parameter. + * @return this parameter block. + */ + public ParameterBlock add(float f) { + return add(new Float(f)); + } + + /** + * Wraps the double value in a Double and places it in the parameter block + * at the specified index. + * + * @param d + * the double value of the parameter. + * @param index + * the index. + * @return this parameter block. + */ + public ParameterBlock set(double d, int index) { + return set(new Double(d), index); + } + + /** + * Wraps the double value in a Double and adds it to the parameter block. + * + * @param d + * the double value of the parameter. + * @return this parameter block. + */ + public ParameterBlock add(double d) { + return add(new Double(d)); + } + + /** + * Wraps the char value in a Character and places it in the parameter block + * at the specified index. + * + * @param c + * the char value of the parameter. + * @param index + * the index. + * @return this parameter block. + */ + public ParameterBlock set(char c, int index) { + return set(new Character(c), index); + } + + /** + * Wraps the char value in a Character and adds it to the parameter block. + * + * @param c + * the char value of the parameter. + * @return this parameter block. + */ + public ParameterBlock add(char c) { + return add(new Character(c)); + } + + /** + * Wraps the byte value in a Byte and places it in the parameter block at + * the specified index. + * + * @param b + * the byte value of the parameter. + * @param index + * the index. + * @return this parameter block. + */ + public ParameterBlock set(byte b, int index) { + return set(new Byte(b), index); + } + + /** + * Wraps the byte value in a Byte and adds it to the parameter block. + * + * @param b + * the byte value of the parameter. + * @return the parameter block. + */ + public ParameterBlock add(byte b) { + return add(new Byte(b)); + } + + /** + * Gets the RenderedImage at the specified index from the vector of source + * images. + * + * @param index + * the index. + * @return the rendered image. + */ + public RenderedImage getRenderedSource(int index) { + return (RenderedImage)sources.elementAt(index); + } + + /** + * Gets the short-valued parameter found at the desired index in the vector + * of parameter values. + * + * @param index + * the index. + * @return the short parameter. + */ + public short getShortParameter(int index) { + return ((Short)parameters.elementAt(index)).shortValue(); + } + + /** + * Gets the long-valued parameter found at the desired index in the vector + * of parameter values. + * + * @param index + * the index. + * @return the long parameter. + */ + public long getLongParameter(int index) { + return ((Long)parameters.elementAt(index)).longValue(); + } + + /** + * Gets the integer-valued parameter found at the desired index in the + * vector of parameter values. + * + * @param index + * the index. + * @return the integer parameter. + */ + public int getIntParameter(int index) { + return ((Integer)parameters.elementAt(index)).intValue(); + } + + /** + * Gets the float-valued parameter found at the desired index in the vector + * of parameter values. + * + * @param index + * the index. + * @return the float parameter. + */ + public float getFloatParameter(int index) { + return ((Float)parameters.elementAt(index)).floatValue(); + } + + /** + * Gets the double-valued parameter found at the desired index in the vector + * of parameter values. + * + * @param index + * the index. + * @return the double parameter. + */ + public double getDoubleParameter(int index) { + return ((Double)parameters.elementAt(index)).doubleValue(); + } + + /** + * Gets the char-valued parameter found at the desired index in the vector + * of parameter values. + * + * @param index + * the index. + * @return the char parameter. + */ + public char getCharParameter(int index) { + return ((Character)parameters.elementAt(index)).charValue(); + } + + /** + * Gets the byte-valued parameter found at the desired index in the vector + * of parameter values. + * + * @param index + * the index. + * @return the byte parameter. + */ + public byte getByteParameter(int index) { + return ((Byte)parameters.elementAt(index)).byteValue(); + } + + /** + * Clears the vector of sources. + */ + public void removeSources() { + sources.removeAllElements(); + } + + /** + * Clears the vector of parameters. + */ + public void removeParameters() { + parameters.removeAllElements(); + } + + /** + * Gets the number of elements in the vector of sources. + * + * @return the number of elements in the vector of sources. + */ + public int getNumSources() { + return sources.size(); + } + + /** + * Gets the number of elements in the vector of parameters. + * + * @return the number of elements in the vector of parameters. + */ + public int getNumParameters() { + return parameters.size(); + } +} diff --git a/awt/java/awt/image/renderable/RenderContext.java b/awt/java/awt/image/renderable/RenderContext.java new file mode 100644 index 0000000..0db512f --- /dev/null +++ b/awt/java/awt/image/renderable/RenderContext.java @@ -0,0 +1,214 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image.renderable; + +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.geom.AffineTransform; + +/** + * The Class RenderContext stores data on how an image is to be rendered: the + * affine transform, the area of interest, and the rendering hints. + * + * @since Android 1.0 + */ +public class RenderContext implements Cloneable { + + /** + * The affine transform. + */ + AffineTransform transform; + + /** + * The area of interest. + */ + Shape aoi; + + /** + * The rendering hints. + */ + RenderingHints hints; + + /** + * Instantiates a new render context. + * + * @param usr2dev + * the affine transform. + * @param aoi + * the area of interest. + * @param hints + * the rendering hints. + */ + public RenderContext(AffineTransform usr2dev, Shape aoi, RenderingHints hints) { + this.transform = (AffineTransform)usr2dev.clone(); + this.aoi = aoi; + this.hints = hints; + } + + /** + * Instantiates a new render context with no specified hints. + * + * @param usr2dev + * the affine transform. + * @param aoi + * the area of interest. + */ + public RenderContext(AffineTransform usr2dev, Shape aoi) { + this(usr2dev, aoi, null); + } + + /** + * Instantiates a new render context with no specified area of interest. + * + * @param usr2dev + * the affine transform. + * @param hints + * the rendering hints. + */ + public RenderContext(AffineTransform usr2dev, RenderingHints hints) { + this(usr2dev, null, hints); + } + + /** + * Instantiates a new render context with no rendering hints or area of + * interest. + * + * @param usr2dev + * the affine transform. + */ + public RenderContext(AffineTransform usr2dev) { + this(usr2dev, null, null); + } + + @Override + public Object clone() { + return new RenderContext(transform, aoi, hints); + } + + /** + * Sets the affine transform for this render context. + * + * @param newTransform + * the new affine transform. + */ + public void setTransform(AffineTransform newTransform) { + transform = (AffineTransform)newTransform.clone(); + } + + /** + * Concatenates the current transform with the specified transform (so they + * are applied with the specified transform acting first) and sets the + * resulting transform as the affine transform of this rendering context. + * + * @param modTransform + * the new transform which modifies the current transform. + * @deprecated use + * {@link RenderContext#preConcatenateTransform(AffineTransform)} + * . + */ + @Deprecated + public void preConcetenateTransform(AffineTransform modTransform) { + preConcatenateTransform(modTransform); + } + + /** + * Concatenates the current transform with the specified transform (so they + * are applied with the specified transform acting first) and sets the + * resulting transform as the affine transform of this rendering context. + * + * @param modTransform + * the new transform which modifies the current transform. + */ + public void preConcatenateTransform(AffineTransform modTransform) { + transform.preConcatenate(modTransform); + } + + /** + * Concatenate the specified transform with the current transform. + * + * @param modTransform + * the new transform which modifies the current transform. + * @deprecated use + * {@link RenderContext#concatenateTransform(AffineTransform)}. + */ + @Deprecated + public void concetenateTransform(AffineTransform modTransform) { + concatenateTransform(modTransform); + } + + /** + * Concatenate the specified transform with the current transform. + * + * @param modTransform + * the new transform which modifies the current transform. + */ + public void concatenateTransform(AffineTransform modTransform) { + transform.concatenate(modTransform); + } + + /** + * Gets the transform. + * + * @return the transform. + */ + public AffineTransform getTransform() { + return (AffineTransform)transform.clone(); + } + + /** + * Sets the area of interest. + * + * @param newAoi + * the new area of interest. + */ + public void setAreaOfInterest(Shape newAoi) { + aoi = newAoi; + } + + /** + * Gets the area of interest. + * + * @return the area of interest. + */ + public Shape getAreaOfInterest() { + return aoi; + } + + /** + * Sets the rendering hints. + * + * @param hints + * the new rendering hints. + */ + public void setRenderingHints(RenderingHints hints) { + this.hints = hints; + } + + /** + * Gets the rendering hints. + * + * @return the rendering hints. + */ + public RenderingHints getRenderingHints() { + return hints; + } +} diff --git a/awt/java/awt/image/renderable/RenderableImage.java b/awt/java/awt/image/renderable/RenderableImage.java new file mode 100644 index 0000000..21332f7 --- /dev/null +++ b/awt/java/awt/image/renderable/RenderableImage.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image.renderable; + +import java.awt.RenderingHints; +import java.awt.image.RenderedImage; +import java.util.Vector; + +/** + * The Interface RenderableImage is implemented by an object that collects all + * of the image-specific data that defines a single image that could be rendered + * to different rendering targets. + * + * @since Android 1.0 + */ +public interface RenderableImage { + + /** + * The Constant HINTS_OBSERVED indicates that the rendering hints are + * applied rather than ignored. + */ + public static final String HINTS_OBSERVED = "HINTS_OBSERVED"; //$NON-NLS-1$ + + /** + * Gets the property from the RenderableImage's parameter block. + * + * @param name + * the name of the property to get. + * @return the value of the property. + */ + public Object getProperty(String name); + + /** + * Creates the rendered image based on the information contained in the + * parameters and the render context. + * + * @param renderContext + * the render context giving rendering specifications such as + * transformations. + * @return the rendered image. + */ + public RenderedImage createRendering(RenderContext renderContext); + + /** + * Creates the scaled rendered image based on the information contained in + * the parameters and the render context. + * + * @param w + * the desired width after scaling or zero if the scaling should + * be proportional, based on the height. + * @param h + * the desired height after scaling or zero if the scaling should + * be proportional, based on the width. + * @param hints + * the rendering hints to use. + * @return the rendered image. + * @throws IllegalArgumentException + * if both the height and width are zero. + */ + public RenderedImage createScaledRendering(int w, int h, RenderingHints hints); + + /** + * Gets the vector of sources from the parameter block. + * + * @return the sources. + */ + public Vector<RenderableImage> getSources(); + + /** + * Gets the names of all of the supported properties in the current context. + * + * @return the property names. + */ + public String[] getPropertyNames(); + + /** + * Creates the default rendering (using the identity transform and default + * render context). + * + * @return the rendered image. + */ + public RenderedImage createDefaultRendering(); + + /** + * Checks if this context supports dynamic rendering. + * + * @return true, if this context supports dynamic rendering. + */ + public boolean isDynamic(); + + /** + * Gets the width of the image. + * + * @return the width of the image. + */ + public float getWidth(); + + /** + * Gets the y coordinate of the upper left corner. + * + * @return the y coordinate of the upper left corner. + */ + public float getMinY(); + + /** + * Gets the x coordinate of the upper left corner. + * + * @return the x coordinate of the upper left corner. + */ + public float getMinX(); + + /** + * Gets the height of the image. + * + * @return the height of the image. + */ + public float getHeight(); + +} diff --git a/awt/java/awt/image/renderable/RenderableImageOp.java b/awt/java/awt/image/renderable/RenderableImageOp.java new file mode 100644 index 0000000..dc45372 --- /dev/null +++ b/awt/java/awt/image/renderable/RenderableImageOp.java @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image.renderable; + +import java.awt.RenderingHints; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.RenderedImage; +import java.util.Vector; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class RenderableImageOp is a basic implementation of RenderableImage, + * with methods to access the parameter data and perform rendering operations. + * + * @since Android 1.0 + */ +public class RenderableImageOp implements RenderableImage { + + /** + * The CRIF. + */ + ContextualRenderedImageFactory CRIF; + + /** + * The param block. + */ + ParameterBlock paramBlock; + + /** + * The height. + */ + float minX, minY, width, height; + + /** + * Instantiates a new renderable image op. + * + * @param CRIF + * the cRIF. + * @param paramBlock + * the param block. + */ + public RenderableImageOp(ContextualRenderedImageFactory CRIF, ParameterBlock paramBlock) { + this.CRIF = CRIF; + this.paramBlock = (ParameterBlock)paramBlock.clone(); + Rectangle2D r = CRIF.getBounds2D(paramBlock); + minX = (float)r.getMinX(); + minY = (float)r.getMinY(); + width = (float)r.getWidth(); + height = (float)r.getHeight(); + } + + public Object getProperty(String name) { + return CRIF.getProperty(paramBlock, name); + } + + /** + * Sets the parameter block. + * + * @param paramBlock + * the param block. + * @return the parameter block. + */ + public ParameterBlock setParameterBlock(ParameterBlock paramBlock) { + ParameterBlock oldParam = this.paramBlock; + this.paramBlock = (ParameterBlock)paramBlock.clone(); + return oldParam; + } + + public RenderedImage createRendering(RenderContext renderContext) { + + Vector<RenderableImage> sources = getSources(); + ParameterBlock rdParam = (ParameterBlock)paramBlock.clone(); + + if (sources != null) { + Vector<Object> rdSources = new Vector<Object>(); + int i = 0; + while (i < sources.size()) { + RenderContext newContext = CRIF + .mapRenderContext(i, renderContext, paramBlock, this); + RenderedImage rdim = sources.elementAt(i).createRendering(newContext); + + if (rdim != null) { + rdSources.addElement(rdim); + } + i++; + } + if (rdSources.size() > 0) { + rdParam.setSources(rdSources); + } + } + return CRIF.create(renderContext, rdParam); + } + + public RenderedImage createScaledRendering(int w, int h, RenderingHints hints) { + if (w == 0 && h == 0) { + // awt.60=Width and Height mustn't be equal zero both + throw new IllegalArgumentException(Messages.getString("awt.60")); //$NON-NLS-1$ + } + if (w == 0) { + w = Math.round(h * (getWidth() / getHeight())); + } + + if (h == 0) { + h = Math.round(w * (getHeight() / getWidth())); + } + + double sx = (double)w / getWidth(); + double sy = (double)h / getHeight(); + + AffineTransform at = AffineTransform.getScaleInstance(sx, sy); + RenderContext context = new RenderContext(at, hints); + return createRendering(context); + } + + public Vector<RenderableImage> getSources() { + if (paramBlock.getNumSources() == 0) { + return null; + } + Vector<RenderableImage> v = new Vector<RenderableImage>(); + int i = 0; + while (i < paramBlock.getNumSources()) { + Object o = paramBlock.getSource(i); + if (o instanceof RenderableImage) { + v.addElement((RenderableImage)o); + } + i++; + } + return v; + } + + public String[] getPropertyNames() { + return CRIF.getPropertyNames(); + } + + /** + * Gets the parameter block. + * + * @return the parameter block + */ + public ParameterBlock getParameterBlock() { + return paramBlock; + } + + public RenderedImage createDefaultRendering() { + AffineTransform at = new AffineTransform(); + RenderContext context = new RenderContext(at); + return createRendering(context); + } + + public boolean isDynamic() { + return CRIF.isDynamic(); + } + + public float getWidth() { + return width; + } + + public float getMinY() { + return minY; + } + + public float getMinX() { + return minX; + } + + public float getHeight() { + return height; + } + +} diff --git a/awt/java/awt/image/renderable/RenderableImageProducer.java b/awt/java/awt/image/renderable/RenderableImageProducer.java new file mode 100644 index 0000000..e83ebc7 --- /dev/null +++ b/awt/java/awt/image/renderable/RenderableImageProducer.java @@ -0,0 +1,151 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image.renderable; + +import java.awt.image.ColorModel; +import java.awt.image.ImageConsumer; +import java.awt.image.ImageProducer; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.util.Vector; + +/** + * The Class RenderableImageProducer provides the implementation for the image + * rendering. + * + * @since Android 1.0 + */ +public class RenderableImageProducer implements ImageProducer, Runnable { + + /** + * The rbl. + */ + RenderableImage rbl; + + /** + * The rc. + */ + RenderContext rc; + + /** + * The consumers. + */ + Vector<ImageConsumer> consumers = new Vector<ImageConsumer>(); + + /** + * Instantiates a new renderable image producer. + * + * @param rdblImage + * the rdbl image. + * @param rc + * the rc. + */ + public RenderableImageProducer(RenderableImage rdblImage, RenderContext rc) { + this.rbl = rdblImage; + this.rc = rc; + } + + /** + * Sets the render context. + * + * @param rc + * the new render context. + */ + public synchronized void setRenderContext(RenderContext rc) { + this.rc = rc; + } + + public synchronized boolean isConsumer(ImageConsumer ic) { + return consumers.contains(ic); + } + + public synchronized void startProduction(ImageConsumer ic) { + addConsumer(ic); + Thread t = new Thread(this, "RenderableImageProducer thread"); //$NON-NLS-1$ + t.start(); + } + + public void requestTopDownLeftRightResend(ImageConsumer ic) { + } + + public synchronized void removeConsumer(ImageConsumer ic) { + if (ic != null) { + consumers.removeElement(ic); + } + } + + public synchronized void addConsumer(ImageConsumer ic) { + if (ic != null && !consumers.contains(ic)) { + consumers.addElement(ic); + } + } + + /** + * Creates the rendered image in a new thread. + */ + public void run() { + if (rbl == null) { + return; + } + + RenderedImage rd; + if (rc != null) { + rd = rbl.createRendering(rc); + } else { + rd = rbl.createDefaultRendering(); + } + + ColorModel cm = rd.getColorModel(); + if (cm == null) { + cm = ColorModel.getRGBdefault(); + } + + Raster r = rd.getData(); + int w = r.getWidth(); + int h = r.getHeight(); + + for (ImageConsumer c : consumers) { + c.setDimensions(w, h); + c.setHints(ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES + | ImageConsumer.SINGLEFRAME | ImageConsumer.SINGLEPASS); + } + + int scanLine[] = new int[w]; + int pixel[] = null; + + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + pixel = r.getPixel(x, y, pixel); + scanLine[x] = cm.getDataElement(pixel, 0); + } + + for (ImageConsumer c : consumers) { + c.setPixels(0, y, w, 1, cm, scanLine, 0, w); + } + } + + for (ImageConsumer c : consumers) { + c.imageComplete(ImageConsumer.STATICIMAGEDONE); + } + } + +} diff --git a/awt/java/awt/image/renderable/RenderedImageFactory.java b/awt/java/awt/image/renderable/RenderedImageFactory.java new file mode 100644 index 0000000..881a40a --- /dev/null +++ b/awt/java/awt/image/renderable/RenderedImageFactory.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image.renderable; + +import java.awt.RenderingHints; +import java.awt.image.RenderedImage; + +/** + * A factory for creating RenderedImage objects based on parameters and + * rendering hints. + * + * @since Android 1.0 + */ +public interface RenderedImageFactory { + + /** + * Creates the rendered image. + * + * @param a0 + * the ParameterBlock. + * @param a1 + * the RenderingHints. + * @return the rendered image. + */ + public RenderedImage create(ParameterBlock a0, RenderingHints a1); + +} diff --git a/awt/java/awt/image/renderable/package.html b/awt/java/awt/image/renderable/package.html new file mode 100644 index 0000000..43aaabc --- /dev/null +++ b/awt/java/awt/image/renderable/package.html @@ -0,0 +1,8 @@ +<html> + <body> + <p> + This package contains classes to create images which are rendering-independent. + </p> + @since Android 1.0 + </body> +</html> diff --git a/awt/java/awt/package.html b/awt/java/awt/package.html new file mode 100644 index 0000000..5a6f9f0 --- /dev/null +++ b/awt/java/awt/package.html @@ -0,0 +1,8 @@ +<html> + <body> + <p> + This package contains classes and interfaces for creating (graphical) user interfaces (GUI), painting 2D graphics and creating, manipulating and drawing images. + </p> + @since Android 1.0 + </body> +</html> diff --git a/awt/java/awt/peer/ButtonPeer.java b/awt/java/awt/peer/ButtonPeer.java new file mode 100644 index 0000000..cc45b49 --- /dev/null +++ b/awt/java/awt/peer/ButtonPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface ButtonPeer { + +} diff --git a/awt/java/awt/peer/CanvasPeer.java b/awt/java/awt/peer/CanvasPeer.java new file mode 100644 index 0000000..e276366 --- /dev/null +++ b/awt/java/awt/peer/CanvasPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface CanvasPeer { + +} diff --git a/awt/java/awt/peer/CheckboxMenuItemPeer.java b/awt/java/awt/peer/CheckboxMenuItemPeer.java new file mode 100644 index 0000000..296f422 --- /dev/null +++ b/awt/java/awt/peer/CheckboxMenuItemPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface CheckboxMenuItemPeer { + +} diff --git a/awt/java/awt/peer/CheckboxPeer.java b/awt/java/awt/peer/CheckboxPeer.java new file mode 100644 index 0000000..e9f8dd1 --- /dev/null +++ b/awt/java/awt/peer/CheckboxPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface CheckboxPeer { + +} diff --git a/awt/java/awt/peer/ChoicePeer.java b/awt/java/awt/peer/ChoicePeer.java new file mode 100644 index 0000000..57b7629 --- /dev/null +++ b/awt/java/awt/peer/ChoicePeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface ChoicePeer { + +} diff --git a/awt/java/awt/peer/ComponentPeer.java b/awt/java/awt/peer/ComponentPeer.java new file mode 100644 index 0000000..bc26791 --- /dev/null +++ b/awt/java/awt/peer/ComponentPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface ComponentPeer { + +} diff --git a/awt/java/awt/peer/DialogPeer.java b/awt/java/awt/peer/DialogPeer.java new file mode 100644 index 0000000..8ae3049 --- /dev/null +++ b/awt/java/awt/peer/DialogPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface DialogPeer { + +} diff --git a/awt/java/awt/peer/FileDialogPeer.java b/awt/java/awt/peer/FileDialogPeer.java new file mode 100644 index 0000000..0d15e48 --- /dev/null +++ b/awt/java/awt/peer/FileDialogPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface FileDialogPeer { + +} diff --git a/awt/java/awt/peer/FontPeer.java b/awt/java/awt/peer/FontPeer.java new file mode 100644 index 0000000..fd9815f --- /dev/null +++ b/awt/java/awt/peer/FontPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface FontPeer { + +} diff --git a/awt/java/awt/peer/FramePeer.java b/awt/java/awt/peer/FramePeer.java new file mode 100644 index 0000000..9cfc40b --- /dev/null +++ b/awt/java/awt/peer/FramePeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface FramePeer { + +} diff --git a/awt/java/awt/peer/LabelPeer.java b/awt/java/awt/peer/LabelPeer.java new file mode 100644 index 0000000..052ca9d --- /dev/null +++ b/awt/java/awt/peer/LabelPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface LabelPeer { + +} diff --git a/awt/java/awt/peer/LightweightPeer.java b/awt/java/awt/peer/LightweightPeer.java new file mode 100644 index 0000000..1dee905 --- /dev/null +++ b/awt/java/awt/peer/LightweightPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface LightweightPeer { + +} diff --git a/awt/java/awt/peer/ListPeer.java b/awt/java/awt/peer/ListPeer.java new file mode 100644 index 0000000..0a27885 --- /dev/null +++ b/awt/java/awt/peer/ListPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface ListPeer { + +} diff --git a/awt/java/awt/peer/MenuBarPeer.java b/awt/java/awt/peer/MenuBarPeer.java new file mode 100644 index 0000000..3ad2c16 --- /dev/null +++ b/awt/java/awt/peer/MenuBarPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface MenuBarPeer { + +} diff --git a/awt/java/awt/peer/MenuComponentPeer.java b/awt/java/awt/peer/MenuComponentPeer.java new file mode 100644 index 0000000..3ac3b34 --- /dev/null +++ b/awt/java/awt/peer/MenuComponentPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface MenuComponentPeer { + +} diff --git a/awt/java/awt/peer/MenuItemPeer.java b/awt/java/awt/peer/MenuItemPeer.java new file mode 100644 index 0000000..b133897 --- /dev/null +++ b/awt/java/awt/peer/MenuItemPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface MenuItemPeer { + +} diff --git a/awt/java/awt/peer/MenuPeer.java b/awt/java/awt/peer/MenuPeer.java new file mode 100644 index 0000000..d643ce7 --- /dev/null +++ b/awt/java/awt/peer/MenuPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface MenuPeer { + +} diff --git a/awt/java/awt/peer/MouseInfoPeer.java b/awt/java/awt/peer/MouseInfoPeer.java new file mode 100644 index 0000000..9173a62 --- /dev/null +++ b/awt/java/awt/peer/MouseInfoPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface MouseInfoPeer { + +} diff --git a/awt/java/awt/peer/PanelPeer.java b/awt/java/awt/peer/PanelPeer.java new file mode 100644 index 0000000..1faa1fe --- /dev/null +++ b/awt/java/awt/peer/PanelPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface PanelPeer { + +} diff --git a/awt/java/awt/peer/PopupMenuPeer.java b/awt/java/awt/peer/PopupMenuPeer.java new file mode 100644 index 0000000..cf1ef61 --- /dev/null +++ b/awt/java/awt/peer/PopupMenuPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface PopupMenuPeer { + +} diff --git a/awt/java/awt/peer/ScrollPanePeer.java b/awt/java/awt/peer/ScrollPanePeer.java new file mode 100644 index 0000000..df3de83 --- /dev/null +++ b/awt/java/awt/peer/ScrollPanePeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface ScrollPanePeer { + +} diff --git a/awt/java/awt/peer/ScrollbarPeer.java b/awt/java/awt/peer/ScrollbarPeer.java new file mode 100644 index 0000000..eec8961 --- /dev/null +++ b/awt/java/awt/peer/ScrollbarPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface ScrollbarPeer { + +} diff --git a/awt/java/awt/peer/TextAreaPeer.java b/awt/java/awt/peer/TextAreaPeer.java new file mode 100644 index 0000000..636707f --- /dev/null +++ b/awt/java/awt/peer/TextAreaPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface TextAreaPeer { + +} diff --git a/awt/java/awt/peer/TextFieldPeer.java b/awt/java/awt/peer/TextFieldPeer.java new file mode 100644 index 0000000..2b8232a --- /dev/null +++ b/awt/java/awt/peer/TextFieldPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface TextFieldPeer { + +} diff --git a/awt/java/awt/peer/WindowPeer.java b/awt/java/awt/peer/WindowPeer.java new file mode 100644 index 0000000..384646f --- /dev/null +++ b/awt/java/awt/peer/WindowPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface WindowPeer { + +} diff --git a/awt/java/beans/FeatureDescriptor.java b/awt/java/beans/FeatureDescriptor.java new file mode 100644 index 0000000..2945c65 --- /dev/null +++ b/awt/java/beans/FeatureDescriptor.java @@ -0,0 +1,234 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package java.beans; + +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +/** + * Common base class for Descriptors. + */ +public class FeatureDescriptor { + + private Map<String, Object> values; + + boolean preferred, hidden, expert; + + String shortDescription; + + String name; + + String displayName; + + /** + * <p> + * Constructs an instance. + * </p> + */ + public FeatureDescriptor() { + this.values = new HashMap<String, Object>(); + } + + /** + * <p> + * Sets the value for the named attribute. + * </p> + * + * @param attributeName + * The name of the attribute to set a value with. + * @param value + * The value to set. + */ + public void setValue(String attributeName, Object value) { + if (attributeName == null || value == null) { + throw new NullPointerException(); + } + values.put(attributeName, value); + } + + /** + * <p> + * Gets the value associated with the named attribute. + * </p> + * + * @param attributeName + * The name of the attribute to get a value for. + * @return The attribute's value. + */ + public Object getValue(String attributeName) { + Object result = null; + if (attributeName != null) { + result = values.get(attributeName); + } + return result; + } + + /** + * <p> + * Enumerates the attribute names. + * </p> + * + * @return An instance of {@link Enumeration}. + */ + public Enumeration<String> attributeNames() { + // Create a new list, so that the references are copied + return Collections.enumeration(new LinkedList<String>(values.keySet())); + } + + /** + * <p> + * Sets the short description. + * </p> + * + * @param text + * The description to set. + */ + public void setShortDescription(String text) { + this.shortDescription = text; + } + + /** + * <p> + * Sets the name. + * </p> + * + * @param name + * The name to set. + */ + public void setName(String name) { + this.name = name; + } + + /** + * <p> + * Sets the display name. + * </p> + * + * @param displayName + * The display name to set. + */ + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + /** + * <p> + * Gets the short description or {@link #getDisplayName()} if not set. + * </p> + * + * @return The description. + */ + public String getShortDescription() { + return shortDescription == null ? getDisplayName() : shortDescription; + } + + /** + * <p> + * Gets the name. + * </p> + * + * @return The name. + */ + public String getName() { + return name; + } + + /** + * <p> + * Gets the display name or {@link #getName()} if not set. + * </p> + * + * @return The display name. + */ + public String getDisplayName() { + return displayName == null ? getName() : displayName; + } + + /** + * <p> + * Sets the preferred indicator. + * </p> + * + * @param preferred + * <code>true</code> if preferred, <code>false</code> + * otherwise. + */ + public void setPreferred(boolean preferred) { + this.preferred = preferred; + } + + /** + * <p> + * Sets the hidden indicator. + * </p> + * + * @param hidden + * <code>true</code> if hidden, <code>false</code> otherwise. + */ + public void setHidden(boolean hidden) { + this.hidden = hidden; + } + + /** + * <p> + * Sets the expert indicator. + * </p> + * + * @param expert + * <code>true</code> if expert, <code>false</code> otherwise. + */ + public void setExpert(boolean expert) { + this.expert = expert; + } + + /** + * <p> + * Indicates if this feature is preferred. + * </p> + * + * @return <code>true</code> if preferred, <code>false</code> otherwise. + */ + public boolean isPreferred() { + return preferred; + } + + /** + * <p> + * Indicates if this feature is hidden. + * </p> + * + * @return <code>true</code> if hidden, <code>false</code> otherwise. + */ + public boolean isHidden() { + return hidden; + } + + /** + * <p> + * Indicates if this feature is an expert feature. + * </p> + * + * @return <code>true</code> if hidden, <code>false</code> otherwise. + */ + public boolean isExpert() { + return expert; + } +} diff --git a/awt/java/beans/IndexedPropertyDescriptor.java b/awt/java/beans/IndexedPropertyDescriptor.java new file mode 100644 index 0000000..25667d9 --- /dev/null +++ b/awt/java/beans/IndexedPropertyDescriptor.java @@ -0,0 +1,227 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.beans; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import org.apache.harmony.beans.internal.nls.Messages; + +public class IndexedPropertyDescriptor extends PropertyDescriptor { + private Method indexedGetter; + + private Method indexedSetter; + + public IndexedPropertyDescriptor(String propertyName, Class<?> beanClass, + String getterName, String setterName, String indexedGetterName, + String indexedSetterName) throws IntrospectionException { + super(propertyName, beanClass, getterName, setterName); + + // RI behaves like this + if (indexedGetterName == null && indexedSetterName == null && + (getterName != null || setterName != null)) { + throw new IntrospectionException(Messages.getString("beans.50")); + } + setIndexedReadMethod(beanClass, indexedGetterName); + setIndexedWriteMethod(beanClass, indexedSetterName); + } + + public IndexedPropertyDescriptor(String propertyName, Method getter, Method setter, + Method indexedGetter, Method indexedSetter) throws IntrospectionException { + super(propertyName, getter, setter); + + // we need this in order to be compatible with RI + if (indexedGetter == null && indexedSetter == null && + (getter != null || setter != null)) { + throw new IntrospectionException(Messages.getString("beans.50")); + } + setIndexedReadMethod(indexedGetter); + setIndexedWriteMethod(indexedSetter); + } + + public IndexedPropertyDescriptor(String propertyName, Class<?> beanClass) + throws IntrospectionException { + super(propertyName, beanClass, null, null); + String getterName; + String setterName; + String indexedGetterName; + String indexedSetterName; + + // array getter + getterName = createDefaultMethodName(propertyName, "get"); //$NON-NLS-1$ + if (hasMethod(beanClass, getterName)) { + setReadMethod(beanClass, getterName); + } + // array setter + setterName = createDefaultMethodName(propertyName, "set"); //$NON-NLS-1$ + if (hasMethod(beanClass, setterName)) { + setWriteMethod(beanClass, setterName); + } + // indexed getter + indexedGetterName = createDefaultMethodName(propertyName, "get"); //$NON-NLS-1$ + if (hasMethod(beanClass, indexedGetterName)) { + setIndexedReadMethod(beanClass, indexedGetterName); + } + // indexed setter + indexedSetterName = createDefaultMethodName(propertyName, "set"); //$NON-NLS-1$ + if (hasMethod(beanClass, indexedSetterName)) { + setIndexedWriteMethod(beanClass, indexedSetterName); + } + // RI seems to behave a bit differently + if (indexedGetter == null && indexedSetter == null && + getReadMethod() == null && getWriteMethod() == null) { + throw new IntrospectionException( + Messages.getString("beans.01", propertyName)); //$NON-NLS-1$ + } + if (indexedGetter == null && indexedSetter == null) { + // not an indexed property indeed + throw new IntrospectionException(Messages.getString("beans.50")); + } + } + + public void setIndexedReadMethod(Method indexedGetter) throws IntrospectionException { + if (indexedGetter != null) { + int modifiers = indexedGetter.getModifiers(); + Class<?>[] parameterTypes; + Class<?> returnType; + Class<?> indexedPropertyType; + + if (!Modifier.isPublic(modifiers)) { + throw new IntrospectionException(Messages.getString("beans.21")); //$NON-NLS-1$ + } + parameterTypes = indexedGetter.getParameterTypes(); + if (parameterTypes.length != 1) { + throw new IntrospectionException(Messages.getString("beans.22")); //$NON-NLS-1$ + } + if (!parameterTypes[0].equals(int.class)) { + throw new IntrospectionException(Messages.getString("beans.23")); //$NON-NLS-1$ + } + returnType = indexedGetter.getReturnType(); + indexedPropertyType = getIndexedPropertyType(); + if ((indexedPropertyType != null) && !returnType.equals(indexedPropertyType)) { + throw new IntrospectionException(Messages.getString("beans.24")); //$NON-NLS-1$ + } + } + this.indexedGetter = indexedGetter; + } + + public void setIndexedWriteMethod(Method indexedSetter) throws IntrospectionException { + if (indexedSetter != null) { + int modifiers = indexedSetter.getModifiers(); + Class<?>[] parameterTypes; + Class<?> firstParameterType; + Class<?> secondParameterType; + Class<?> propType; + + if (!Modifier.isPublic(modifiers)) { + throw new IntrospectionException(Messages.getString("beans.25")); //$NON-NLS-1$ + } + parameterTypes = indexedSetter.getParameterTypes(); + if (parameterTypes.length != 2) { + throw new IntrospectionException(Messages.getString("beans.26")); //$NON-NLS-1$ + } + firstParameterType = parameterTypes[0]; + if (!firstParameterType.equals(int.class)) { + throw new IntrospectionException(Messages.getString("beans.27")); //$NON-NLS-1$ + } + secondParameterType = parameterTypes[1]; + propType = getIndexedPropertyType(); + if (propType != null && !secondParameterType.equals(propType)) { + throw new IntrospectionException(Messages.getString("beans.28")); //$NON-NLS-1$ + } + } + this.indexedSetter = indexedSetter; + } + + public Method getIndexedWriteMethod() { + return indexedSetter; + } + + public Method getIndexedReadMethod() { + return indexedGetter; + } + + @Override + public boolean equals(Object obj) { + boolean result = super.equals(obj); + + if (result) { + IndexedPropertyDescriptor pd = (IndexedPropertyDescriptor) obj; + + if (indexedGetter != null) { + result = indexedGetter.equals(pd.getIndexedReadMethod()); + } else if (result && indexedGetter == null) { + result = pd.getIndexedReadMethod() == null; + } + + if (result) { + if (indexedSetter != null) { + result = indexedSetter.equals(pd.getIndexedWriteMethod()); + } else if (indexedSetter == null) { + result = pd.getIndexedWriteMethod() == null; + } + } + } + + return result; + } + + public Class<?> getIndexedPropertyType() { + Class<?> result = null; + + if (indexedGetter != null) { + result = indexedGetter.getReturnType(); + } else if (indexedSetter != null) { + Class<?>[] parameterTypes = indexedSetter.getParameterTypes(); + + result = parameterTypes[1]; + } + return result; + } + + private void setIndexedReadMethod(Class<?> beanClass, String indexedGetterName) { + Method[] getters = findMethods(beanClass, indexedGetterName); + boolean result = false; + + for (Method element : getters) { + try { + setIndexedReadMethod(element); + result = true; + } catch (IntrospectionException ie) {} + + if (result) { + break; + } + } + } + + private void setIndexedWriteMethod(Class<?> beanClass, String indexedSetterName) { + Method[] setters = findMethods(beanClass, indexedSetterName); + boolean result = false; + + for (Method element : setters) { + try { + setIndexedWriteMethod(element); + result = true; + } catch (IntrospectionException ie) {} + + if (result) { + break; + } + } + } +} diff --git a/awt/java/beans/IntrospectionException.java b/awt/java/beans/IntrospectionException.java new file mode 100644 index 0000000..c895afe --- /dev/null +++ b/awt/java/beans/IntrospectionException.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.beans; + +public class IntrospectionException extends Exception { + + static final long serialVersionUID = -3728150539969542619L; + + public IntrospectionException(String message) { + super(message); + } +} diff --git a/awt/java/beans/PropertyDescriptor.java b/awt/java/beans/PropertyDescriptor.java new file mode 100644 index 0000000..9389152 --- /dev/null +++ b/awt/java/beans/PropertyDescriptor.java @@ -0,0 +1,300 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.beans; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Vector; +import org.apache.harmony.beans.internal.nls.Messages; + +public class PropertyDescriptor extends FeatureDescriptor { + private Method getter; + + private Method setter; + + private Class<?> propertyEditorClass; + + private boolean constrained; + + private boolean bound; + + public PropertyDescriptor(String propertyName, Class<?> beanClass, String getterName, + String setterName) throws IntrospectionException { + super(); + if (beanClass == null) { + throw new IntrospectionException(Messages.getString("beans.03")); //$NON-NLS-1$ + } + if (propertyName == null || propertyName.length() == 0) { + throw new IntrospectionException(Messages.getString("beans.04")); //$NON-NLS-1$ + } + this.setName(propertyName); + this.setDisplayName(propertyName); + if (setterName != null) { + if (hasMethod(beanClass, setterName)) { + setWriteMethod(beanClass, setterName); + } else { + throw new IntrospectionException(Messages.getString("beans.20")); //$NON-NLS-1$ + } + } + if (getterName != null) { + if (hasMethod(beanClass, getterName)) { + setReadMethod(beanClass, getterName); + } else { + throw new IntrospectionException(Messages.getString("beans.1F")); //$NON-NLS-1$ + } + } + } + + public PropertyDescriptor(String propertyName, Method getter, Method setter) + throws IntrospectionException { + super(); + if (propertyName == null || propertyName.length() == 0) { + throw new IntrospectionException(Messages.getString("beans.04")); //$NON-NLS-1$ + } + this.setName(propertyName); + this.setDisplayName(propertyName); + setWriteMethod(setter); + setReadMethod(getter); + } + + public PropertyDescriptor(String propertyName, Class<?> beanClass) + throws IntrospectionException { + String getterName; + String setterName; + if (beanClass == null) { + throw new IntrospectionException(Messages.getString("beans.03")); //$NON-NLS-1$ + } + if (propertyName == null || propertyName.length() == 0) { + throw new IntrospectionException(Messages.getString("beans.04")); //$NON-NLS-1$ + } + this.setName(propertyName); + this.setDisplayName(propertyName); + getterName = createDefaultMethodName(propertyName, "is"); //$NON-NLS-1$ + if (hasMethod(beanClass, getterName)) { + setReadMethod(beanClass, getterName); + } else { + getterName = createDefaultMethodName(propertyName, "get"); //$NON-NLS-1$ + if (hasMethod(beanClass, getterName)) { + setReadMethod(beanClass, getterName); + } + } + setterName = createDefaultMethodName(propertyName, "set"); //$NON-NLS-1$ + if (hasMethod(beanClass, setterName)) { + setWriteMethod(beanClass, setterName); + } + if (getter == null && setter == null) { + throw new IntrospectionException(Messages.getString("beans.01", propertyName)); //$NON-NLS-1$ + } + } + + public void setWriteMethod(Method setter) throws IntrospectionException { + if (setter != null) { + int modifiers = setter.getModifiers(); + if (!Modifier.isPublic(modifiers)) { + throw new IntrospectionException(Messages.getString("beans.05")); //$NON-NLS-1$ + } + Class<?>[] parameterTypes = setter.getParameterTypes(); + if (parameterTypes.length != 1) { + throw new IntrospectionException(Messages.getString("beans.06")); //$NON-NLS-1$ + } + Class<?> parameterType = parameterTypes[0]; + Class<?> propertyType = getPropertyType(); + if (propertyType != null && !propertyType.equals(parameterType)) { + throw new IntrospectionException(Messages.getString("beans.07")); //$NON-NLS-1$ + } + } + this.setter = setter; + } + + public void setReadMethod(Method getter) throws IntrospectionException { + if (getter != null) { + int modifiers = getter.getModifiers(); + if (!Modifier.isPublic(modifiers)) { + throw new IntrospectionException(Messages.getString("beans.0A")); //$NON-NLS-1$ + } + Class<?>[] parameterTypes = getter.getParameterTypes(); + if (parameterTypes.length != 0) { + throw new IntrospectionException(Messages.getString("beans.08")); //$NON-NLS-1$ + } + Class<?> returnType = getter.getReturnType(); + if (returnType.equals(Void.TYPE)) { + throw new IntrospectionException(Messages.getString("beans.33")); //$NON-NLS-1$ + } + Class<?> propertyType = getPropertyType(); + if ((propertyType != null) && !returnType.equals(propertyType)) { + throw new IntrospectionException(Messages.getString("beans.09")); //$NON-NLS-1$ + } + } + this.getter = getter; + } + + public Method getWriteMethod() { + return setter; + } + + public Method getReadMethod() { + return getter; + } + + @Override + public boolean equals(Object object) { + boolean result = (object != null && object instanceof PropertyDescriptor); + if (result) { + PropertyDescriptor pd = (PropertyDescriptor) object; + boolean gettersAreEqual = (this.getter == null) && (pd.getReadMethod() == null) + || (this.getter != null) && (this.getter.equals(pd.getReadMethod())); + boolean settersAreEqual = (this.setter == null) && (pd.getWriteMethod() == null) + || (this.setter != null) && (this.setter.equals(pd.getWriteMethod())); + boolean propertyTypesAreEqual = this.getPropertyType() == pd.getPropertyType(); + boolean propertyEditorClassesAreEqual = this.getPropertyEditorClass() == pd + .getPropertyEditorClass(); + boolean boundPropertyAreEqual = this.isBound() == pd.isBound(); + boolean constrainedPropertyAreEqual = this.isConstrained() == pd.isConstrained(); + result = gettersAreEqual && settersAreEqual && propertyTypesAreEqual + && propertyEditorClassesAreEqual && boundPropertyAreEqual + && constrainedPropertyAreEqual; + } + return result; + } + + public void setPropertyEditorClass(Class<?> propertyEditorClass) { + this.propertyEditorClass = propertyEditorClass; + } + + public Class<?> getPropertyType() { + Class<?> result = null; + if (getter != null) { + result = getter.getReturnType(); + } else if (setter != null) { + Class<?>[] parameterTypes = setter.getParameterTypes(); + result = parameterTypes[0]; + } + return result; + } + + public Class<?> getPropertyEditorClass() { + return propertyEditorClass; + } + + public void setConstrained(boolean constrained) { + this.constrained = constrained; + } + + public void setBound(boolean bound) { + this.bound = bound; + } + + public boolean isConstrained() { + return constrained; + } + + public boolean isBound() { + return bound; + } + + boolean hasMethod(Class<?> beanClass, String methodName) { + Method[] methods = findMethods(beanClass, methodName); + return (methods.length > 0); + } + + String createDefaultMethodName(String propertyName, String prefix) { + String result = null; + if (propertyName != null) { + String bos = propertyName.substring(0, 1).toUpperCase(); + String eos = propertyName.substring(1, propertyName.length()); + result = prefix + bos + eos; + } + return result; + } + + Method[] findMethods(Class<?> aClass, String methodName) { + Method[] allMethods = aClass.getMethods(); + Vector<Method> matchedMethods = new Vector<Method>(); + Method[] result; + for (Method method : allMethods) { + if (method.getName().equals(methodName)) { + matchedMethods.add(method); + } + } + result = new Method[matchedMethods.size()]; + for (int j = 0; j < matchedMethods.size(); ++j) { + result[j] = matchedMethods.elementAt(j); + } + return result; + } + + void setReadMethod(Class<?> beanClass, String getterName) { + boolean result = false; + Method[] getters = findMethods(beanClass, getterName); + for (Method element : getters) { + try { + setReadMethod(element); + result = true; + } catch (IntrospectionException ie) { + } + if (result) { + break; + } + } + } + + void setWriteMethod(Class<?> beanClass, String setterName) throws IntrospectionException { + boolean result = false; + Method[] setters = findMethods(beanClass, setterName); + for (Method element : setters) { + try { + setWriteMethod(element); + result = true; + } catch (IntrospectionException ie) { + } + if (result) { + break; + } + } + } + + public PropertyEditor createPropertyEditor(Object bean) { + PropertyEditor editor; + if (propertyEditorClass == null) { + return null; + } + if (!PropertyEditor.class.isAssignableFrom(propertyEditorClass)) { + // beans.48=Property editor is not assignable from the + // PropertyEditor interface + throw new ClassCastException(Messages.getString("beans.48")); //$NON-NLS-1$ + } + try { + Constructor<?> constr; + try { + // try to look for the constructor with single Object argument + constr = propertyEditorClass.getConstructor(Object.class); + editor = (PropertyEditor) constr.newInstance(bean); + } catch (NoSuchMethodException e) { + // try no-argument constructor + constr = propertyEditorClass.getConstructor(); + editor = (PropertyEditor) constr.newInstance(); + } + } catch (Exception e) { + // beans.47=Unable to instantiate property editor + RuntimeException re = new RuntimeException(Messages.getString("beans.47"), e); //$NON-NLS-1$ + throw re; + } + return editor; + } +} diff --git a/awt/java/beans/PropertyEditor.java b/awt/java/beans/PropertyEditor.java new file mode 100644 index 0000000..65bedea --- /dev/null +++ b/awt/java/beans/PropertyEditor.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.beans; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Rectangle; + +public interface PropertyEditor { + + public void paintValue(Graphics gfx, Rectangle box); + + public void setAsText(String text) throws IllegalArgumentException; + + public String[] getTags(); + + public String getJavaInitializationString(); + + public String getAsText(); + + public void setValue(Object value); + + public Object getValue(); + + public void removePropertyChangeListener(PropertyChangeListener listener); + + public void addPropertyChangeListener(PropertyChangeListener listener); + + public Component getCustomEditor(); + + public boolean supportsCustomEditor(); + + public boolean isPaintable(); +} diff --git a/awt/java/beans/PropertyEditorManager.java b/awt/java/beans/PropertyEditorManager.java new file mode 100644 index 0000000..ed55829 --- /dev/null +++ b/awt/java/beans/PropertyEditorManager.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.beans; + +import java.util.HashMap; +import java.util.Map; + +public class PropertyEditorManager { + + private static String[] path = { "org.apache.harmony.beans.editors" }; //$NON-NLS-1$ + + private static final Map<Class<?>, Class<?>> registeredEditors = new HashMap<Class<?>, Class<?>>(); + + public PropertyEditorManager() { + } + + public static void registerEditor(Class<?> targetType, Class<?> editorClass) { + if (targetType == null) { + throw new NullPointerException(); + } + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPropertiesAccess(); + } + if (editorClass != null) { + registeredEditors.put(targetType, editorClass); + } else { + registeredEditors.remove(targetType); + } + } + + public static synchronized PropertyEditor findEditor(Class<?> targetType) { + if (targetType == null) { + throw new NullPointerException(); + } + + Class<?> editorClass = null; + PropertyEditor editor = null; + + editorClass = registeredEditors.get(targetType); + + if (editorClass == null) { + String editorClassName = targetType.getName() + "Editor"; //$NON-NLS-1$ + ClassLoader loader = targetType.getClassLoader(); + + if (loader == null) { + loader = Thread.currentThread().getContextClassLoader(); + } + + try { + editorClass = Class.forName(editorClassName, true, loader); + } catch (ClassNotFoundException cnfe) { + String shortEditorClassName = editorClassName + .substring(editorClassName.lastIndexOf(".") + 1); //$NON-NLS-1$ + + if (targetType.isPrimitive()) { + shortEditorClassName = shortEditorClassName.substring(0, 1) + .toUpperCase() + + shortEditorClassName.substring(1); + } + + for (String element : path) { + editorClassName = element + "." + shortEditorClassName; //$NON-NLS-1$ + + try { + editorClass = Class.forName(editorClassName, true, + loader); + break; + } catch (Exception e) { + } + } + } catch (Exception e) { + } + } + + if (editorClass != null) { + try { + editor = (PropertyEditor) editorClass.newInstance(); + } catch (Exception e) { + } + } + + return editor; + } + + public static synchronized void setEditorSearchPath(String[] apath) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPropertiesAccess(); + } + + path = apath; + } + + public static synchronized String[] getEditorSearchPath() { + return path; + } +} diff --git a/awt/java/beans/PropertyEditorSupport.java b/awt/java/beans/PropertyEditorSupport.java new file mode 100644 index 0000000..c3929a1 --- /dev/null +++ b/awt/java/beans/PropertyEditorSupport.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.beans; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.harmony.beans.internal.nls.Messages; + +public class PropertyEditorSupport implements PropertyEditor { + + Object source = null; + + List<PropertyChangeListener> listeners = new ArrayList<PropertyChangeListener>(); + + Object oldValue = null; + + Object newValue = null; + + public PropertyEditorSupport(Object source) { + if (source == null) { + throw new NullPointerException(Messages.getString("beans.0C")); //$NON-NLS-1$ + } + this.source = source; + } + + public PropertyEditorSupport() { + source = this; + } + + public void paintValue(Graphics gfx, Rectangle box) { + } + + public void setAsText(String text) throws IllegalArgumentException { + if (newValue instanceof String) { + setValue(text); + } else { + throw new IllegalArgumentException(text); + } + } + + public String[] getTags() { + return null; + } + + public String getJavaInitializationString() { + return "???"; //$NON-NLS-1$ + } + + public String getAsText() { + return newValue == null ? "null" : newValue.toString(); //$NON-NLS-1$ + } + + public void setValue(Object value) { + this.oldValue = this.newValue; + this.newValue = value; + firePropertyChange(); + } + + public Object getValue() { + return newValue; + } + + public void setSource(Object source) { + if (source == null) { + throw new NullPointerException(Messages.getString("beans.0C")); //$NON-NLS-1$ + } + this.source = source; + } + + public Object getSource() { + return source; + } + + public synchronized void removePropertyChangeListener( + PropertyChangeListener listener) { + if (listeners != null) { + listeners.remove(listener); + } + } + + public synchronized void addPropertyChangeListener( + PropertyChangeListener listener) { + listeners.add(listener); + } + + public Component getCustomEditor() { + return null; + } + + public boolean supportsCustomEditor() { + return false; + } + + public boolean isPaintable() { + return false; + } + + public void firePropertyChange() { + if (listeners.size() > 0) { + PropertyChangeEvent event = new PropertyChangeEvent(source, null, + oldValue, newValue); + Iterator<PropertyChangeListener> iterator = listeners.iterator(); + + while (iterator.hasNext()) { + PropertyChangeListener listener = iterator.next(); + listener.propertyChange(event); + } + } + } +} diff --git a/awt/java/beans/PropertyVetoException.java b/awt/java/beans/PropertyVetoException.java new file mode 100644 index 0000000..c7f092a --- /dev/null +++ b/awt/java/beans/PropertyVetoException.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.beans; + +/** + * Indicates that a proposed property change is unacceptable. + */ +public class PropertyVetoException extends Exception { + + private static final long serialVersionUID = 129596057694162164L; + + private final PropertyChangeEvent evt; + + /** + * <p> + * Constructs an instance with a message and the change event. + * </p> + * + * @param message + * A description of the veto. + * @param event + * The event that was vetoed. + */ + public PropertyVetoException(String message, PropertyChangeEvent event) { + super(message); + this.evt = event; + } + + /** + * <p> + * Gets the property change event. + * </p> + * + * @return An instance of {@link PropertyChangeEvent} + */ + public PropertyChangeEvent getPropertyChangeEvent() { + return evt; + } +} |