Showing the changes to java/pkg/sun/java2d (352 of 18352 files). Show all
Unified · Split
Binary file not shown.
| @@ -0,0 +1,56 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This class is the default DisposerRecord implementation which | |
| 30 | + * holds pointers to the native disposal method and the data to be disposed. | |
| 31 | + */ | |
| 32 | +public class DefaultDisposerRecord implements DisposerRecord { | |
| 33 | + private long dataPointer; | |
| 34 | + private long disposerMethodPointer; | |
| 35 | + | |
| 36 | + public DefaultDisposerRecord(long disposerMethodPointer, long dataPointer) { | |
| 37 | + this.disposerMethodPointer = disposerMethodPointer; | |
| 38 | + this.dataPointer = dataPointer; | |
| 39 | + } | |
| 40 | + | |
| 41 | + public void dispose() { | |
| 42 | + invokeNativeDispose(disposerMethodPointer, | |
| 43 | + dataPointer); | |
| 44 | + } | |
| 45 | + | |
| 46 | + public long getDataPointer() { | |
| 47 | + return dataPointer; | |
| 48 | + } | |
| 49 | + | |
| 50 | + public long getDisposerMethodPointer() { | |
| 51 | + return disposerMethodPointer; | |
| 52 | + } | |
| 53 | + | |
| 54 | + public static native void invokeNativeDispose(long disposerMethodPointer, | |
| 55 | + long dataPointer); | |
| 56 | +} | |
Binary file not shown.
| @@ -0,0 +1,41 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d; | |
| 27 | + | |
| 28 | +import sun.java2d.pipe.hw.*; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * Classes implementing this interface provide access to their | |
| 32 | + * destination surfaces. | |
| 33 | + */ | |
| 34 | +public interface DestSurfaceProvider { | |
| 35 | + /** | |
| 36 | + * Returns a surface currently used as a destination surface for rendering. | |
| 37 | + * | |
| 38 | + * @return destination surface | |
| 39 | + */ | |
| 40 | + public Surface getDestSurface(); | |
| 41 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,262 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d; | |
| 27 | + | |
| 28 | +import java.lang.ref.Reference; | |
| 29 | +import java.lang.ref.ReferenceQueue; | |
| 30 | +import java.lang.ref.PhantomReference; | |
| 31 | +import java.lang.ref.WeakReference; | |
| 32 | +import java.util.ArrayList; | |
| 33 | +import java.util.Hashtable; | |
| 34 | + | |
| 35 | +/** | |
| 36 | + * This class is used for registering and disposing the native | |
| 37 | + * data associated with java objects. | |
| 38 | + * | |
| 39 | + * The object can register itself by calling one of the addRecord | |
| 40 | + * methods and providing either the pointer to the native disposal | |
| 41 | + * method or a descendant of the DisposerRecord class with overridden | |
| 42 | + * dispose() method. | |
| 43 | + * | |
| 44 | + * When the object becomes unreachable, the dispose() method | |
| 45 | + * of the associated DisposerRecord object will be called. | |
| 46 | + * | |
| 47 | + * @see DisposerRecord | |
| 48 | + */ | |
| 49 | +public class Disposer implements Runnable { | |
| 50 | + private static final ReferenceQueue queue = new ReferenceQueue(); | |
| 51 | + private static final Hashtable records = new Hashtable(); | |
| 52 | + | |
| 53 | + private static Disposer disposerInstance; | |
| 54 | + public static final int WEAK = 0; | |
| 55 | + public static final int PHANTOM = 1; | |
| 56 | + public static int refType = PHANTOM; | |
| 57 | + | |
| 58 | + static { | |
| 59 | + java.security.AccessController.doPrivileged( | |
| 60 | + new sun.security.action.LoadLibraryAction("awt")); | |
| 61 | + initIDs(); | |
| 62 | + String type = (String) java.security.AccessController.doPrivileged( | |
| 63 | + new sun.security.action.GetPropertyAction("sun.java2d.reftype")); | |
| 64 | + if (type != null) { | |
| 65 | + if (type.equals("weak")) { | |
| 66 | + refType = WEAK; | |
| 67 | + System.err.println("Using WEAK refs"); | |
| 68 | + } else { | |
| 69 | + refType = PHANTOM; | |
| 70 | + System.err.println("Using PHANTOM refs"); | |
| 71 | + } | |
| 72 | + } | |
| 73 | + disposerInstance = new Disposer(); | |
| 74 | + java.security.AccessController.doPrivileged( | |
| 75 | + new java.security.PrivilegedAction() { | |
| 76 | + public Object run() { | |
| 77 | + /* The thread must be a member of a thread group | |
| 78 | + * which will not get GCed before VM exit. | |
| 79 | + * Make its parent the top-level thread group. | |
| 80 | + */ | |
| 81 | + ThreadGroup tg = Thread.currentThread().getThreadGroup(); | |
| 82 | + for (ThreadGroup tgn = tg; | |
| 83 | + tgn != null; | |
| 84 | + tg = tgn, tgn = tg.getParent()); | |
| 85 | + Thread t = | |
| 86 | + new Thread(tg, disposerInstance, "Java2D Disposer"); | |
| 87 | + t.setContextClassLoader(null); | |
| 88 | + t.setDaemon(true); | |
| 89 | + t.setPriority(Thread.MAX_PRIORITY); | |
| 90 | + t.start(); | |
| 91 | + return null; | |
| 92 | + } | |
| 93 | + } | |
| 94 | + ); | |
| 95 | + } | |
| 96 | + | |
| 97 | + /** | |
| 98 | + * Registers the object and the native data for later disposal. | |
| 99 | + * @param target Object to be registered | |
| 100 | + * @param disposeMethod pointer to the native disposal method | |
| 101 | + * @param pData pointer to the data to be passed to the | |
| 102 | + * native disposal method | |
| 103 | + */ | |
| 104 | + public static void addRecord(Object target, | |
| 105 | + long disposeMethod, long pData) | |
| 106 | + { | |
| 107 | + disposerInstance.add(target, | |
| 108 | + new DefaultDisposerRecord(disposeMethod, pData)); | |
| 109 | + } | |
| 110 | + | |
| 111 | + /** | |
| 112 | + * Registers the object and the native data for later disposal. | |
| 113 | + * @param target Object to be registered | |
| 114 | + * @param rec the associated DisposerRecord object | |
| 115 | + * @see DisposerRecord | |
| 116 | + */ | |
| 117 | + public static void addRecord(Object target, DisposerRecord rec) { | |
| 118 | + disposerInstance.add(target, rec); | |
| 119 | + } | |
| 120 | + | |
| 121 | + /** | |
| 122 | + * Performs the actual registration of the target object to be disposed. | |
| 123 | + * @param target Object to be registered, or if target is an instance | |
| 124 | + * of DisposerTarget, its associated disposer referent | |
| 125 | + * will be the Object that is registered | |
| 126 | + * @param rec the associated DisposerRecord object | |
| 127 | + * @see DisposerRecord | |
| 128 | + */ | |
| 129 | + synchronized void add(Object target, DisposerRecord rec) { | |
| 130 | + if (target instanceof DisposerTarget) { | |
| 131 | + target = ((DisposerTarget)target).getDisposerReferent(); | |
| 132 | + } | |
| 133 | + java.lang.ref.Reference ref; | |
| 134 | + if (refType == PHANTOM) { | |
| 135 | + ref = new PhantomReference(target, queue); | |
| 136 | + } else { | |
| 137 | + ref = new WeakReference(target, queue); | |
| 138 | + } | |
| 139 | + records.put(ref, rec); | |
| 140 | + } | |
| 141 | + | |
| 142 | + public void run() { | |
| 143 | + while (true) { | |
| 144 | + try { | |
| 145 | + Object obj = queue.remove(); | |
| 146 | + ((Reference)obj).clear(); | |
| 147 | + DisposerRecord rec = (DisposerRecord)records.remove(obj); | |
| 148 | + rec.dispose(); | |
| 149 | + obj = null; | |
| 150 | + rec = null; | |
| 151 | + clearDeferredRecords(); | |
| 152 | + } catch (Exception e) { | |
| 153 | + System.out.println("Exception while removing reference: " + e); | |
| 154 | + e.printStackTrace(); | |
| 155 | + } | |
| 156 | + } | |
| 157 | + } | |
| 158 | + | |
| 159 | + /* | |
| 160 | + * This is a marker interface that, if implemented, means it | |
| 161 | + * doesn't acquire any special locks, and is safe to | |
| 162 | + * be disposed in the poll loop on whatever thread | |
| 163 | + * which happens to be the Toolkit thread, is in use. | |
| 164 | + */ | |
| 165 | + public static interface PollDisposable { | |
| 166 | + }; | |
| 167 | + | |
| 168 | + private static ArrayList<DisposerRecord> deferredRecords = null; | |
| 169 | + | |
| 170 | + private static void clearDeferredRecords() { | |
| 171 | + if (deferredRecords == null || deferredRecords.isEmpty()) { | |
| 172 | + return; | |
| 173 | + } | |
| 174 | + for (int i=0;i<deferredRecords.size(); i++) { | |
| 175 | + try { | |
| 176 | + DisposerRecord rec = deferredRecords.get(i); | |
| 177 | + rec.dispose(); | |
| 178 | + } catch (Exception e) { | |
| 179 | + System.out.println("Exception while disposing deferred rec."); | |
| 180 | + e.printStackTrace(); | |
| 181 | + } | |
| 182 | + } | |
| 183 | + deferredRecords.clear(); | |
| 184 | + } | |
| 185 | + | |
| 186 | + /* | |
| 187 | + * Set to indicate the queue is presently being polled. | |
| 188 | + */ | |
| 189 | + public static volatile boolean pollingQueue = false; | |
| 190 | + | |
| 191 | + /* | |
| 192 | + * The pollRemove() method is called back from a dispose method | |
| 193 | + * that is running on the toolkit thread and wants to | |
| 194 | + * dispose any pending refs that are safe to be disposed | |
| 195 | + * on that thread. | |
| 196 | + */ | |
| 197 | + public static void pollRemove() { | |
| 198 | + | |
| 199 | + /* This should never be called recursively, so this check | |
| 200 | + * is just a safeguard against the unexpected. | |
| 201 | + */ | |
| 202 | + if (pollingQueue) { | |
| 203 | + return; | |
| 204 | + } | |
| 205 | + Object obj; | |
| 206 | + pollingQueue = true; | |
| 207 | + int freed = 0; | |
| 208 | + int deferred = 0; | |
| 209 | + try { | |
| 210 | + while ((obj = queue.poll()) != null | |
| 211 | + && freed < 10000 && deferred < 100) { | |
| 212 | + freed++; | |
| 213 | + ((Reference)obj).clear(); | |
| 214 | + DisposerRecord rec = (DisposerRecord)records.remove(obj); | |
| 215 | + if (rec instanceof PollDisposable) { | |
| 216 | + rec.dispose(); | |
| 217 | + obj = null; | |
| 218 | + rec = null; | |
| 219 | + } else { | |
| 220 | + if (rec == null) { // shouldn't happen, but just in case. | |
| 221 | + continue; | |
| 222 | + } | |
| 223 | + deferred++; | |
| 224 | + if (deferredRecords == null) { | |
| 225 | + deferredRecords = new ArrayList<DisposerRecord>(5); | |
| 226 | + } | |
| 227 | + deferredRecords.add(rec); | |
| 228 | + } | |
| 229 | + } | |
| 230 | + } catch (Exception e) { | |
| 231 | + System.out.println("Exception while removing reference: " + e); | |
| 232 | + e.printStackTrace(); | |
| 233 | + } finally { | |
| 234 | + pollingQueue = false; | |
| 235 | + } | |
| 236 | + } | |
| 237 | + | |
| 238 | + private static native void initIDs(); | |
| 239 | + | |
| 240 | + /* | |
| 241 | + * This was added for use by the 2D font implementation to avoid creation | |
| 242 | + * of an additional disposer thread. | |
| 243 | + * WARNING: this thread class monitors a specific queue, so a reference | |
| 244 | + * added here must have been created with this queue. Failure to do | |
| 245 | + * so will clutter the records hashmap and no one will be cleaning up | |
| 246 | + * the reference queue. | |
| 247 | + */ | |
| 248 | + public static void addReference(Reference ref, DisposerRecord rec) { | |
| 249 | + records.put(ref, rec); | |
| 250 | + } | |
| 251 | + | |
| 252 | + public static void addObjectRecord(Object obj, DisposerRecord rec) { | |
| 253 | + records.put(new WeakReference(obj, queue) , rec); | |
| 254 | + } | |
| 255 | + | |
| 256 | + /* This is intended for use in conjunction with addReference(..) | |
| 257 | + */ | |
| 258 | + public static ReferenceQueue getQueue() { | |
| 259 | + return queue; | |
| 260 | + } | |
| 261 | + | |
| 262 | +} | |
Binary file not shown.
| @@ -0,0 +1,34 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This class is used to hold the resource to be | |
| 30 | + * disposed. | |
| 31 | + */ | |
| 32 | +public interface DisposerRecord { | |
| 33 | + public void dispose(); | |
| 34 | +} | |
Binary file not shown.
| @@ -0,0 +1,38 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This is an interface which should be implemented by | |
| 30 | + * the classes which use Disposer. | |
| 31 | + */ | |
| 32 | +public interface DisposerTarget { | |
| 33 | + /** | |
| 34 | + * Returns an object which will be | |
| 35 | + * used as the referent in the ReferenceQueue | |
| 36 | + */ | |
| 37 | + public Object getDisposerReferent(); | |
| 38 | +} | |
Binary file not shown.
| @@ -0,0 +1,39 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d; | |
| 27 | + | |
| 28 | +import sun.awt.FontConfiguration; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * Font support for graphics environment | |
| 32 | + */ | |
| 33 | +public interface FontSupport { | |
| 34 | + | |
| 35 | + /** | |
| 36 | + * Returns the current font configuration. | |
| 37 | + */ | |
| 38 | + public FontConfiguration getFontConfiguration(); | |
| 39 | +} | |
Binary file not shown.
| @@ -0,0 +1,103 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d; | |
| 27 | + | |
| 28 | +import java.awt.GraphicsEnvironment; | |
| 29 | +import java.awt.GraphicsDevice; | |
| 30 | +import java.awt.Graphics2D; | |
| 31 | +import java.awt.HeadlessException; | |
| 32 | +import java.awt.image.BufferedImage; | |
| 33 | +import java.awt.Font; | |
| 34 | +import java.text.AttributedCharacterIterator; | |
| 35 | +import java.awt.print.PrinterJob; | |
| 36 | +import java.util.Map; | |
| 37 | +import java.util.Hashtable; | |
| 38 | +import java.util.Locale; | |
| 39 | +import java.util.Vector; | |
| 40 | +import java.util.StringTokenizer; | |
| 41 | +import java.util.ResourceBundle; | |
| 42 | +import java.util.MissingResourceException; | |
| 43 | +import java.io.IOException; | |
| 44 | +import java.io.FilenameFilter; | |
| 45 | +import java.io.File; | |
| 46 | +import java.util.NoSuchElementException; | |
| 47 | +import sun.awt.FontConfiguration; | |
| 48 | +import java.util.TreeMap; | |
| 49 | +import java.util.Set; | |
| 50 | +import java.awt.font.TextAttribute; | |
| 51 | +import java.io.InputStream; | |
| 52 | +import java.io.FileInputStream; | |
| 53 | +import java.io.BufferedInputStream; | |
| 54 | +import java.util.Properties; | |
| 55 | +import java.awt.Point; | |
| 56 | +import java.awt.Rectangle; | |
| 57 | + | |
| 58 | +/** | |
| 59 | + * Headless decorator implementation of a SunGraphicsEnvironment | |
| 60 | + */ | |
| 61 | + | |
| 62 | +public class HeadlessGraphicsEnvironment extends GraphicsEnvironment { | |
| 63 | + | |
| 64 | + private GraphicsEnvironment ge; | |
| 65 | + | |
| 66 | + public HeadlessGraphicsEnvironment(GraphicsEnvironment ge) { | |
| 67 | + this.ge = ge; | |
| 68 | + } | |
| 69 | + | |
| 70 | + public GraphicsDevice[] getScreenDevices() | |
| 71 | + throws HeadlessException { | |
| 72 | + throw new HeadlessException(); | |
| 73 | + } | |
| 74 | + | |
| 75 | + public GraphicsDevice getDefaultScreenDevice() | |
| 76 | + throws HeadlessException { | |
| 77 | + throw new HeadlessException(); | |
| 78 | + } | |
| 79 | + | |
| 80 | + public Point getCenterPoint() throws HeadlessException { | |
| 81 | + throw new HeadlessException(); | |
| 82 | + } | |
| 83 | + | |
| 84 | + public Rectangle getMaximumWindowBounds() throws HeadlessException { | |
| 85 | + throw new HeadlessException(); | |
| 86 | + } | |
| 87 | + | |
| 88 | + public Graphics2D createGraphics(BufferedImage img) { | |
| 89 | + return ge.createGraphics(img); } | |
| 90 | + | |
| 91 | + public Font[] getAllFonts() { return ge.getAllFonts(); } | |
| 92 | + | |
| 93 | + public String[] getAvailableFontFamilyNames() { | |
| 94 | + return ge.getAvailableFontFamilyNames(); } | |
| 95 | + | |
| 96 | + public String[] getAvailableFontFamilyNames(Locale l) { | |
| 97 | + return ge.getAvailableFontFamilyNames(l); } | |
| 98 | + | |
| 99 | + /* Used by FontManager : internal API */ | |
| 100 | + public GraphicsEnvironment getSunGraphicsEnvironment() { | |
| 101 | + return ge; | |
| 102 | + } | |
| 103 | +} | |
Binary file not shown.
| @@ -0,0 +1,55 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Signals that some part of a graphics pipeline is not in an appropriate | |
| 30 | + * state for the requested operation. The most likely cause of this is | |
| 31 | + * an asynchronous change to the configuration of the destination surface | |
| 32 | + * since the current set of rendering loops was chosen. Other potential | |
| 33 | + * causes are the appearance or disappearance of overlapping opaque | |
| 34 | + * windows which toggle the need to use platform graphics or direct | |
| 35 | + * graphics access. | |
| 36 | + */ | |
| 37 | +public class InvalidPipeException extends IllegalStateException { | |
| 38 | + /** | |
| 39 | + * Constructs an InvalidPipeException with no detail message. | |
| 40 | + * A detail message is a String that describes this particular exception. | |
| 41 | + */ | |
| 42 | + public InvalidPipeException() { | |
| 43 | + super(); | |
| 44 | + } | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * Constructs an InvalidPipeException with the specified detail | |
| 48 | + * message. A detail message is a String that describes this particular | |
| 49 | + * exception. | |
| 50 | + * @param s the String that contains a detailed message | |
| 51 | + */ | |
| 52 | + public InvalidPipeException(String s) { | |
| 53 | + super(s); | |
| 54 | + } | |
| 55 | +} | |
Binary file not shown.
| @@ -0,0 +1,159 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d; | |
| 27 | + | |
| 28 | +import java.awt.Rectangle; | |
| 29 | +import java.awt.image.Raster; | |
| 30 | +import java.awt.image.ColorModel; | |
| 31 | +import java.awt.GraphicsConfiguration; | |
| 32 | + | |
| 33 | +import sun.java2d.StateTrackable.State; | |
| 34 | +import sun.java2d.loops.SurfaceType; | |
| 35 | +import sun.java2d.pipe.NullPipe; | |
| 36 | + | |
| 37 | +/** | |
| 38 | + * This class provides an empty implementation of the SurfaceData | |
| 39 | + * abstract superclass. All operations on it translate into NOP | |
| 40 | + * or harmless operations. | |
| 41 | + */ | |
| 42 | +public class NullSurfaceData extends SurfaceData { | |
| 43 | + public static final SurfaceData theInstance = new NullSurfaceData(); | |
| 44 | + | |
| 45 | + private NullSurfaceData() { | |
| 46 | + super(State.IMMUTABLE, SurfaceType.Any, ColorModel.getRGBdefault()); | |
| 47 | + } | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * Sets this SurfaceData object to the invalid state. All Graphics | |
| 51 | + * objects must get a new SurfaceData object via the refresh method | |
| 52 | + * and revalidate their pipelines before continuing. | |
| 53 | + */ | |
| 54 | + public void invalidate() { | |
| 55 | + } | |
| 56 | + | |
| 57 | + /** | |
| 58 | + * Return a new SurfaceData object that represents the current state | |
| 59 | + * of the destination that this SurfaceData object describes. | |
| 60 | + * This method is typically called when the SurfaceData is invalidated. | |
| 61 | + */ | |
| 62 | + public SurfaceData getReplacement() { | |
| 63 | + return this; | |
| 64 | + } | |
| 65 | + | |
| 66 | + private final static NullPipe nullpipe = new NullPipe(); | |
| 67 | + | |
| 68 | + public void validatePipe(SunGraphics2D sg2d) { | |
| 69 | + sg2d.drawpipe = nullpipe; | |
| 70 | + sg2d.fillpipe = nullpipe; | |
| 71 | + sg2d.shapepipe = nullpipe; | |
| 72 | + sg2d.textpipe = nullpipe; | |
| 73 | + sg2d.imagepipe = nullpipe; | |
| 74 | + } | |
| 75 | + | |
| 76 | + public GraphicsConfiguration getDeviceConfiguration() { | |
| 77 | + return null; | |
| 78 | + } | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * Return a readable Raster which contains the pixels for the | |
| 82 | + * specified rectangular region of the destination surface. | |
| 83 | + * The coordinate origin of the returned Raster is the same as | |
| 84 | + * the device space origin of the destination surface. | |
| 85 | + * In some cases the returned Raster might also be writeable. | |
| 86 | + * In most cases, the returned Raster might contain more pixels | |
| 87 | + * than requested. | |
| 88 | + * | |
| 89 | + * @see useTightBBoxes | |
| 90 | + */ | |
| 91 | + public Raster getRaster(int x, int y, int w, int h) { | |
| 92 | + throw new InvalidPipeException("should be NOP"); | |
| 93 | + } | |
| 94 | + | |
| 95 | + /** | |
| 96 | + * Does the pixel accessibility of the destination surface | |
| 97 | + * suggest that rendering algorithms might want to take | |
| 98 | + * extra time to calculate a more accurate bounding box for | |
| 99 | + * the operation being performed? | |
| 100 | + * The typical case when this will be true is when a copy of | |
| 101 | + * the pixels has to be made when doing a getRaster. The | |
| 102 | + * fewer pixels copied, the faster the operation will go. | |
| 103 | + * | |
| 104 | + * @see getRaster | |
| 105 | + */ | |
| 106 | + public boolean useTightBBoxes() { | |
| 107 | + return false; | |
| 108 | + } | |
| 109 | + | |
| 110 | + /** | |
| 111 | + * Returns the pixel data for the specified Argb value packed | |
| 112 | + * into an integer for easy storage and conveyance. | |
| 113 | + */ | |
| 114 | + public int pixelFor(int rgb) { | |
| 115 | + return rgb; | |
| 116 | + } | |
| 117 | + | |
| 118 | + /** | |
| 119 | + * Returns the Argb representation for the specified integer value | |
| 120 | + * which is packed in the format of the associated ColorModel. | |
| 121 | + */ | |
| 122 | + public int rgbFor(int pixel) { | |
| 123 | + return pixel; | |
| 124 | + } | |
| 125 | + | |
| 126 | + /** | |
| 127 | + * Returns the bounds of the destination surface. | |
| 128 | + */ | |
| 129 | + public Rectangle getBounds() { | |
| 130 | + return new Rectangle(); | |
| 131 | + } | |
| 132 | + | |
| 133 | + /** | |
| 134 | + * Performs Security Permissions checks to see if a Custom | |
| 135 | + * Composite object should be allowed access to the pixels | |
| 136 | + * of this surface. | |
| 137 | + */ | |
| 138 | + protected void checkCustomComposite() { | |
| 139 | + return; | |
| 140 | + } | |
| 141 | + | |
| 142 | + /** | |
| 143 | + * Performs a copyarea within this surface. Returns | |
| 144 | + * false if there is no algorithm to perform the copyarea | |
| 145 | + * given the current settings of the SunGraphics2D. | |
| 146 | + */ | |
| 147 | + public boolean copyArea(SunGraphics2D sg2d, | |
| 148 | + int x, int y, int w, int h, int dx, int dy) | |
| 149 | + { | |
| 150 | + return true; | |
| 151 | + } | |
| 152 | + | |
| 153 | + /** | |
| 154 | + * Returns destination Image associated with this SurfaceData (null) | |
| 155 | + */ | |
| 156 | + public Object getDestination() { | |
| 157 | + return null; | |
| 158 | + } | |
| 159 | +} | |
| @@ -0,0 +1,393 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 2000, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d; | |
| 27 | + | |
| 28 | +import java.util.Comparator; | |
| 29 | +import java.util.Collections; | |
| 30 | +import java.util.Iterator; | |
| 31 | +import java.util.List; | |
| 32 | +import java.util.Vector; | |
| 33 | + | |
| 34 | +/** | |
| 35 | + * Maintains a list of half-open intervals, called Spans. | |
| 36 | + * A Span can be tested against the list of Spans | |
| 37 | + * for intersection. | |
| 38 | + */ | |
| 39 | +public class Spans { | |
| 40 | + | |
| 41 | + /** | |
| 42 | + * This class will sort and collapse its span | |
| 43 | + * entries after this many span additions via | |
| 44 | + * the <code>add</code> method. | |
| 45 | + */ | |
| 46 | + private static final int kMaxAddsSinceSort = 256; | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * Holds a list of individual | |
| 50 | + * Span instances. | |
| 51 | + */ | |
| 52 | + private List mSpans = new Vector(kMaxAddsSinceSort); | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * The number of <code>Span</code> | |
| 56 | + * instances that have been added | |
| 57 | + * to this object without a sort | |
| 58 | + * and collapse taking place. | |
| 59 | + */ | |
| 60 | + private int mAddsSinceSort = 0; | |
| 61 | + | |
| 62 | + public Spans() { | |
| 63 | + | |
| 64 | + } | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * Add a span covering the half open interval | |
| 68 | + * including <code>start</code> up to | |
| 69 | + * but not including <code>end</code>. | |
| 70 | + */ | |
| 71 | + public void add(float start, float end) { | |
| 72 | + | |
| 73 | + if (mSpans != null) { | |
| 74 | + mSpans.add(new Span(start, end)); | |
| 75 | + | |
| 76 | + if (++mAddsSinceSort >= kMaxAddsSinceSort) { | |
| 77 | + sortAndCollapse(); | |
| 78 | + } | |
| 79 | + } | |
| 80 | + } | |
| 81 | + | |
| 82 | + /** | |
| 83 | + * Add a span which covers the entire range. | |
| 84 | + * This call is logically equivalent to | |
| 85 | + * <code>add(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY)</code> | |
| 86 | + * The result of making this call is that | |
| 87 | + * all future <code>add</code> calls are ignored | |
| 88 | + * and the <code>intersects</code> method always | |
| 89 | + * returns true. | |
| 90 | + */ | |
| 91 | + public void addInfinite() { | |
| 92 | + mSpans = null; | |
| 93 | + } | |
| 94 | + | |
| 95 | + /** | |
| 96 | + * Returns true if the span defined by the half-open | |
| 97 | + * interval from <code>start</code> up to, | |
| 98 | + * but not including, <code>end</code> intersects | |
| 99 | + * any of the spans defined by this instance. | |
| 100 | + */ | |
| 101 | + public boolean intersects(float start, float end) { | |
| 102 | + boolean doesIntersect; | |
| 103 | + | |
| 104 | + if (mSpans != null) { | |
| 105 | + | |
| 106 | + /* If we have added any spans since we last | |
| 107 | + * sorted and collapsed our list of spans | |
| 108 | + * then we need to resort and collapse. | |
| 109 | + */ | |
| 110 | + if (mAddsSinceSort > 0) { | |
| 111 | + sortAndCollapse(); | |
| 112 | + } | |
| 113 | + | |
| 114 | + /* The SpanIntersection comparator considers | |
| 115 | + * two spans equal if they intersect. If | |
| 116 | + * the search finds a match then we have an | |
| 117 | + * intersection. | |
| 118 | + */ | |
| 119 | + int found = Collections.binarySearch(mSpans, | |
| 120 | + new Span(start, end), | |
| 121 | + SpanIntersection.instance); | |
| 122 | + | |
| 123 | + doesIntersect = found >= 0; | |
| 124 | + | |
| 125 | + /* The addInfinite() method has been invoked so | |
| 126 | + * everything intersect this instance. | |
| 127 | + */ | |
| 128 | + } else { | |
| 129 | + doesIntersect = true; | |
| 130 | + } | |
| 131 | + | |
| 132 | + return doesIntersect; | |
| 133 | + } | |
| 134 | + | |
| 135 | + /** | |
| 136 | + * Sort the spans in ascending order by their | |
| 137 | + * start position. After the spans are sorted | |
| 138 | + * collapse any spans that intersect into a | |
| 139 | + * single span. The result is a sorted, | |
| 140 | + * non-overlapping list of spans. | |
| 141 | + */ | |
| 142 | + private void sortAndCollapse() { | |
| 143 | + | |
| 144 | + Collections.sort(mSpans); | |
| 145 | + mAddsSinceSort = 0; | |
| 146 | + | |
| 147 | + Iterator iter = mSpans.iterator(); | |
| 148 | + | |
| 149 | + /* Have 'span' start at the first span in | |
| 150 | + * the collection. The collection may be empty | |
| 151 | + * so we're careful. | |
| 152 | + */ | |
| 153 | + Span span = null; | |
| 154 | + if (iter.hasNext()) { | |
| 155 | + span = (Span) iter.next(); | |
| 156 | + } | |
| 157 | + | |
| 158 | + /* Loop over the spans collapsing those that intersect | |
| 159 | + * into a single span. | |
| 160 | + */ | |
| 161 | + while (iter.hasNext()) { | |
| 162 | + | |
| 163 | + Span nextSpan = (Span) iter.next(); | |
| 164 | + | |
| 165 | + /* The spans are in ascending start position | |
| 166 | + * order and so the next span's starting point | |
| 167 | + * is either in the span we are trying to grow | |
| 168 | + * or it is beyond the first span and thus the | |
| 169 | + * two spans do not intersect. | |
| 170 | + * | |
| 171 | + * span: <----------< | |
| 172 | + * nextSpan: <------ (intersects) | |
| 173 | + * nextSpan: <------ (doesn't intersect) | |
| 174 | + * | |
| 175 | + * If the spans intersect then we'll remove | |
| 176 | + * nextSpan from the list. If nextSpan's | |
| 177 | + * ending was beyond the first's then | |
| 178 | + * we extend the first. | |
| 179 | + * | |
| 180 | + * span: <----------< | |
| 181 | + * nextSpan: <-----< (don't change span) | |
| 182 | + * nextSpan: <-----------< (grow span) | |
| 183 | + */ | |
| 184 | + | |
| 185 | + if (span.subsume(nextSpan)) { | |
| 186 | + iter.remove(); | |
| 187 | + | |
| 188 | + /* The next span did not intersect the current | |
| 189 | + * span and so it can not be collapsed. Instead | |
| 190 | + * it becomes the start of the next set of spans | |
| 191 | + * to be collapsed. | |
| 192 | + */ | |
| 193 | + } else { | |
| 194 | + span = nextSpan; | |
| 195 | + } | |
| 196 | + } | |
| 197 | + } | |
| 198 | + | |
| 199 | + /* | |
| 200 | + // For debugging. | |
| 201 | + | |
| 202 | + private void printSpans() { | |
| 203 | + System.out.println("----------"); | |
| 204 | + if (mSpans != null) { | |
| 205 | + Iterator iter = mSpans.iterator(); | |
| 206 | + while (iter.hasNext()) { | |
| 207 | + Span span = (Span) iter.next(); | |
| 208 | + System.out.println(span); | |
| 209 | + } | |
| 210 | + } | |
| 211 | + System.out.println("----------"); | |
| 212 | + | |
| 213 | + } | |
| 214 | + */ | |
| 215 | + | |
| 216 | + /** | |
| 217 | + * Holds a single half-open interval. | |
| 218 | + */ | |
| 219 | + static class Span implements Comparable { | |
| 220 | + | |
| 221 | + /** | |
| 222 | + * The span includes the starting point. | |
| 223 | + */ | |
| 224 | + private float mStart; | |
| 225 | + | |
| 226 | + /** | |
| 227 | + * The span goes up to but does not include | |
| 228 | + * the ending point. | |
| 229 | + */ | |
| 230 | + private float mEnd; | |
| 231 | + | |
| 232 | + /** | |
| 233 | + * Create a half-open interval including | |
| 234 | + * <code>start</code> but not including | |
| 235 | + * <code>end</code>. | |
| 236 | + */ | |
| 237 | + Span(float start, float end) { | |
| 238 | + mStart = start; | |
| 239 | + mEnd = end; | |
| 240 | + } | |
| 241 | + | |
| 242 | + /** | |
| 243 | + * Return the start of the <code>Span</code>. | |
| 244 | + * The start is considered part of the | |
| 245 | + * half-open interval. | |
| 246 | + */ | |
| 247 | + final float getStart() { | |
| 248 | + return mStart; | |
| 249 | + } | |
| 250 | + | |
| 251 | + /** | |
| 252 | + * Return the end of the <code>Span</code>. | |
| 253 | + * The end is not considered part of the | |
| 254 | + * half-open interval. | |
| 255 | + */ | |
| 256 | + final float getEnd() { | |
| 257 | + return mEnd; | |
| 258 | + } | |
| 259 | + | |
| 260 | + /** | |
| 261 | + * Change the initial position of the | |
| 262 | + * <code>Span</code>. | |
| 263 | + */ | |
| 264 | + final void setStart(float start) { | |
| 265 | + mStart = start; | |
| 266 | + } | |
| 267 | + | |
| 268 | + /** | |
| 269 | + * Change the terminal position of the | |
| 270 | + * <code>Span</code>. | |
| 271 | + */ | |
| 272 | + final void setEnd(float end) { | |
| 273 | + mEnd = end; | |
| 274 | + } | |
| 275 | + | |
| 276 | + /** | |
| 277 | + * Attempt to alter this <code>Span</code> | |
| 278 | + * to include <code>otherSpan</code> without | |
| 279 | + * altering this span's starting position. | |
| 280 | + * If <code>otherSpan</code> can be so consumed | |
| 281 | + * by this <code>Span</code> then <code>true</code> | |
| 282 | + * is returned. | |
| 283 | + */ | |
| 284 | + boolean subsume(Span otherSpan) { | |
| 285 | + | |
| 286 | + /* We can only subsume 'otherSpan' if | |
| 287 | + * its starting position lies in our | |
| 288 | + * interval. | |
| 289 | + */ | |
| 290 | + boolean isSubsumed = contains(otherSpan.mStart); | |
| 291 | + | |
| 292 | + /* If the other span's starting position | |
| 293 | + * was in our interval and the other span | |
| 294 | + * was longer than this span, then we need | |
| 295 | + * to grow this span to cover the difference. | |
| 296 | + */ | |
| 297 | + if (isSubsumed && otherSpan.mEnd > mEnd) { | |
| 298 | + mEnd = otherSpan.mEnd; | |
| 299 | + } | |
| 300 | + | |
| 301 | + return isSubsumed; | |
| 302 | + } | |
| 303 | + | |
| 304 | + /** | |
| 305 | + * Return true if the passed in position | |
| 306 | + * lies in the half-open interval defined | |
| 307 | + * by this <code>Span</code>. | |
| 308 | + */ | |
| 309 | + boolean contains(float pos) { | |
| 310 | + return mStart <= pos && pos < mEnd; | |
| 311 | + } | |
| 312 | + | |
| 313 | + /** | |
| 314 | + * Rank spans according to their starting | |
| 315 | + * position. The end position is ignored | |
| 316 | + * in this ranking. | |
| 317 | + */ | |
| 318 | + public int compareTo(Object o) { | |
| 319 | + Span otherSpan = (Span) o; | |
| 320 | + float otherStart = otherSpan.getStart(); | |
| 321 | + int result; | |
| 322 | + | |
| 323 | + if (mStart < otherStart) { | |
| 324 | + result = -1; | |
| 325 | + } else if (mStart > otherStart) { | |
| 326 | + result = 1; | |
| 327 | + } else { | |
| 328 | + result = 0; | |
| 329 | + } | |
| 330 | + | |
| 331 | + return result; | |
| 332 | + } | |
| 333 | + | |
| 334 | + public String toString() { | |
| 335 | + return "Span: " + mStart + " to " + mEnd; | |
| 336 | + } | |
| 337 | + | |
| 338 | + } | |
| 339 | + | |
| 340 | + /** | |
| 341 | + * This class ranks a pair of <code>Span</code> | |
| 342 | + * instances. If the instances intersect they | |
| 343 | + * are deemed equal otherwise they are ranked | |
| 344 | + * by their relative position. Use | |
| 345 | + * <code>SpanIntersection.instance</code> to | |
| 346 | + * get the single instance of this class. | |
| 347 | + */ | |
| 348 | + static class SpanIntersection implements Comparator { | |
| 349 | + | |
| 350 | + /** | |
| 351 | + * This class is a Singleton and the following | |
| 352 | + * is the single instance. | |
| 353 | + */ | |
| 354 | + static final SpanIntersection instance = | |
| 355 | + new SpanIntersection(); | |
| 356 | + | |
| 357 | + /** | |
| 358 | + * Only this class can create instances of itself. | |
| 359 | + */ | |
| 360 | + private SpanIntersection() { | |
| 361 | + | |
| 362 | + } | |
| 363 | + | |
| 364 | + public int compare(Object o1, Object o2) { | |
| 365 | + int result; | |
| 366 | + Span span1 = (Span) o1; | |
| 367 | + Span span2 = (Span) o2; | |
| 368 | + | |
| 369 | + /* Span 1 is entirely to the left of span2. | |
| 370 | + * span1: <-----< | |
| 371 | + * span2: <-----< | |
| 372 | + */ | |
| 373 | + if (span1.getEnd() <= span2.getStart()) { | |
| 374 | + result = -1; | |
| 375 | + | |
| 376 | + /* Span 2 is entirely to the right of span2. | |
| 377 | + * span1: <-----< | |
| 378 | + * span2: <-----< | |
| 379 | + */ | |
| 380 | + } else if (span1.getStart() >= span2.getEnd()) { | |
| 381 | + result = 1; | |
| 382 | + | |
| 383 | + /* Otherwise they intersect and we declare them equal. | |
| 384 | + */ | |
| 385 | + } else { | |
| 386 | + result = 0; | |
| 387 | + } | |
| 388 | + | |
| 389 | + return result; | |
| 390 | + } | |
| 391 | + | |
| 392 | + } | |
| 393 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,256 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This interface is implemented by classes which contain complex state | |
| 30 | + * so that other objects can track whether or not their state has changed | |
| 31 | + * since earlier interactions with the object. | |
| 32 | + * <p> | |
| 33 | + * The suggested usage pattern for code that manages some trackable data | |
| 34 | + * is as follows: | |
| 35 | + * <pre> | |
| 36 | + * class Trackable implements StateTrackable { | |
| 37 | + * TrackedInfo data; | |
| 38 | + * State curState = STABLE; | |
| 39 | + * StateTracker curTracker = null; | |
| 40 | + * // Hypothetical method to return a static piece of our tracked data. | |
| 41 | + * // Assume that Datum is either a copy of some piece of the tracked | |
| 42 | + * // data or that it is itself immutable. | |
| 43 | + * public Datum getSomeDatum(int key) { | |
| 44 | + * // No need to modify the state for this type of "get" call. | |
| 45 | + * return data.getDatum(key); | |
| 46 | + * } | |
| 47 | + * // Hypothetical method to return a raw reference to our tracked data. | |
| 48 | + * public TrackedInfo getRawHandleToInfo() { | |
| 49 | + * // Since we are returning a raw reference to our tracked | |
| 50 | + * // data and since we can not track what the caller will | |
| 51 | + * // do with that reference, we can no longer track the | |
| 52 | + * // state of this data. | |
| 53 | + * synchronized (this) { | |
| 54 | + * // Note: modifying both curState and curTracker requires | |
| 55 | + * // synchronization against the getStateTracker method. | |
| 56 | + * curState = UNTRACKABLE; | |
| 57 | + * curTracker = null; | |
| 58 | + * } | |
| 59 | + * return data; | |
| 60 | + * } | |
| 61 | + * // Hypothetical method to set a single piece of data to some | |
| 62 | + * // new static value. | |
| 63 | + * public void setSomeDatum(int key, Datum datum) { | |
| 64 | + * data.setDatum(key, datum); | |
| 65 | + * // We do not need to change state for this, we simply | |
| 66 | + * // invalidate the outstanding StateTracker objects. | |
| 67 | + * // Note: setting curTracker to null requires no synchronization. | |
| 68 | + * curTracker = null; | |
| 69 | + * } | |
| 70 | + * // getStateTracker must be synchronized against any code that | |
| 71 | + * // changes the State. | |
| 72 | + * public synchronized StateTracker getStateTracker() { | |
| 73 | + * StateTracker st = curTracker; | |
| 74 | + * if (st == null) { | |
| 75 | + * switch (curState) { | |
| 76 | + * case IMMUTABLE: st = StateTracker.ALWAYS_CURRENT; break; | |
| 77 | + * case STABLE: st = new Tracker(this); break; | |
| 78 | + * case DYNAMIC: st = StateTracker.NEVER_CURRENT; break; | |
| 79 | + * case UNTRACKABLE: st = StateTracker.NEVER_CURRENT; break; | |
| 80 | + * } | |
| 81 | + * curTracker = st; | |
| 82 | + * } | |
| 83 | + * return st; | |
| 84 | + * } | |
| 85 | + * | |
| 86 | + * static class Tracker implements StateTracker { | |
| 87 | + * Trackable theTrackable; | |
| 88 | + * public Tracker(Trackable t) { | |
| 89 | + * theTrackable = t; | |
| 90 | + * } | |
| 91 | + * public boolean isCurrent() { | |
| 92 | + * return (theTrackable.curTracker == this); | |
| 93 | + * } | |
| 94 | + * } | |
| 95 | + * } | |
| 96 | + * </pre> | |
| 97 | + * Note that the mechanism shown above for invalidating outstanding | |
| 98 | + * StateTracker objects is not the most theoretically conservative | |
| 99 | + * way to implement state tracking in a "set" method. | |
| 100 | + * There is a small window of opportunity after the data has changed | |
| 101 | + * before the outstanding StateTracker objects are invalidated and | |
| 102 | + * where they will indicate that the data is still the same as when | |
| 103 | + * they were instantiated. | |
| 104 | + * While this is technically inaccurate, it is acceptable since the more | |
| 105 | + * conservative approaches to state management are much more complex and | |
| 106 | + * cost much more in terms of performance for a very small gain in | |
| 107 | + * correctness. | |
| 108 | + * For example: | |
| 109 | + * <p> | |
| 110 | + * The most conservative approach would be to synchronize all accesses | |
| 111 | + * and all modifications to the data, including its State. | |
| 112 | + * This would require synchronized blocks around some potentially large | |
| 113 | + * bodies of code which would impact the multi-threaded scalability of | |
| 114 | + * the implementation. | |
| 115 | + * Further, if data is to be coordinated or transferred between two | |
| 116 | + * trackable objects then both would need to be synchronized raising | |
| 117 | + * the possibility of deadlock unless some strict rules of priority | |
| 118 | + * for the locking of the objects were established and followed | |
| 119 | + * religiously. | |
| 120 | + * Either or both of these drawbacks makes such an implementation | |
| 121 | + * infeasible. | |
| 122 | + * <p> | |
| 123 | + * A less conservative approach would be to change the state of the | |
| 124 | + * trackable object to DYNAMIC during all modifications of the data | |
| 125 | + * and then to change it back to STABLE after those modifications | |
| 126 | + * are complete. | |
| 127 | + * While this state transition more accurately reflects the temporary | |
| 128 | + * loss of tracking during the modification phase, in reality the | |
| 129 | + * time period of the modifications would be small in most cases | |
| 130 | + * and the 2 changes of state would each require synchronization. | |
| 131 | + * <p> | |
| 132 | + * In comparison the act of setting the <code>curTracker</code> | |
| 133 | + * reference to null in the usage pattern above effectively invalidates | |
| 134 | + * all outstanding <code>Tracker</code> objects as soon as possible | |
| 135 | + * after the change to the data and requires very little code and no | |
| 136 | + * synchronization to implement. | |
| 137 | + * <p> | |
| 138 | + * In the end it is up to the implementor of a StateTrackable object | |
| 139 | + * how fine the granularity of State updates should be managed based | |
| 140 | + * on the frequency and atomicity of the modifications and the | |
| 141 | + * consequences of returning an inaccurate State for a particularly | |
| 142 | + * small window of opportunity. | |
| 143 | + * Most implementations are likely to follow the liberal, but efficient | |
| 144 | + * guidelines found in the usage pattern proposed above. | |
| 145 | + * | |
| 146 | + * @since 1.7 | |
| 147 | + */ | |
| 148 | +public interface StateTrackable { | |
| 149 | + /** | |
| 150 | + * An enumeration describing the current state of a trackable | |
| 151 | + * object. | |
| 152 | + * These values describe how often the complex data contained | |
| 153 | + * in a trackable object can be changed and whether or not it | |
| 154 | + * makes sense to try to track the data in its current state. | |
| 155 | + * @see StateTrackable#getState | |
| 156 | + * @since 1.7 | |
| 157 | + */ | |
| 158 | + public enum State { | |
| 159 | + /** | |
| 160 | + * The complex data will never change again. | |
| 161 | + * Information related to the current contents of the complex | |
| 162 | + * data can be calculated and cached indefinitely with no | |
| 163 | + * further checks to see if the information is stale. | |
| 164 | + */ | |
| 165 | + IMMUTABLE, | |
| 166 | + | |
| 167 | + /** | |
| 168 | + * The complex data is currently stable, but could change at | |
| 169 | + * some point in the future. | |
| 170 | + * Information related to the current contents of the complex | |
| 171 | + * data can be calculated and cached, but a StateTracker should | |
| 172 | + * be used to verify the freshness of such precalculated data | |
| 173 | + * before each future use. | |
| 174 | + */ | |
| 175 | + STABLE, | |
| 176 | + | |
| 177 | + /** | |
| 178 | + * The complex data is currently in flux and is frequently | |
| 179 | + * changing. | |
| 180 | + * While information related to the current contents of the | |
| 181 | + * complex data could be calculated and cached, there is a | |
| 182 | + * reasonably high probability that the cached information | |
| 183 | + * would be found to be out of date by the next time it is | |
| 184 | + * used. | |
| 185 | + * It may also be the case that the current contents are | |
| 186 | + * temporarily untrackable, but that they may become trackable | |
| 187 | + * again in the future. | |
| 188 | + */ | |
| 189 | + DYNAMIC, | |
| 190 | + | |
| 191 | + /** | |
| 192 | + * The complex data can currently be changed by external | |
| 193 | + * references and agents in a way that cannot be tracked. | |
| 194 | + * If any information about the current contents of the complex | |
| 195 | + * data were to be cached, there would be no way to determine | |
| 196 | + * whether or not that cached information was out of date. | |
| 197 | + */ | |
| 198 | + UNTRACKABLE, | |
| 199 | + }; | |
| 200 | + | |
| 201 | + /** | |
| 202 | + * Returns the general state of the complex data held by this | |
| 203 | + * object. | |
| 204 | + * This return value can be used to determine if it makes | |
| 205 | + * strategic sense to try and cache information about the current | |
| 206 | + * contents of this object. | |
| 207 | + * The StateTracker returned from the getStateTracker() method | |
| 208 | + * will further aid in determining when the data has been | |
| 209 | + * changed so that the caches can be verified upon future uses. | |
| 210 | + * @return the current state of trackability of the complex | |
| 211 | + * data stored in this object. | |
| 212 | + * @see #getStateTracker | |
| 213 | + * @since 1.7 | |
| 214 | + */ | |
| 215 | + public State getState(); | |
| 216 | + | |
| 217 | + /** | |
| 218 | + * Returns an object which can track future changes to the | |
| 219 | + * complex data stored in this object. | |
| 220 | + * If an external agent caches information about the complex | |
| 221 | + * data of this object, it should first get a StateTracker | |
| 222 | + * object from this method so that it can check if such | |
| 223 | + * information is current upon future uses. | |
| 224 | + * Note that a valid StateTracker will always be returned | |
| 225 | + * regardless of the return value of getState(), but in some | |
| 226 | + * cases the StateTracker may be a trivial implementation | |
| 227 | + * which always returns the same value from its | |
| 228 | + * {@link StateTracker#isCurrent isCurrent} method. | |
| 229 | + * <ul> | |
| 230 | + * <li>If the current state is {@link State#IMMUTABLE IMMUTABLE}, | |
| 231 | + * this StateTracker and any future StateTracker objects | |
| 232 | + * returned from this method will always indicate that | |
| 233 | + * the state has not changed.</li> | |
| 234 | + * <li>If the current state is {@link State#UNTRACKABLE UNTRACKABLE}, | |
| 235 | + * this StateTracker and any future StateTracker objects | |
| 236 | + * returned from this method will always indicate that | |
| 237 | + * the state has changed.</li> | |
| 238 | + * <li>If the current state is {@link State#DYNAMIC DYNAMIC}, | |
| 239 | + * this StateTracker may always indicate that the current | |
| 240 | + * state has changed, but another StateTracker returned | |
| 241 | + * from this method in the future when the state has changed | |
| 242 | + * to {@link State#STABLE STABLE} will correctly track changes.</li> | |
| 243 | + * <li>Otherwise the current state is {@link State#STABLE STABLE} | |
| 244 | + * and this StateTracker will indicate whether or not the | |
| 245 | + * data has changed since the time at which it was fetched | |
| 246 | + * from the object.</li> | |
| 247 | + * </ul> | |
| 248 | + * @return an object implementing the StateTracker interface | |
| 249 | + * that tracks whether changes have been made to the complex | |
| 250 | + * contents of this object since it was returned. | |
| 251 | + * @see State | |
| 252 | + * @see #getState | |
| 253 | + * @since 1.7 | |
| 254 | + */ | |
| 255 | + public StateTracker getStateTracker(); | |
| 256 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,256 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d; | |
| 27 | + | |
| 28 | +import sun.java2d.StateTrackable.State; | |
| 29 | +import static sun.java2d.StateTrackable.State.*; | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * This class provides a basic pre-packaged implementation of the | |
| 33 | + * complete {@link StateTrackable} interface with implementations | |
| 34 | + * of the required methods in the interface and methods to manage | |
| 35 | + * transitions in the state of the object. | |
| 36 | + * Classes which wish to implement StateTrackable could create an | |
| 37 | + * instance of this class and delegate all of their implementations | |
| 38 | + * for {@code StateTrackable} methods to the corresponding methods | |
| 39 | + * of this class. | |
| 40 | + */ | |
| 41 | +public final class StateTrackableDelegate implements StateTrackable { | |
| 42 | + /** | |
| 43 | + * The {@code UNTRACKABLE_DELEGATE} provides an implementation | |
| 44 | + * of the StateTrackable interface that is permanently in the | |
| 45 | + * {@link State#UNTRACKABLE UNTRACKABLE} state. | |
| 46 | + */ | |
| 47 | + public final static StateTrackableDelegate UNTRACKABLE_DELEGATE = | |
| 48 | + new StateTrackableDelegate(UNTRACKABLE); | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * The {@code IMMUTABLE_DELEGATE} provides an implementation | |
| 52 | + * of the StateTrackable interface that is permanently in the | |
| 53 | + * {@link State#IMMUTABLE IMMUTABLE} state. | |
| 54 | + */ | |
| 55 | + public final static StateTrackableDelegate IMMUTABLE_DELEGATE = | |
| 56 | + new StateTrackableDelegate(IMMUTABLE); | |
| 57 | + | |
| 58 | + /** | |
| 59 | + * Returns a {@code StateTrackableDelegate} instance with the | |
| 60 | + * specified initial {@link State State}. | |
| 61 | + * If the specified {@code State} is | |
| 62 | + * {@link State#UNTRACKABLE UNTRACKABLE} or | |
| 63 | + * {@link State#IMMUTABLE IMMUTABLE} | |
| 64 | + * then the approprirate static instance | |
| 65 | + * {@link #UNTRACKABLE_DELEGATE} or {@link #IMMUTABLE_DELEGATE} | |
| 66 | + * is returned. | |
| 67 | + */ | |
| 68 | + public static StateTrackableDelegate createInstance(State state) { | |
| 69 | + switch (state) { | |
| 70 | + case UNTRACKABLE: | |
| 71 | + return UNTRACKABLE_DELEGATE; | |
| 72 | + case STABLE: | |
| 73 | + return new StateTrackableDelegate(STABLE); | |
| 74 | + case DYNAMIC: | |
| 75 | + return new StateTrackableDelegate(DYNAMIC); | |
| 76 | + case IMMUTABLE: | |
| 77 | + return IMMUTABLE_DELEGATE; | |
| 78 | + default: | |
| 79 | + throw new InternalError("unknown state"); | |
| 80 | + } | |
| 81 | + } | |
| 82 | + | |
| 83 | + private State theState; | |
| 84 | + StateTracker theTracker; // package private for easy access from tracker | |
| 85 | + private int numDynamicAgents; | |
| 86 | + | |
| 87 | + /** | |
| 88 | + * Constructs a StateTrackableDelegate object with the specified | |
| 89 | + * initial State. | |
| 90 | + */ | |
| 91 | + private StateTrackableDelegate(State state) { | |
| 92 | + this.theState = state; | |
| 93 | + } | |
| 94 | + | |
| 95 | + /** | |
| 96 | + * @inheritDoc | |
| 97 | + * @since 1.7 | |
| 98 | + */ | |
| 99 | + public State getState() { | |
| 100 | + return theState; | |
| 101 | + } | |
| 102 | + | |
| 103 | + /** | |
| 104 | + * @inheritDoc | |
| 105 | + * @since 1.7 | |
| 106 | + */ | |
| 107 | + public synchronized StateTracker getStateTracker() { | |
| 108 | + StateTracker st = theTracker; | |
| 109 | + if (st == null) { | |
| 110 | + switch (theState) { | |
| 111 | + case IMMUTABLE: | |
| 112 | + st = StateTracker.ALWAYS_CURRENT; | |
| 113 | + break; | |
| 114 | + case STABLE: | |
| 115 | + st = new StateTracker() { | |
| 116 | + public boolean isCurrent() { | |
| 117 | + return (theTracker == this); | |
| 118 | + } | |
| 119 | + }; | |
| 120 | + break; | |
| 121 | + case DYNAMIC: | |
| 122 | + // We return the NEVER_CURRENT tracker, but that is | |
| 123 | + // just temporary while we are in the DYNAMIC state. | |
| 124 | + // NO BREAK | |
| 125 | + case UNTRACKABLE: | |
| 126 | + st = StateTracker.NEVER_CURRENT; | |
| 127 | + break; | |
| 128 | + } | |
| 129 | + theTracker = st; | |
| 130 | + } | |
| 131 | + return st; | |
| 132 | + } | |
| 133 | + | |
| 134 | + /** | |
| 135 | + * This method provides an easy way for delegating classes to | |
| 136 | + * change the overall {@link State State} of the delegate to | |
| 137 | + * {@link State#IMMUTABLE IMMUTABLE}. | |
| 138 | + * @throws IllegalStateException if the current state is | |
| 139 | + * {@link State#UNTRACKABLE UNTRACKABLE} | |
| 140 | + * @see #setUntrackable | |
| 141 | + * @since 1.7 | |
| 142 | + */ | |
| 143 | + public synchronized void setImmutable() { | |
| 144 | + if (theState == UNTRACKABLE || theState == DYNAMIC) { | |
| 145 | + throw new IllegalStateException("UNTRACKABLE or DYNAMIC "+ | |
| 146 | + "objects cannot become IMMUTABLE"); | |
| 147 | + } | |
| 148 | + theState = IMMUTABLE; | |
| 149 | + theTracker = null; | |
| 150 | + } | |
| 151 | + | |
| 152 | + /** | |
| 153 | + * This method provides an easy way for delegating classes to | |
| 154 | + * change the overall {@link State State} of the delegate to | |
| 155 | + * {@link State#UNTRACKABLE UNTRACKABLE}. | |
| 156 | + * This method is typically called when references to the | |
| 157 | + * internal data buffers have been made public. | |
| 158 | + * @throws IllegalStateException if the current state is | |
| 159 | + * {@link State#IMMUTABLE IMMUTABLE} | |
| 160 | + * @see #setImmutable | |
| 161 | + * @since 1.7 | |
| 162 | + */ | |
| 163 | + public synchronized void setUntrackable() { | |
| 164 | + if (theState == IMMUTABLE) { | |
| 165 | + throw new IllegalStateException("IMMUTABLE objects cannot "+ | |
| 166 | + "become UNTRACKABLE"); | |
| 167 | + } | |
| 168 | + theState = UNTRACKABLE; | |
| 169 | + theTracker = null; | |
| 170 | + } | |
| 171 | + | |
| 172 | + /** | |
| 173 | + * This method provides an easy way for delegating classes to | |
| 174 | + * manage temporarily setting the overall {@link State State} | |
| 175 | + * of the delegate to {@link State#DYNAMIC DYNAMIC} | |
| 176 | + * during well-defined time frames of dynamic pixel updating. | |
| 177 | + * This method should be called once before each flow of control | |
| 178 | + * that might dynamically update the pixels in an uncontrolled | |
| 179 | + * or unpredictable fashion. | |
| 180 | + * <p> | |
| 181 | + * The companion method {@link #removeDynamicAgent} method should | |
| 182 | + * also be called once after each such flow of control has ended. | |
| 183 | + * Failing to call the remove method will result in this object | |
| 184 | + * permanently becoming {@link State#DYNAMIC DYNAMIC} | |
| 185 | + * and therefore effectively untrackable. | |
| 186 | + * <p> | |
| 187 | + * This method will only change the {@link State State} of the | |
| 188 | + * delegate if it is currently {@link State#STABLE STABLE}. | |
| 189 | + * | |
| 190 | + * @throws IllegalStateException if the current state is | |
| 191 | + * {@link State#IMMUTABLE IMMUTABLE} | |
| 192 | + * @since 1.7 | |
| 193 | + */ | |
| 194 | + public synchronized void addDynamicAgent() { | |
| 195 | + if (theState == IMMUTABLE) { | |
| 196 | + throw new IllegalStateException("Cannot change state from "+ | |
| 197 | + "IMMUTABLE"); | |
| 198 | + } | |
| 199 | + ++numDynamicAgents; | |
| 200 | + if (theState == STABLE) { | |
| 201 | + theState = DYNAMIC; | |
| 202 | + theTracker = null; | |
| 203 | + } | |
| 204 | + } | |
| 205 | + | |
| 206 | + /** | |
| 207 | + * This method provides an easy way for delegating classes to | |
| 208 | + * manage restoring the overall {@link State State} of the | |
| 209 | + * delegate back to {@link State#STABLE STABLE} | |
| 210 | + * after a well-defined time frame of dynamic pixel updating. | |
| 211 | + * This method should be called once after each flow of control | |
| 212 | + * that might dynamically update the pixels in an uncontrolled | |
| 213 | + * or unpredictable fashion has ended. | |
| 214 | + * <p> | |
| 215 | + * The companion method {@link #addDynamicAgent} method should | |
| 216 | + * have been called at some point before each such flow of | |
| 217 | + * control began. | |
| 218 | + * If this method is called without having previously called | |
| 219 | + * the add method, the {@link State State} of this object | |
| 220 | + * will become unreliable. | |
| 221 | + * <p> | |
| 222 | + * This method will only change the {@link State State} of the | |
| 223 | + * delegate if the number of outstanding dynamic agents has | |
| 224 | + * gone to 0 and it is currently | |
| 225 | + * {@link State#DYNAMIC DYNAMIC}. | |
| 226 | + * | |
| 227 | + * @since 1.7 | |
| 228 | + */ | |
| 229 | + protected synchronized void removeDynamicAgent() { | |
| 230 | + if (--numDynamicAgents == 0 && theState == DYNAMIC) { | |
| 231 | + theState = STABLE; | |
| 232 | + theTracker = null; | |
| 233 | + } | |
| 234 | + } | |
| 235 | + | |
| 236 | + /** | |
| 237 | + * This method provides an easy way for delegating classes to | |
| 238 | + * indicate that the contents have changed. | |
| 239 | + * This method will invalidate outstanding StateTracker objects | |
| 240 | + * so that any other agents which maintain cached information | |
| 241 | + * about the pixels will know to refresh their cached copies. | |
| 242 | + * This method should be called after every modification to | |
| 243 | + * the data, such as any calls to any of the setElem methods. | |
| 244 | + * <p> | |
| 245 | + * Note that, for efficiency, this method does not check the | |
| 246 | + * {@link State State} of the object to see if it is compatible | |
| 247 | + * with being marked dirty | |
| 248 | + * (i.e. not {@link State#IMMUTABLE IMMUTABLE}). | |
| 249 | + * It is up to the callers to enforce the fact that an | |
| 250 | + * {@code IMMUTABLE} delegate is never modified. | |
| 251 | + * @since 1.7 | |
| 252 | + */ | |
| 253 | + public final void markDirty() { | |
| 254 | + theTracker = null; | |
| 255 | + } | |
| 256 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,104 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This interface is used to track changes to the complex data of an | |
| 30 | + * object that implements the StateTrackable interface. | |
| 31 | + * <p> | |
| 32 | + * The usage pattern for code accessing the trackable data is as follows: | |
| 33 | + * <pre> | |
| 34 | + * StateTrackable trackedobject; | |
| 35 | + * MyInfo cacheddata; | |
| 36 | + * StateTracker cachetracker; | |
| 37 | + * public synchronized MyInfo getInfoAbout(StateTrackable obj) { | |
| 38 | + * if (trackedobject != obj || !cachetracker.isCurrent()) { | |
| 39 | + * // Note: Always call getStateTracker() before | |
| 40 | + * // caching any data about the objct... | |
| 41 | + * cachetracker = obj.getStateTracker(); | |
| 42 | + * cacheddata = calculateInfoFrom(obj); | |
| 43 | + * trackedobject = obj; | |
| 44 | + * } | |
| 45 | + * return cacheddata; | |
| 46 | + * } | |
| 47 | + * </pre> | |
| 48 | + * Note that the sample code above works correctly regardless of the | |
| 49 | + * {@link StateTrackable.State State} of the complex data of the object, | |
| 50 | + * but it may be inefficient to store precalculated information about | |
| 51 | + * an object whose current {@link StateTrackable.State State} is | |
| 52 | + * {@link StateTrackable.State#UNTRACKABLE UNTRACKABLE} | |
| 53 | + * and it is unnecessary to perform the {@link #isCurrent} test for | |
| 54 | + * data whose current {@link StateTrackable.State State} is | |
| 55 | + * {@link StateTrackable.State#IMMUTABLE IMMUTABLE}. | |
| 56 | + * Optimizations to the sample code for either or both of those terminal | |
| 57 | + * States may be of benefit for some use cases, but is left out of the | |
| 58 | + * example to reduce its complexity. | |
| 59 | + * | |
| 60 | + * @see StateTrackable.State | |
| 61 | + * @since 1.7 | |
| 62 | + */ | |
| 63 | +public interface StateTracker { | |
| 64 | + /** | |
| 65 | + * An implementation of the StateTracker interface which | |
| 66 | + * always returns true. | |
| 67 | + * This implementation is useful for objects whose current | |
| 68 | + * {@link StateTrackable.State State} is | |
| 69 | + * {@link StateTrackable.State#IMMUTABLE IMMUTABLE}. | |
| 70 | + * @since 1.7 | |
| 71 | + */ | |
| 72 | + public StateTracker ALWAYS_CURRENT = new StateTracker() { | |
| 73 | + public boolean isCurrent() { | |
| 74 | + return true; | |
| 75 | + } | |
| 76 | + }; | |
| 77 | + | |
| 78 | + /** | |
| 79 | + * An implementation of the StateTracker interface which | |
| 80 | + * always returns false. | |
| 81 | + * This implementation is useful for objects whose current | |
| 82 | + * {@link StateTrackable.State State} is | |
| 83 | + * {@link StateTrackable.State#UNTRACKABLE UNTRACKABLE}. | |
| 84 | + * This implementation may also be useful for some objects | |
| 85 | + * whose current {@link StateTrackable.State State} is | |
| 86 | + * {@link StateTrackable.State#DYNAMIC DYNAMIC}. | |
| 87 | + * @since 1.7 | |
| 88 | + */ | |
| 89 | + public StateTracker NEVER_CURRENT = new StateTracker() { | |
| 90 | + public boolean isCurrent() { | |
| 91 | + return false; | |
| 92 | + } | |
| 93 | + }; | |
| 94 | + | |
| 95 | + /** | |
| 96 | + * Returns true iff the contents of the complex data of the | |
| 97 | + * associated StateTrackable object have not changed since | |
| 98 | + * the time that this StateTracker was returned from its | |
| 99 | + * getStateTracker() method. | |
| 100 | + * @see StateTrackable | |
| 101 | + * @since 1.7 | |
| 102 | + */ | |
| 103 | + public boolean isCurrent(); | |
| 104 | +} | |
Binary file not shown.
| @@ -0,0 +1,129 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d; | |
| 27 | + | |
| 28 | +import java.awt.Composite; | |
| 29 | +import java.awt.CompositeContext; | |
| 30 | +import java.awt.AlphaComposite; | |
| 31 | +import java.awt.image.ColorModel; | |
| 32 | +import java.awt.image.BufferedImage; | |
| 33 | +import java.awt.image.Raster; | |
| 34 | +import java.awt.image.WritableRaster; | |
| 35 | +import sun.awt.image.BufImgSurfaceData; | |
| 36 | +import sun.java2d.loops.XORComposite; | |
| 37 | +import sun.java2d.loops.CompositeType; | |
| 38 | +import sun.java2d.loops.Blit; | |
| 39 | + | |
| 40 | +public class SunCompositeContext implements CompositeContext { | |
| 41 | + ColorModel srcCM; | |
| 42 | + ColorModel dstCM; | |
| 43 | + Composite composite; | |
| 44 | + CompositeType comptype; | |
| 45 | + | |
| 46 | + public SunCompositeContext(AlphaComposite ac, | |
| 47 | + ColorModel s, ColorModel d) | |
| 48 | + { | |
| 49 | + if (s == null) { | |
| 50 | + throw new NullPointerException("Source color model cannot be null"); | |
| 51 | + } | |
| 52 | + if (d == null) { | |
| 53 | + throw new NullPointerException("Destination color model cannot be null"); | |
| 54 | + } | |
| 55 | + srcCM = s; | |
| 56 | + dstCM = d; | |
| 57 | + this.composite = ac; | |
| 58 | + this.comptype = CompositeType.forAlphaComposite(ac); | |
| 59 | + } | |
| 60 | + | |
| 61 | + public SunCompositeContext(XORComposite xc, | |
| 62 | + ColorModel s, ColorModel d) | |
| 63 | + { | |
| 64 | + if (s == null) { | |
| 65 | + throw new NullPointerException("Source color model cannot be null"); | |
| 66 | + } | |
| 67 | + if (d == null) { | |
| 68 | + throw new NullPointerException("Destination color model cannot be null"); | |
| 69 | + } | |
| 70 | + srcCM = s; | |
| 71 | + dstCM = d; | |
| 72 | + this.composite = xc; | |
| 73 | + this.comptype = CompositeType.Xor; | |
| 74 | + } | |
| 75 | + | |
| 76 | + /** | |
| 77 | + * Release resources allocated for context. | |
| 78 | + */ | |
| 79 | + public void dispose() { | |
| 80 | + } | |
| 81 | + | |
| 82 | + /** | |
| 83 | + * This method composes the two source tiles | |
| 84 | + * and places the result in the destination tile. Note that | |
| 85 | + * the destination can be the same object as either | |
| 86 | + * the first or second source. | |
| 87 | + * @param src1 The first source tile for the compositing operation. | |
| 88 | + * @param src2 The second source tile for the compositing operation. | |
| 89 | + * @param dst The tile where the result of the operation is stored. | |
| 90 | + */ | |
| 91 | + public void compose(Raster srcArg, Raster dstIn, WritableRaster dstOut) { | |
| 92 | + WritableRaster src; | |
| 93 | + int w; | |
| 94 | + int h; | |
| 95 | + | |
| 96 | + if (dstIn != dstOut) { | |
| 97 | + dstOut.setDataElements(0, 0, dstIn); | |
| 98 | + } | |
| 99 | + | |
| 100 | + // REMIND: We should be able to create a SurfaceData from just | |
| 101 | + // a non-writable Raster and a ColorModel. Since we need to | |
| 102 | + // create a SurfaceData from a BufferedImage then we need to | |
| 103 | + // make a WritableRaster since it is needed to construct a | |
| 104 | + // BufferedImage. | |
| 105 | + if (srcArg instanceof WritableRaster) { | |
| 106 | + src = (WritableRaster) srcArg; | |
| 107 | + } else { | |
| 108 | + src = srcArg.createCompatibleWritableRaster(); | |
| 109 | + src.setDataElements(0, 0, srcArg); | |
| 110 | + } | |
| 111 | + | |
| 112 | + w = Math.min(src.getWidth(), dstIn.getWidth()); | |
| 113 | + h = Math.min(src.getHeight(), dstIn.getHeight()); | |
| 114 | + | |
| 115 | + BufferedImage srcImg = new BufferedImage(srcCM, src, | |
| 116 | + srcCM.isAlphaPremultiplied(), | |
| 117 | + null); | |
| 118 | + BufferedImage dstImg = new BufferedImage(dstCM, dstOut, | |
| 119 | + dstCM.isAlphaPremultiplied(), | |
| 120 | + null); | |
| 121 | + | |
| 122 | + SurfaceData srcData = BufImgSurfaceData.createData(srcImg); | |
| 123 | + SurfaceData dstData = BufImgSurfaceData.createData(dstImg); | |
| 124 | + Blit blit = Blit.getFromCache(srcData.getSurfaceType(), | |
| 125 | + comptype, | |
| 126 | + dstData.getSurfaceType()); | |
| 127 | + blit.Blit(srcData, dstData, composite, null, 0, 0, 0, 0, w, h); | |
| 128 | + } | |
| 129 | +} | |
Binary file not shown.
| @@ -0,0 +1,3310 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d; | |
| 27 | + | |
| 28 | +import java.awt.Graphics; | |
| 29 | +import java.awt.Graphics2D; | |
| 30 | +import java.awt.RenderingHints; | |
| 31 | +import java.awt.RenderingHints.Key; | |
| 32 | +import java.awt.geom.Area; | |
| 33 | +import java.awt.geom.AffineTransform; | |
| 34 | +import java.awt.geom.NoninvertibleTransformException; | |
| 35 | +import java.awt.AlphaComposite; | |
| 36 | +import java.awt.BasicStroke; | |
| 37 | +import java.awt.image.BufferedImage; | |
| 38 | +import java.awt.image.BufferedImageOp; | |
| 39 | +import java.awt.image.RenderedImage; | |
| 40 | +import java.awt.image.renderable.RenderableImage; | |
| 41 | +import java.awt.image.renderable.RenderContext; | |
| 42 | +import java.awt.image.AffineTransformOp; | |
| 43 | +import java.awt.image.Raster; | |
| 44 | +import java.awt.image.WritableRaster; | |
| 45 | +import java.awt.Image; | |
| 46 | +import java.awt.Composite; | |
| 47 | +import java.awt.Color; | |
| 48 | +import java.awt.image.ColorModel; | |
| 49 | +import java.awt.GraphicsConfiguration; | |
| 50 | +import java.awt.Paint; | |
| 51 | +import java.awt.GradientPaint; | |
| 52 | +import java.awt.LinearGradientPaint; | |
| 53 | +import java.awt.RadialGradientPaint; | |
| 54 | +import java.awt.TexturePaint; | |
| 55 | +import java.awt.geom.Rectangle2D; | |
| 56 | +import java.awt.geom.PathIterator; | |
| 57 | +import java.awt.geom.GeneralPath; | |
| 58 | +import java.awt.Shape; | |
| 59 | +import java.awt.Stroke; | |
| 60 | +import java.awt.FontMetrics; | |
| 61 | +import java.awt.Rectangle; | |
| 62 | +import java.text.AttributedCharacterIterator; | |
| 63 | +import java.awt.Font; | |
| 64 | +import java.awt.image.ImageObserver; | |
| 65 | +import java.awt.Transparency; | |
| 66 | +import java.awt.font.GlyphVector; | |
| 67 | +import java.awt.font.TextLayout; | |
| 68 | +import sun.font.FontDesignMetrics; | |
| 69 | +import sun.font.FontUtilities; | |
| 70 | +import sun.java2d.pipe.PixelDrawPipe; | |
| 71 | +import sun.java2d.pipe.PixelFillPipe; | |
| 72 | +import sun.java2d.pipe.ShapeDrawPipe; | |
| 73 | +import sun.java2d.pipe.ValidatePipe; | |
| 74 | +import sun.java2d.pipe.ShapeSpanIterator; | |
| 75 | +import sun.java2d.pipe.Region; | |
| 76 | +import sun.java2d.pipe.TextPipe; | |
| 77 | +import sun.java2d.pipe.DrawImagePipe; | |
| 78 | +import sun.java2d.pipe.LoopPipe; | |
| 79 | +import sun.java2d.loops.FontInfo; | |
| 80 | +import sun.java2d.loops.RenderLoops; | |
| 81 | +import sun.java2d.loops.CompositeType; | |
| 82 | +import sun.java2d.loops.SurfaceType; | |
| 83 | +import sun.java2d.loops.Blit; | |
| 84 | +import sun.java2d.loops.MaskFill; | |
| 85 | +import sun.font.FontManager; | |
| 86 | +import java.awt.font.FontRenderContext; | |
| 87 | +import sun.java2d.loops.XORComposite; | |
| 88 | +import sun.awt.ConstrainableGraphics; | |
| 89 | +import sun.awt.SunHints; | |
| 90 | +import java.util.Map; | |
| 91 | +import java.util.Iterator; | |
| 92 | +import sun.java2d.DestSurfaceProvider; | |
| 93 | +import sun.misc.PerformanceLogger; | |
| 94 | + | |
| 95 | +/** | |
| 96 | + * This is a the master Graphics2D superclass for all of the Sun | |
| 97 | + * Graphics implementations. This class relies on subclasses to | |
| 98 | + * manage the various device information, but provides an overall | |
| 99 | + * general framework for performing all of the requests in the | |
| 100 | + * Graphics and Graphics2D APIs. | |
| 101 | + * | |
| 102 | + * @author Jim Graham | |
| 103 | + */ | |
| 104 | +public final class SunGraphics2D | |
| 105 | + extends Graphics2D | |
| 106 | + implements ConstrainableGraphics, Cloneable, DestSurfaceProvider | |
| 107 | +{ | |
| 108 | + /* | |
| 109 | + * Attribute States | |
| 110 | + */ | |
| 111 | + /* Paint */ | |
| 112 | + public static final int PAINT_CUSTOM = 6; /* Any other Paint object */ | |
| 113 | + public static final int PAINT_TEXTURE = 5; /* Tiled Image */ | |
| 114 | + public static final int PAINT_RAD_GRADIENT = 4; /* Color RadialGradient */ | |
| 115 | + public static final int PAINT_LIN_GRADIENT = 3; /* Color LinearGradient */ | |
| 116 | + public static final int PAINT_GRADIENT = 2; /* Color Gradient */ | |
| 117 | + public static final int PAINT_ALPHACOLOR = 1; /* Non-opaque Color */ | |
| 118 | + public static final int PAINT_OPAQUECOLOR = 0; /* Opaque Color */ | |
| 119 | + | |
| 120 | + /* Composite*/ | |
| 121 | + public static final int COMP_CUSTOM = 3;/* Custom Composite */ | |
| 122 | + public static final int COMP_XOR = 2;/* XOR Mode Composite */ | |
| 123 | + public static final int COMP_ALPHA = 1;/* AlphaComposite */ | |
| 124 | + public static final int COMP_ISCOPY = 0;/* simple stores into destination, | |
| 125 | + * i.e. Src, SrcOverNoEa, and other | |
| 126 | + * alpha modes which replace | |
| 127 | + * the destination. | |
| 128 | + */ | |
| 129 | + | |
| 130 | + /* Stroke */ | |
| 131 | + public static final int STROKE_CUSTOM = 3; /* custom Stroke */ | |
| 132 | + public static final int STROKE_WIDE = 2; /* BasicStroke */ | |
| 133 | + public static final int STROKE_THINDASHED = 1; /* BasicStroke */ | |
| 134 | + public static final int STROKE_THIN = 0; /* BasicStroke */ | |
| 135 | + | |
| 136 | + /* Transform */ | |
| 137 | + public static final int TRANSFORM_GENERIC = 4; /* any 3x2 */ | |
| 138 | + public static final int TRANSFORM_TRANSLATESCALE = 3; /* scale XY */ | |
| 139 | + public static final int TRANSFORM_ANY_TRANSLATE = 2; /* non-int translate */ | |
| 140 | + public static final int TRANSFORM_INT_TRANSLATE = 1; /* int translate */ | |
| 141 | + public static final int TRANSFORM_ISIDENT = 0; /* Identity */ | |
| 142 | + | |
| 143 | + /* Clipping */ | |
| 144 | + public static final int CLIP_SHAPE = 2; /* arbitrary clip */ | |
| 145 | + public static final int CLIP_RECTANGULAR = 1; /* rectangular clip */ | |
| 146 | + public static final int CLIP_DEVICE = 0; /* no clipping set */ | |
| 147 | + | |
| 148 | + /* The following fields are used when the current Paint is a Color. */ | |
| 149 | + public int eargb; // ARGB value with ExtraAlpha baked in | |
| 150 | + public int pixel; // pixel value for eargb | |
| 151 | + | |
| 152 | + public SurfaceData surfaceData; | |
| 153 | + | |
| 154 | + public PixelDrawPipe drawpipe; | |
| 155 | + public PixelFillPipe fillpipe; | |
| 156 | + public DrawImagePipe imagepipe; | |
| 157 | + public ShapeDrawPipe shapepipe; | |
| 158 | + public TextPipe textpipe; | |
| 159 | + public MaskFill alphafill; | |
| 160 | + | |
| 161 | + public RenderLoops loops; | |
| 162 | + | |
| 163 | + public CompositeType imageComp; /* Image Transparency checked on fly */ | |
| 164 | + | |
| 165 | + public int paintState; | |
| 166 | + public int compositeState; | |
| 167 | + public int strokeState; | |
| 168 | + public int transformState; | |
| 169 | + public int clipState; | |
| 170 | + | |
| 171 | + public Color foregroundColor; | |
| 172 | + public Color backgroundColor; | |
| 173 | + | |
| 174 | + public AffineTransform transform; | |
| 175 | + public int transX; | |
| 176 | + public int transY; | |
| 177 | + | |
| 178 | + protected static final Stroke defaultStroke = new BasicStroke(); | |
| 179 | + protected static final Composite defaultComposite = AlphaComposite.SrcOver; | |
| 180 | + private static final Font defaultFont = | |
| 181 | + new Font(Font.DIALOG, Font.PLAIN, 12); | |
| 182 | + | |
| 183 | + public Paint paint; | |
| 184 | + public Stroke stroke; | |
| 185 | + public Composite composite; | |
| 186 | + protected Font font; | |
| 187 | + protected FontMetrics fontMetrics; | |
| 188 | + | |
| 189 | + public int renderHint; | |
| 190 | + public int antialiasHint; | |
| 191 | + public int textAntialiasHint; | |
| 192 | + private int fractionalMetricsHint; | |
| 193 | + | |
| 194 | + /* A gamma adjustment to the colour used in lcd text blitting */ | |
| 195 | + public int lcdTextContrast; | |
| 196 | + private static int lcdTextContrastDefaultValue = 140; | |
| 197 | + | |
| 198 | + private int interpolationHint; // raw value of rendering Hint | |
| 199 | + public int strokeHint; | |
| 200 | + | |
| 201 | + public int interpolationType; // algorithm choice based on | |
| 202 | + // interpolation and render Hints | |
| 203 | + | |
| 204 | + public RenderingHints hints; | |
| 205 | + | |
| 206 | + public Region constrainClip; // lightweight bounds | |
| 207 | + public int constrainX; | |
| 208 | + public int constrainY; | |
| 209 | + | |
| 210 | + public Region clipRegion; | |
| 211 | + public Shape usrClip; | |
| 212 | + protected Region devClip; // Actual physical drawable | |
| 213 | + | |
| 214 | + // cached state for text rendering | |
| 215 | + private boolean validFontInfo; | |
| 216 | + private FontInfo fontInfo; | |
| 217 | + private FontInfo glyphVectorFontInfo; | |
| 218 | + private FontRenderContext glyphVectorFRC; | |
| 219 | + | |
| 220 | + private final static int slowTextTransformMask = | |
| 221 | + AffineTransform.TYPE_GENERAL_TRANSFORM | |
| 222 | + | AffineTransform.TYPE_MASK_ROTATION | |
| 223 | + | AffineTransform.TYPE_FLIP; | |
| 224 | + | |
| 225 | + static { | |
| 226 | + if (PerformanceLogger.loggingEnabled()) { | |
| 227 | + PerformanceLogger.setTime("SunGraphics2D static initialization"); | |
| 228 | + } | |
| 229 | + } | |
| 230 | + | |
| 231 | + public SunGraphics2D(SurfaceData sd, Color fg, Color bg, Font f) { | |
| 232 | + surfaceData = sd; | |
| 233 | + foregroundColor = fg; | |
| 234 | + backgroundColor = bg; | |
| 235 | + | |
| 236 | + transform = new AffineTransform(); | |
| 237 | + stroke = defaultStroke; | |
| 238 | + composite = defaultComposite; | |
| 239 | + paint = foregroundColor; | |
| 240 | + | |
| 241 | + imageComp = CompositeType.SrcOverNoEa; | |
| 242 | + | |
| 243 | + renderHint = SunHints.INTVAL_RENDER_DEFAULT; | |
| 244 | + antialiasHint = SunHints.INTVAL_ANTIALIAS_OFF; | |
| 245 | + textAntialiasHint = SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT; | |
| 246 | + fractionalMetricsHint = SunHints.INTVAL_FRACTIONALMETRICS_OFF; | |
| 247 | + lcdTextContrast = lcdTextContrastDefaultValue; | |
| 248 | + interpolationHint = -1; | |
| 249 | + strokeHint = SunHints.INTVAL_STROKE_DEFAULT; | |
| 250 | + | |
| 251 | + interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR; | |
| 252 | + | |
| 253 | + validateColor(); | |
| 254 | + | |
| 255 | + font = f; | |
| 256 | + if (font == null) { | |
| 257 | + font = defaultFont; | |
| 258 | + } | |
| 259 | + | |
| 260 | + setDevClip(sd.getBounds()); | |
| 261 | + invalidatePipe(); | |
| 262 | + } | |
| 263 | + | |
| 264 | + protected Object clone() { | |
| 265 | + try { | |
| 266 | + SunGraphics2D g = (SunGraphics2D) super.clone(); | |
| 267 | + g.transform = new AffineTransform(this.transform); | |
| 268 | + if (hints != null) { | |
| 269 | + g.hints = (RenderingHints) this.hints.clone(); | |
| 270 | + } | |
| 271 | + /* FontInfos are re-used, so must be cloned too, if they | |
| 272 | + * are valid, and be nulled out if invalid. | |
| 273 | + * The implied trade-off is that there is more to be gained | |
| 274 | + * from re-using these objects than is lost by having to | |
| 275 | + * clone them when the SG2D is cloned. | |
| 276 | + */ | |
| 277 | + if (this.fontInfo != null) { | |
| 278 | + if (this.validFontInfo) { | |
| 279 | + g.fontInfo = (FontInfo)this.fontInfo.clone(); | |
| 280 | + } else { | |
| 281 | + g.fontInfo = null; | |
| 282 | + } | |
| 283 | + } | |
| 284 | + if (this.glyphVectorFontInfo != null) { | |
| 285 | + g.glyphVectorFontInfo = | |
| 286 | + (FontInfo)this.glyphVectorFontInfo.clone(); | |
| 287 | + g.glyphVectorFRC = this.glyphVectorFRC; | |
| 288 | + } | |
| 289 | + //g.invalidatePipe(); | |
| 290 | + return g; | |
| 291 | + } catch (CloneNotSupportedException e) { | |
| 292 | + } | |
| 293 | + return null; | |
| 294 | + } | |
| 295 | + | |
| 296 | + /** | |
| 297 | + * Create a new SunGraphics2D based on this one. | |
| 298 | + */ | |
| 299 | + public Graphics create() { | |
| 300 | + return (Graphics) clone(); | |
| 301 | + } | |
| 302 | + | |
| 303 | + public void setDevClip(int x, int y, int w, int h) { | |
| 304 | + Region c = constrainClip; | |
| 305 | + if (c == null) { | |
| 306 | + devClip = Region.getInstanceXYWH(x, y, w, h); | |
| 307 | + } else { | |
| 308 | + devClip = c.getIntersectionXYWH(x, y, w, h); | |
| 309 | + } | |
| 310 | + validateCompClip(); | |
| 311 | + } | |
| 312 | + | |
| 313 | + public void setDevClip(Rectangle r) { | |
| 314 | + setDevClip(r.x, r.y, r.width, r.height); | |
| 315 | + } | |
| 316 | + | |
| 317 | + /** | |
| 318 | + * Constrain rendering for lightweight objects. | |
| 319 | + * | |
| 320 | + * REMIND: This method will back off to the "workaround" | |
| 321 | + * of using translate and clipRect if the Graphics | |
| 322 | + * to be constrained has a complex transform. The | |
| 323 | + * drawback of the workaround is that the resulting | |
| 324 | + * clip and device origin cannot be "enforced". | |
| 325 | + * | |
| 326 | + * @exception IllegalStateException If the Graphics | |
| 327 | + * to be constrained has a complex transform. | |
| 328 | + */ | |
| 329 | + public void constrain(int x, int y, int w, int h) { | |
| 330 | + if ((x|y) != 0) { | |
| 331 | + translate(x, y); | |
| 332 | + } | |
| 333 | + if (transformState >= TRANSFORM_TRANSLATESCALE) { | |
| 334 | + clipRect(0, 0, w, h); | |
| 335 | + return; | |
| 336 | + } | |
| 337 | + x = constrainX = transX; | |
| 338 | + y = constrainY = transY; | |
| 339 | + w = Region.dimAdd(x, w); | |
| 340 | + h = Region.dimAdd(y, h); | |
| 341 | + Region c = constrainClip; | |
| 342 | + if (c == null) { | |
| 343 | + c = Region.getInstanceXYXY(x, y, w, h); | |
| 344 | + } else { | |
| 345 | + c = c.getIntersectionXYXY(x, y, w, h); | |
| 346 | + if (c == constrainClip) { | |
| 347 | + // Common case to ignore | |
| 348 | + return; | |
| 349 | + } | |
| 350 | + } | |
| 351 | + constrainClip = c; | |
| 352 | + if (!devClip.isInsideQuickCheck(c)) { | |
| 353 | + devClip = devClip.getIntersection(c); | |
| 354 | + validateCompClip(); | |
| 355 | + } | |
| 356 | + } | |
| 357 | + | |
| 358 | + protected static ValidatePipe invalidpipe = new ValidatePipe(); | |
| 359 | + | |
| 360 | + /* | |
| 361 | + * Invalidate the pipeline | |
| 362 | + */ | |
| 363 | + protected void invalidatePipe() { | |
| 364 | + drawpipe = invalidpipe; | |
| 365 | + fillpipe = invalidpipe; | |
| 366 | + shapepipe = invalidpipe; | |
| 367 | + textpipe = invalidpipe; | |
| 368 | + imagepipe = invalidpipe; | |
| 369 | + loops = null; | |
| 370 | + } | |
| 371 | + | |
| 372 | + public void validatePipe() { | |
| 373 | + surfaceData.validatePipe(this); | |
| 374 | + } | |
| 375 | + | |
| 376 | + /* | |
| 377 | + * Intersect two Shapes by the simplest method, attempting to produce | |
| 378 | + * a simplified result. | |
| 379 | + * The boolean arguments keep1 and keep2 specify whether or not | |
| 380 | + * the first or second shapes can be modified during the operation | |
| 381 | + * or whether that shape must be "kept" unmodified. | |
| 382 | + */ | |
| 383 | + Shape intersectShapes(Shape s1, Shape s2, boolean keep1, boolean keep2) { | |
| 384 | + if (s1 instanceof Rectangle && s2 instanceof Rectangle) { | |
| 385 | + return ((Rectangle) s1).intersection((Rectangle) s2); | |
| 386 | + } | |
| 387 | + if (s1 instanceof Rectangle2D) { | |
| 388 | + return intersectRectShape((Rectangle2D) s1, s2, keep1, keep2); | |
| 389 | + } else if (s2 instanceof Rectangle2D) { | |
| 390 | + return intersectRectShape((Rectangle2D) s2, s1, keep2, keep1); | |
| 391 | + } | |
| 392 | + return intersectByArea(s1, s2, keep1, keep2); | |
| 393 | + } | |
| 394 | + | |
| 395 | + /* | |
| 396 | + * Intersect a Rectangle with a Shape by the simplest method, | |
| 397 | + * attempting to produce a simplified result. | |
| 398 | + * The boolean arguments keep1 and keep2 specify whether or not | |
| 399 | + * the first or second shapes can be modified during the operation | |
| 400 | + * or whether that shape must be "kept" unmodified. | |
| 401 | + */ | |
| 402 | + Shape intersectRectShape(Rectangle2D r, Shape s, | |
| 403 | + boolean keep1, boolean keep2) { | |
| 404 | + if (s instanceof Rectangle2D) { | |
| 405 | + Rectangle2D r2 = (Rectangle2D) s; | |
| 406 | + Rectangle2D outrect; | |
| 407 | + if (!keep1) { | |
| 408 | + outrect = r; | |
| 409 | + } else if (!keep2) { | |
| 410 | + outrect = r2; | |
| 411 | + } else { | |
| 412 | + outrect = new Rectangle2D.Float(); | |
| 413 | + } | |
| 414 | + double x1 = Math.max(r.getX(), r2.getX()); | |
| 415 | + double x2 = Math.min(r.getX() + r.getWidth(), | |
| 416 | + r2.getX() + r2.getWidth()); | |
| 417 | + double y1 = Math.max(r.getY(), r2.getY()); | |
| 418 | + double y2 = Math.min(r.getY() + r.getHeight(), | |
| 419 | + r2.getY() + r2.getHeight()); | |
| 420 | + | |
| 421 | + if (((x2 - x1) < 0) || ((y2 - y1) < 0)) | |
| 422 | + // Width or height is negative. No intersection. | |
| 423 | + outrect.setFrameFromDiagonal(0, 0, 0, 0); | |
| 424 | + else | |
| 425 | + outrect.setFrameFromDiagonal(x1, y1, x2, y2); | |
| 426 | + return outrect; | |
| 427 | + } | |
| 428 | + if (r.contains(s.getBounds2D())) { | |
| 429 | + if (keep2) { | |
| 430 | + s = cloneShape(s); | |
| 431 | + } | |
| 432 | + return s; | |
| 433 | + } | |
| 434 | + return intersectByArea(r, s, keep1, keep2); | |
| 435 | + } | |
| 436 | + | |
| 437 | + protected static Shape cloneShape(Shape s) { | |
| 438 | + return new GeneralPath(s); | |
| 439 | + } | |
| 440 | + | |
| 441 | + /* | |
| 442 | + * Intersect two Shapes using the Area class. Presumably other | |
| 443 | + * attempts at simpler intersection methods proved fruitless. | |
| 444 | + * The boolean arguments keep1 and keep2 specify whether or not | |
| 445 | + * the first or second shapes can be modified during the operation | |
| 446 | + * or whether that shape must be "kept" unmodified. | |
| 447 | + * @see #intersectShapes | |
| 448 | + * @see #intersectRectShape | |
| 449 | + */ | |
| 450 | + Shape intersectByArea(Shape s1, Shape s2, boolean keep1, boolean keep2) { | |
| 451 | + Area a1, a2; | |
| 452 | + | |
| 453 | + // First see if we can find an overwriteable source shape | |
| 454 | + // to use as our destination area to avoid duplication. | |
| 455 | + if (!keep1 && (s1 instanceof Area)) { | |
| 456 | + a1 = (Area) s1; | |
| 457 | + } else if (!keep2 && (s2 instanceof Area)) { | |
| 458 | + a1 = (Area) s2; | |
| 459 | + s2 = s1; | |
| 460 | + } else { | |
| 461 | + a1 = new Area(s1); | |
| 462 | + } | |
| 463 | + | |
| 464 | + if (s2 instanceof Area) { | |
| 465 | + a2 = (Area) s2; | |
| 466 | + } else { | |
| 467 | + a2 = new Area(s2); | |
| 468 | + } | |
| 469 | + | |
| 470 | + a1.intersect(a2); | |
| 471 | + if (a1.isRectangular()) { | |
| 472 | + return a1.getBounds(); | |
| 473 | + } | |
| 474 | + | |
| 475 | + return a1; | |
| 476 | + } | |
| 477 | + | |
| 478 | + /* | |
| 479 | + * Intersect usrClip bounds and device bounds to determine the composite | |
| 480 | + * rendering boundaries. | |
| 481 | + */ | |
| 482 | + public Region getCompClip() { | |
| 483 | + if (!surfaceData.isValid()) { | |
| 484 | + // revalidateAll() implicitly recalculcates the composite clip | |
| 485 | + revalidateAll(); | |
| 486 | + } | |
| 487 | + | |
| 488 | + return clipRegion; | |
| 489 | + } | |
| 490 | + | |
| 491 | + public Font getFont() { | |
| 492 | + if (font == null) { | |
| 493 | + font = defaultFont; | |
| 494 | + } | |
| 495 | + return font; | |
| 496 | + } | |
| 497 | + | |
| 498 | + private static final double[] IDENT_MATRIX = {1, 0, 0, 1}; | |
| 499 | + private static final AffineTransform IDENT_ATX = | |
| 500 | + new AffineTransform(); | |
| 501 | + | |
| 502 | + private static final int MINALLOCATED = 8; | |
| 503 | + private static final int TEXTARRSIZE = 17; | |
| 504 | + private static double[][] textTxArr = new double[TEXTARRSIZE][]; | |
| 505 | + private static AffineTransform[] textAtArr = | |
| 506 | + new AffineTransform[TEXTARRSIZE]; | |
| 507 | + | |
| 508 | + static { | |
| 509 | + for (int i=MINALLOCATED;i<TEXTARRSIZE;i++) { | |
| 510 | + textTxArr[i] = new double [] {i, 0, 0, i}; | |
| 511 | + textAtArr[i] = new AffineTransform( textTxArr[i]); | |
| 512 | + } | |
| 513 | + } | |
| 514 | + | |
| 515 | + // cached state for various draw[String,Char,Byte] optimizations | |
| 516 | + public FontInfo checkFontInfo(FontInfo info, Font font, | |
| 517 | + FontRenderContext frc) { | |
| 518 | + /* Do not create a FontInfo object as part of construction of an | |
| 519 | + * SG2D as its possible it may never be needed - ie if no text | |
| 520 | + * is drawn using this SG2D. | |
| 521 | + */ | |
| 522 | + if (info == null) { | |
| 523 | + info = new FontInfo(); | |
| 524 | + } | |
| 525 | + | |
| 526 | + float ptSize = font.getSize2D(); | |
| 527 | + int txFontType; | |
| 528 | + AffineTransform devAt, textAt=null; | |
| 529 | + if (font.isTransformed()) { | |
| 530 | + textAt = font.getTransform(); | |
| 531 | + textAt.scale(ptSize, ptSize); | |
| 532 | + txFontType = textAt.getType(); | |
| 533 | + info.originX = (float)textAt.getTranslateX(); | |
| 534 | + info.originY = (float)textAt.getTranslateY(); | |
| 535 | + textAt.translate(-info.originX, -info.originY); | |
| 536 | + if (transformState >= TRANSFORM_TRANSLATESCALE) { | |
| 537 | + transform.getMatrix(info.devTx = new double[4]); | |
| 538 | + devAt = new AffineTransform(info.devTx); | |
| 539 | + textAt.preConcatenate(devAt); | |
| 540 | + } else { | |
| 541 | + info.devTx = IDENT_MATRIX; | |
| 542 | + devAt = IDENT_ATX; | |
| 543 | + } | |
| 544 | + textAt.getMatrix(info.glyphTx = new double[4]); | |
| 545 | + double shearx = textAt.getShearX(); | |
| 546 | + double scaley = textAt.getScaleY(); | |
| 547 | + if (shearx != 0) { | |
| 548 | + scaley = Math.sqrt(shearx * shearx + scaley * scaley); | |
| 549 | + } | |
| 550 | + info.pixelHeight = (int)(Math.abs(scaley)+0.5); | |
| 551 | + } else { | |
| 552 | + txFontType = AffineTransform.TYPE_IDENTITY; | |
| 553 | + info.originX = info.originY = 0; | |
| 554 | + if (transformState >= TRANSFORM_TRANSLATESCALE) { | |
| 555 | + transform.getMatrix(info.devTx = new double[4]); | |
| 556 | + devAt = new AffineTransform(info.devTx); | |
| 557 | + info.glyphTx = new double[4]; | |
| 558 | + for (int i = 0; i < 4; i++) { | |
| 559 | + info.glyphTx[i] = info.devTx[i] * ptSize; | |
| 560 | + } | |
| 561 | + textAt = new AffineTransform(info.glyphTx); | |
| 562 | + double shearx = transform.getShearX(); | |
| 563 | + double scaley = transform.getScaleY(); | |
| 564 | + if (shearx != 0) { | |
| 565 | + scaley = Math.sqrt(shearx * shearx + scaley * scaley); | |
| 566 | + } | |
| 567 | + info.pixelHeight = (int)(Math.abs(scaley * ptSize)+0.5); | |
| 568 | + } else { | |
| 569 | + /* If the double represents a common integral, we | |
| 570 | + * may have pre-allocated objects. | |
| 571 | + * A "sparse" array be seems to be as fast as a switch | |
| 572 | + * even for 3 or 4 pt sizes, and is more flexible. | |
| 573 | + * This should perform comparably in single-threaded | |
| 574 | + * rendering to the old code which synchronized on the | |
| 575 | + * class and scale better on MP systems. | |
| 576 | + */ | |
| 577 | + int pszInt = (int)ptSize; | |
| 578 | + if (ptSize == pszInt && | |
| 579 | + pszInt >= MINALLOCATED && pszInt < TEXTARRSIZE) { | |
| 580 | + info.glyphTx = textTxArr[pszInt]; | |
| 581 | + textAt = textAtArr[pszInt]; | |
| 582 | + info.pixelHeight = pszInt; | |
| 583 | + } else { | |
| 584 | + info.pixelHeight = (int)(ptSize+0.5); | |
| 585 | + } | |
| 586 | + if (textAt == null) { | |
| 587 | + info.glyphTx = new double[] {ptSize, 0, 0, ptSize}; | |
| 588 | + textAt = new AffineTransform(info.glyphTx); | |
| 589 | + } | |
| 590 | + | |
| 591 | + info.devTx = IDENT_MATRIX; | |
| 592 | + devAt = IDENT_ATX; | |
| 593 | + } | |
| 594 | + } | |
| 595 | + | |
| 596 | + info.font2D = FontUtilities.getFont2D(font); | |
| 597 | + | |
| 598 | + int fmhint = fractionalMetricsHint; | |
| 599 | + if (fmhint == SunHints.INTVAL_FRACTIONALMETRICS_DEFAULT) { | |
| 600 | + fmhint = SunHints.INTVAL_FRACTIONALMETRICS_OFF; | |
| 601 | + } | |
| 602 | + info.lcdSubPixPos = false; // conditionally set true in LCD mode. | |
| 603 | + | |
| 604 | + /* The text anti-aliasing hints that are set by the client need | |
| 605 | + * to be interpreted for the current state and stored in the | |
| 606 | + * FontInfo.aahint which is what will actually be used and | |
| 607 | + * will be one of OFF, ON, LCD_HRGB or LCD_VRGB. | |
| 608 | + * This is what pipe selection code should typically refer to, not | |
| 609 | + * textAntialiasHint. This means we are now evaluating the meaning | |
| 610 | + * of "default" here. Any pipe that really cares about that will | |
| 611 | + * also need to consult that variable. | |
| 612 | + * Otherwise these are being used only as args to getStrike, | |
| 613 | + * and are encapsulated in that object which is part of the | |
| 614 | + * FontInfo, so we do not need to store them directly as fields | |
| 615 | + * in the FontInfo object. | |
| 616 | + * That could change if FontInfo's were more selectively | |
| 617 | + * revalidated when graphics state changed. Presently this | |
| 618 | + * method re-evaluates all fields in the fontInfo. | |
| 619 | + * The strike doesn't need to know the RGB subpixel order. Just | |
| 620 | + * if its H or V orientation, so if an LCD option is specified we | |
| 621 | + * always pass in the RGB hint to the strike. | |
| 622 | + * frc is non-null only if this is a GlyphVector. For reasons | |
| 623 | + * which are probably a historical mistake the AA hint in a GV | |
| 624 | + * is honoured when we render, overriding the Graphics setting. | |
| 625 | + */ | |
| 626 | + int aahint; | |
| 627 | + if (frc == null) { | |
| 628 | + aahint = textAntialiasHint; | |
| 629 | + } else { | |
| 630 | + aahint = ((SunHints.Value)frc.getAntiAliasingHint()).getIndex(); | |
| 631 | + } | |
| 632 | + if (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT) { | |
| 633 | + if (antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) { | |
| 634 | + aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON; | |
| 635 | + } else { | |
| 636 | + aahint = SunHints.INTVAL_TEXT_ANTIALIAS_OFF; | |
| 637 | + } | |
| 638 | + } else { | |
| 639 | + /* If we are in checkFontInfo because a rendering hint has been | |
| 640 | + * set then all pipes are revalidated. But we can also | |
| 641 | + * be here because setFont() has been called when the 'gasp' | |
| 642 | + * hint is set, as then the font size determines the text pipe. | |
| 643 | + * See comments in SunGraphics2d.setFont(Font). | |
| 644 | + */ | |
| 645 | + if (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_GASP) { | |
| 646 | + if (info.font2D.useAAForPtSize(info.pixelHeight)) { | |
| 647 | + aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON; | |
| 648 | + } else { | |
| 649 | + aahint = SunHints.INTVAL_TEXT_ANTIALIAS_OFF; | |
| 650 | + } | |
| 651 | + } else if (aahint >= SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB) { | |
| 652 | + /* loops for default rendering modes are installed in the SG2D | |
| 653 | + * constructor. If there are none this will be null. | |
| 654 | + * Not all compositing modes update the render loops, so | |
| 655 | + * we also test that this is a mode we know should support | |
| 656 | + * this. One minor issue is that the loops aren't necessarily | |
| 657 | + * installed for a new rendering mode until after this | |
| 658 | + * method is called during pipeline validation. So it is | |
| 659 | + * theoretically possible that it was set to null for a | |
| 660 | + * compositing mode, the composite is then set back to Src, | |
| 661 | + * but the loop is still null when this is called and AA=ON | |
| 662 | + * is installed instead of an LCD mode. | |
| 663 | + * However this is done in the right order in SurfaceData.java | |
| 664 | + * so this is not likely to be a problem - but not | |
| 665 | + * guaranteed. | |
| 666 | + */ | |
| 667 | + if ( | |
| 668 | + !surfaceData.canRenderLCDText(this) | |
| 669 | +// loops.drawGlyphListLCDLoop == null || | |
| 670 | +// compositeState > COMP_ISCOPY || | |
| 671 | +// paintState > PAINT_ALPHACOLOR | |
| 672 | + ) { | |
| 673 | + aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON; | |
| 674 | + } else { | |
| 675 | + info.lcdRGBOrder = true; | |
| 676 | + /* Collapse these into just HRGB or VRGB. | |
| 677 | + * Pipe selection code needs only to test for these two. | |
| 678 | + * Since these both select the same pipe anyway its | |
| 679 | + * tempting to collapse into one value. But they are | |
| 680 | + * different strikes (glyph caches) so the distinction | |
| 681 | + * needs to be made for that purpose. | |
| 682 | + */ | |
| 683 | + if (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HBGR) { | |
| 684 | + aahint = SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB; | |
| 685 | + info.lcdRGBOrder = false; | |
| 686 | + } else if | |
| 687 | + (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VBGR) { | |
| 688 | + aahint = SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB; | |
| 689 | + info.lcdRGBOrder = false; | |
| 690 | + } | |
| 691 | + /* Support subpixel positioning only for the case in | |
| 692 | + * which the horizontal resolution is increased | |
| 693 | + */ | |
| 694 | + info.lcdSubPixPos = | |
| 695 | + fmhint == SunHints.INTVAL_FRACTIONALMETRICS_ON && | |
| 696 | + aahint == SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB; | |
| 697 | + } | |
| 698 | + } | |
| 699 | + } | |
| 700 | + info.aaHint = aahint; | |
| 701 | + info.fontStrike = info.font2D.getStrike(font, devAt, textAt, | |
| 702 | + aahint, fmhint); | |
| 703 | + return info; | |
| 704 | + } | |
| 705 | + | |
| 706 | + public static boolean isRotated(double [] mtx) { | |
| 707 | + if ((mtx[0] == mtx[3]) && | |
| 708 | + (mtx[1] == 0.0) && | |
| 709 | + (mtx[2] == 0.0) && | |
| 710 | + (mtx[0] > 0.0)) | |
| 711 | + { | |
| 712 | + return false; | |
| 713 | + } | |
| 714 | + | |
| 715 | + return true; | |
| 716 | + } | |
| 717 | + | |
| 718 | + public void setFont(Font font) { | |
| 719 | + /* replacing the reference equality test font != this.font with | |
| 720 | + * !font.equals(this.font) did not yield any measurable difference | |
| 721 | + * in testing, but there may be yet to be identified cases where it | |
| 722 | + * is beneficial. | |
| 723 | + */ | |
| 724 | + if (font != null && font!=this.font/*!font.equals(this.font)*/) { | |
| 725 | + /* In the GASP AA case the textpipe depends on the glyph size | |
| 726 | + * as determined by graphics and font transforms as well as the | |
| 727 | + * font size, and information in the font. But we may invalidate | |
| 728 | + * the pipe only to find that it made no difference. | |
| 729 | + * Deferring pipe invalidation to checkFontInfo won't work because | |
| 730 | + * when called we may already be rendering to the wrong pipe. | |
| 731 | + * So, if the font is transformed, or the graphics has more than | |
| 732 | + * a simple scale, we'll take that as enough of a hint to | |
| 733 | + * revalidate everything. But if they aren't we will | |
| 734 | + * use the font's point size to query the gasp table and see if | |
| 735 | + * what it says matches what's currently being used, in which | |
| 736 | + * case there's no need to invalidate the textpipe. | |
| 737 | + * This should be sufficient for all typical uses cases. | |
| 738 | + */ | |
| 739 | + if (textAntialiasHint == SunHints.INTVAL_TEXT_ANTIALIAS_GASP && | |
| 740 | + textpipe != invalidpipe && | |
| 741 | + (transformState > TRANSFORM_ANY_TRANSLATE || | |
| 742 | + font.isTransformed() || | |
| 743 | + fontInfo == null || // Precaution, if true shouldn't get here | |
| 744 | + (fontInfo.aaHint == SunHints.INTVAL_TEXT_ANTIALIAS_ON) != | |
| 745 | + FontUtilities.getFont2D(font). | |
| 746 | + useAAForPtSize(font.getSize()))) { | |
| 747 | + textpipe = invalidpipe; | |
| 748 | + } | |
| 749 | + this.font = font; | |
| 750 | + this.fontMetrics = null; | |
| 751 | + this.validFontInfo = false; | |
| 752 | + } | |
| 753 | + } | |
| 754 | + | |
| 755 | + public FontInfo getFontInfo() { | |
| 756 | + if (!validFontInfo) { | |
| 757 | + this.fontInfo = checkFontInfo(this.fontInfo, font, null); | |
| 758 | + validFontInfo = true; | |
| 759 | + } | |
| 760 | + return this.fontInfo; | |
| 761 | + } | |
| 762 | + | |
| 763 | + /* Used by drawGlyphVector which specifies its own font. */ | |
| 764 | + public FontInfo getGVFontInfo(Font font, FontRenderContext frc) { | |
| 765 | + if (glyphVectorFontInfo != null && | |
| 766 | + glyphVectorFontInfo.font == font && | |
| 767 | + glyphVectorFRC == frc) { | |
| 768 | + return glyphVectorFontInfo; | |
| 769 | + } else { | |
| 770 | + glyphVectorFRC = frc; | |
| 771 | + return glyphVectorFontInfo = | |
| 772 | + checkFontInfo(glyphVectorFontInfo, font, frc); | |
| 773 | + } | |
| 774 | + } | |
| 775 | + | |
| 776 | + public FontMetrics getFontMetrics() { | |
| 777 | + if (this.fontMetrics != null) { | |
| 778 | + return this.fontMetrics; | |
| 779 | + } | |
| 780 | + /* NB the constructor and the setter disallow "font" being null */ | |
| 781 | + return this.fontMetrics = | |
| 782 | + FontDesignMetrics.getMetrics(font, getFontRenderContext()); | |
| 783 | + } | |
| 784 | + | |
| 785 | + public FontMetrics getFontMetrics(Font font) { | |
| 786 | + if ((this.fontMetrics != null) && (font == this.font)) { | |
| 787 | + return this.fontMetrics; | |
| 788 | + } | |
| 789 | + FontMetrics fm = | |
| 790 | + FontDesignMetrics.getMetrics(font, getFontRenderContext()); | |
| 791 | + | |
| 792 | + if (this.font == font) { | |
| 793 | + this.fontMetrics = fm; | |
| 794 | + } | |
| 795 | + return fm; | |
| 796 | + } | |
| 797 | + | |
| 798 | + /** | |
| 799 | + * Checks to see if a Path intersects the specified Rectangle in device | |
| 800 | + * space. The rendering attributes taken into account include the | |
| 801 | + * clip, transform, and stroke attributes. | |
| 802 | + * @param rect The area in device space to check for a hit. | |
| 803 | + * @param p The path to check for a hit. | |
| 804 | + * @param onStroke Flag to choose between testing the stroked or | |
| 805 | + * the filled path. | |
| 806 | + * @return True if there is a hit, false otherwise. | |
| 807 | + * @see #setStroke | |
| 808 | + * @see #fillPath | |
| 809 | + * @see #drawPath | |
| 810 | + * @see #transform | |
| 811 | + * @see #setTransform | |
| 812 | + * @see #clip | |
| 813 | + * @see #setClip | |
| 814 | + */ | |
| 815 | + public boolean hit(Rectangle rect, Shape s, boolean onStroke) { | |
| 816 | + if (onStroke) { | |
| 817 | + s = stroke.createStrokedShape(s); | |
| 818 | + } | |
| 819 | + | |
| 820 | + s = transformShape(s); | |
| 821 | + if ((constrainX|constrainY) != 0) { | |
| 822 | + rect = new Rectangle(rect); | |
| 823 | + rect.translate(constrainX, constrainY); | |
| 824 | + } | |
| 825 | + | |
| 826 | + return s.intersects(rect); | |
| 827 | + } | |
| 828 | + | |
| 829 | + /** | |
| 830 | + * Return the ColorModel associated with this Graphics2D. | |
| 831 | + */ | |
| 832 | + public ColorModel getDeviceColorModel() { | |
| 833 | + return surfaceData.getColorModel(); | |
| 834 | + } | |
| 835 | + | |
| 836 | + /** | |
| 837 | + * Return the device configuration associated with this Graphics2D. | |
| 838 | + */ | |
| 839 | + public GraphicsConfiguration getDeviceConfiguration() { | |
| 840 | + return surfaceData.getDeviceConfiguration(); | |
| 841 | + } | |
| 842 | + | |
| 843 | + /** | |
| 844 | + * Return the SurfaceData object assigned to manage the destination | |
| 845 | + * drawable surface of this Graphics2D. | |
| 846 | + */ | |
| 847 | + public final SurfaceData getSurfaceData() { | |
| 848 | + return surfaceData; | |
| 849 | + } | |
| 850 | + | |
| 851 | + /** | |
| 852 | + * Sets the Composite in the current graphics state. Composite is used | |
| 853 | + * in all drawing methods such as drawImage, drawString, drawPath, | |
| 854 | + * and fillPath. It specifies how new pixels are to be combined with | |
| 855 | + * the existing pixels on the graphics device in the rendering process. | |
| 856 | + * @param comp The Composite object to be used for drawing. | |
| 857 | + * @see java.awt.Graphics#setXORMode | |
| 858 | + * @see java.awt.Graphics#setPaintMode | |
| 859 | + * @see AlphaComposite | |
| 860 | + */ | |
| 861 | + public void setComposite(Composite comp) { | |
| 862 | + if (composite == comp) { | |
| 863 | + return; | |
| 864 | + } | |
| 865 | + int newCompState; | |
| 866 | + CompositeType newCompType; | |
| 867 | + if (comp instanceof AlphaComposite) { | |
| 868 | + AlphaComposite alphacomp = (AlphaComposite) comp; | |
| 869 | + newCompType = CompositeType.forAlphaComposite(alphacomp); | |
| 870 | + if (newCompType == CompositeType.SrcOverNoEa) { | |
| 871 | + if (paintState == PAINT_OPAQUECOLOR || | |
| 872 | + (paintState > PAINT_ALPHACOLOR && | |
| 873 | + paint.getTransparency() == Transparency.OPAQUE)) | |
| 874 | + { | |
| 875 | + newCompState = COMP_ISCOPY; | |
| 876 | + } else { | |
| 877 | + newCompState = COMP_ALPHA; | |
| 878 | + } | |
| 879 | + } else if (newCompType == CompositeType.SrcNoEa || | |
| 880 | + newCompType == CompositeType.Src || | |
| 881 | + newCompType == CompositeType.Clear) | |
| 882 | + { | |
| 883 | + newCompState = COMP_ISCOPY; | |
| 884 | + } else if (surfaceData.getTransparency() == Transparency.OPAQUE && | |
| 885 | + newCompType == CompositeType.SrcIn) | |
| 886 | + { | |
| 887 | + newCompState = COMP_ISCOPY; | |
| 888 | + } else { | |
| 889 | + newCompState = COMP_ALPHA; | |
| 890 | + } | |
| 891 | + } else if (comp instanceof XORComposite) { | |
| 892 | + newCompState = COMP_XOR; | |
| 893 | + newCompType = CompositeType.Xor; | |
| 894 | + } else if (comp == null) { | |
| 895 | + throw new IllegalArgumentException("null Composite"); | |
| 896 | + } else { | |
| 897 | + surfaceData.checkCustomComposite(); | |
| 898 | + newCompState = COMP_CUSTOM; | |
| 899 | + newCompType = CompositeType.General; | |
| 900 | + } | |
| 901 | + if (compositeState != newCompState || | |
| 902 | + imageComp != newCompType) | |
| 903 | + { | |
| 904 | + compositeState = newCompState; | |
| 905 | + imageComp = newCompType; | |
| 906 | + invalidatePipe(); | |
| 907 | + validFontInfo = false; | |
| 908 | + } | |
| 909 | + composite = comp; | |
| 910 | + if (paintState <= PAINT_ALPHACOLOR) { | |
| 911 | + validateColor(); | |
| 912 | + } | |
| 913 | + } | |
| 914 | + | |
| 915 | + /** | |
| 916 | + * Sets the Paint in the current graphics state. | |
| 917 | + * @param paint The Paint object to be used to generate color in | |
| 918 | + * the rendering process. | |
| 919 | + * @see java.awt.Graphics#setColor | |
| 920 | + * @see GradientPaint | |
| 921 | + * @see TexturePaint | |
| 922 | + */ | |
| 923 | + public void setPaint(Paint paint) { | |
| 924 | + if (paint instanceof Color) { | |
| 925 | + setColor((Color) paint); | |
| 926 | + return; | |
| 927 | + } | |
| 928 | + if (paint == null || this.paint == paint) { | |
| 929 | + return; | |
| 930 | + } | |
| 931 | + this.paint = paint; | |
| 932 | + if (imageComp == CompositeType.SrcOverNoEa) { | |
| 933 | + // special case where compState depends on opacity of paint | |
| 934 | + if (paint.getTransparency() == Transparency.OPAQUE) { | |
| 935 | + if (compositeState != COMP_ISCOPY) { | |
| 936 | + compositeState = COMP_ISCOPY; | |
| 937 | + } | |
| 938 | + } else { | |
| 939 | + if (compositeState == COMP_ISCOPY) { | |
| 940 | + compositeState = COMP_ALPHA; | |
| 941 | + } | |
| 942 | + } | |
| 943 | + } | |
| 944 | + Class paintClass = paint.getClass(); | |
| 945 | + if (paintClass == GradientPaint.class) { | |
| 946 | + paintState = PAINT_GRADIENT; | |
| 947 | + } else if (paintClass == LinearGradientPaint.class) { | |
| 948 | + paintState = PAINT_LIN_GRADIENT; | |
| 949 | + } else if (paintClass == RadialGradientPaint.class) { | |
| 950 | + paintState = PAINT_RAD_GRADIENT; | |
| 951 | + } else if (paintClass == TexturePaint.class) { | |
| 952 | + paintState = PAINT_TEXTURE; | |
| 953 | + } else { | |
| 954 | + paintState = PAINT_CUSTOM; | |
| 955 | + } | |
| 956 | + validFontInfo = false; | |
| 957 | + invalidatePipe(); | |
| 958 | + } | |
| 959 | + | |
| 960 | + static final int NON_UNIFORM_SCALE_MASK = | |
| 961 | + (AffineTransform.TYPE_GENERAL_TRANSFORM | | |
| 962 | + AffineTransform.TYPE_GENERAL_SCALE); | |
| 963 | + public static final double MinPenSizeAA = | |
| 964 | + sun.java2d.pipe.RenderingEngine.getInstance().getMinimumAAPenSize(); | |
| 965 | + public static final double MinPenSizeAASquared = | |
| 966 | + (MinPenSizeAA * MinPenSizeAA); | |
| 967 | + // Since inaccuracies in the trig package can cause us to | |
| 968 | + // calculated a rotated pen width of just slightly greater | |
| 969 | + // than 1.0, we add a fudge factor to our comparison value | |
| 970 | + // here so that we do not misclassify single width lines as | |
| 971 | + // wide lines under certain rotations. | |
| 972 | + public static final double MinPenSizeSquared = 1.000000001; | |
| 973 | + | |
| 974 | + private void validateBasicStroke(BasicStroke bs) { | |
| 975 | + boolean aa = (antialiasHint == SunHints.INTVAL_ANTIALIAS_ON); | |
| 976 | + if (transformState < TRANSFORM_TRANSLATESCALE) { | |
| 977 | + if (aa) { | |
| 978 | + if (bs.getLineWidth() <= MinPenSizeAA) { | |
| 979 | + if (bs.getDashArray() == null) { | |
| 980 | + strokeState = STROKE_THIN; | |
| 981 | + } else { | |
| 982 | + strokeState = STROKE_THINDASHED; | |
| 983 | + } | |
| 984 | + } else { | |
| 985 | + strokeState = STROKE_WIDE; | |
| 986 | + } | |
| 987 | + } else { | |
| 988 | + if (bs == defaultStroke) { | |
| 989 | + strokeState = STROKE_THIN; | |
| 990 | + } else if (bs.getLineWidth() <= 1.0f) { | |
| 991 | + if (bs.getDashArray() == null) { | |
| 992 | + strokeState = STROKE_THIN; | |
| 993 | + } else { | |
| 994 | + strokeState = STROKE_THINDASHED; | |
| 995 | + } | |
| 996 | + } else { | |
| 997 | + strokeState = STROKE_WIDE; | |
| 998 | + } | |
| 999 | + } | |
| 1000 | + } else { | |
| 1001 | + double widthsquared; | |
| 1002 | + if ((transform.getType() & NON_UNIFORM_SCALE_MASK) == 0) { | |
| 1003 | + /* sqrt omitted, compare to squared limits below. */ | |
| 1004 | + widthsquared = Math.abs(transform.getDeterminant()); | |
| 1005 | + } else { | |
| 1006 | + /* First calculate the "maximum scale" of this transform. */ | |
| 1007 | + double A = transform.getScaleX(); // m00 | |
| 1008 | + double C = transform.getShearX(); // m01 | |
| 1009 | + double B = transform.getShearY(); // m10 | |
| 1010 | + double D = transform.getScaleY(); // m11 | |
| 1011 | + | |
| 1012 | + /* | |
| 1013 | + * Given a 2 x 2 affine matrix [ A B ] such that | |
| 1014 | + * [ C D ] | |
| 1015 | + * v' = [x' y'] = [Ax + Cy, Bx + Dy], we want to | |
| 1016 | + * find the maximum magnitude (norm) of the vector v' | |
| 1017 | + * with the constraint (x^2 + y^2 = 1). | |
| 1018 | + * The equation to maximize is | |
| 1019 | + * |v'| = sqrt((Ax+Cy)^2+(Bx+Dy)^2) | |
| 1020 | + * or |v'| = sqrt((AA+BB)x^2 + 2(AC+BD)xy + (CC+DD)y^2). | |
| 1021 | + * Since sqrt is monotonic we can maximize |v'|^2 | |
| 1022 | + * instead and plug in the substitution y = sqrt(1 - x^2). | |
| 1023 | + * Trigonometric equalities can then be used to get | |
| 1024 | + * rid of most of the sqrt terms. | |
| 1025 | + */ | |
| 1026 | + double EA = A*A + B*B; // x^2 coefficient | |
| 1027 | + double EB = 2*(A*C + B*D); // xy coefficient | |
| 1028 | + double EC = C*C + D*D; // y^2 coefficient | |
| 1029 | + | |
| 1030 | + /* | |
| 1031 | + * There is a lot of calculus omitted here. | |
| 1032 | + * | |
| 1033 | + * Conceptually, in the interests of understanding the | |
| 1034 | + * terms that the calculus produced we can consider | |
| 1035 | + * that EA and EC end up providing the lengths along | |
| 1036 | + * the major axes and the hypot term ends up being an | |
| 1037 | + * adjustment for the additional length along the off-axis | |
| 1038 | + * angle of rotated or sheared ellipses as well as an | |
| 1039 | + * adjustment for the fact that the equation below | |
| 1040 | + * averages the two major axis lengths. (Notice that | |
| 1041 | + * the hypot term contains a part which resolves to the | |
| 1042 | + * difference of these two axis lengths in the absence | |
| 1043 | + * of rotation.) | |
| 1044 | + * | |
| 1045 | + * In the calculus, the ratio of the EB and (EA-EC) terms | |
| 1046 | + * ends up being the tangent of 2*theta where theta is | |
| 1047 | + * the angle that the long axis of the ellipse makes | |
| 1048 | + * with the horizontal axis. Thus, this equation is | |
| 1049 | + * calculating the length of the hypotenuse of a triangle | |
| 1050 | + * along that axis. | |
| 1051 | + */ | |
| 1052 | + double hypot = Math.sqrt(EB*EB + (EA-EC)*(EA-EC)); | |
| 1053 | + | |
| 1054 | + /* sqrt omitted, compare to squared limits below. */ | |
| 1055 | + widthsquared = ((EA + EC + hypot)/2.0); | |
| 1056 | + } | |
| 1057 | + if (bs != defaultStroke) { | |
| 1058 | + widthsquared *= bs.getLineWidth() * bs.getLineWidth(); | |
| 1059 | + } | |
| 1060 | + if (widthsquared <= | |
| 1061 | + (aa ? MinPenSizeAASquared : MinPenSizeSquared)) | |
| 1062 | + { | |
| 1063 | + if (bs.getDashArray() == null) { | |
| 1064 | + strokeState = STROKE_THIN; | |
| 1065 | + } else { | |
| 1066 | + strokeState = STROKE_THINDASHED; | |
| 1067 | + } | |
| 1068 | + } else { | |
| 1069 | + strokeState = STROKE_WIDE; | |
| 1070 | + } | |
| 1071 | + } | |
| 1072 | + } | |
| 1073 | + | |
| 1074 | + /* | |
| 1075 | + * Sets the Stroke in the current graphics state. | |
| 1076 | + * @param s The Stroke object to be used to stroke a Path in | |
| 1077 | + * the rendering process. | |
| 1078 | + * @see BasicStroke | |
| 1079 | + */ | |
| 1080 | + public void setStroke(Stroke s) { | |
| 1081 | + if (s == null) { | |
| 1082 | + throw new IllegalArgumentException("null Stroke"); | |
| 1083 | + } | |
| 1084 | + int saveStrokeState = strokeState; | |
| 1085 | + stroke = s; | |
| 1086 | + if (s instanceof BasicStroke) { | |
| 1087 | + validateBasicStroke((BasicStroke) s); | |
| 1088 | + } else { | |
| 1089 | + strokeState = STROKE_CUSTOM; | |
| 1090 | + } | |
| 1091 | + if (strokeState != saveStrokeState) { | |
| 1092 | + invalidatePipe(); | |
| 1093 | + } | |
| 1094 | + } | |
| 1095 | + | |
| 1096 | + /** | |
| 1097 | + * Sets the preferences for the rendering algorithms. | |
| 1098 | + * Hint categories include controls for rendering quality and | |
| 1099 | + * overall time/quality trade-off in the rendering process. | |
| 1100 | + * @param hintKey The key of hint to be set. The strings are | |
| 1101 | + * defined in the RenderingHints class. | |
| 1102 | + * @param hintValue The value indicating preferences for the specified | |
| 1103 | + * hint category. These strings are defined in the RenderingHints | |
| 1104 | + * class. | |
| 1105 | + * @see RenderingHints | |
| 1106 | + */ | |
| 1107 | + public void setRenderingHint(Key hintKey, Object hintValue) { | |
| 1108 | + // If we recognize the key, we must recognize the value | |
| 1109 | + // otherwise throw an IllegalArgumentException | |
| 1110 | + // and do not change the Hints object | |
| 1111 | + // If we do not recognize the key, just pass it through | |
| 1112 | + // to the Hints object untouched | |
| 1113 | + if (!hintKey.isCompatibleValue(hintValue)) { | |
| 1114 | + throw new IllegalArgumentException | |
| 1115 | + (hintValue+" is not compatible with "+hintKey); | |
| 1116 | + } | |
| 1117 | + if (hintKey instanceof SunHints.Key) { | |
| 1118 | + boolean stateChanged; | |
| 1119 | + boolean textStateChanged = false; | |
| 1120 | + boolean recognized = true; | |
| 1121 | + SunHints.Key sunKey = (SunHints.Key) hintKey; | |
| 1122 | + int newHint; | |
| 1123 | + if (sunKey == SunHints.KEY_TEXT_ANTIALIAS_LCD_CONTRAST) { | |
| 1124 | + newHint = ((Integer)hintValue).intValue(); | |
| 1125 | + } else { | |
| 1126 | + newHint = ((SunHints.Value) hintValue).getIndex(); | |
| 1127 | + } | |
| 1128 | + switch (sunKey.getIndex()) { | |
| 1129 | + case SunHints.INTKEY_RENDERING: | |
| 1130 | + stateChanged = (renderHint != newHint); | |
| 1131 | + if (stateChanged) { | |
| 1132 | + renderHint = newHint; | |
| 1133 | + if (interpolationHint == -1) { | |
| 1134 | + interpolationType = | |
| 1135 | + (newHint == SunHints.INTVAL_RENDER_QUALITY | |
| 1136 | + ? AffineTransformOp.TYPE_BILINEAR | |
| 1137 | + : AffineTransformOp.TYPE_NEAREST_NEIGHBOR); | |
| 1138 | + } | |
| 1139 | + } | |
| 1140 | + break; | |
| 1141 | + case SunHints.INTKEY_ANTIALIASING: | |
| 1142 | + stateChanged = (antialiasHint != newHint); | |
| 1143 | + antialiasHint = newHint; | |
| 1144 | + if (stateChanged) { | |
| 1145 | + textStateChanged = | |
| 1146 | + (textAntialiasHint == | |
| 1147 | + SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT); | |
| 1148 | + if (strokeState != STROKE_CUSTOM) { | |
| 1149 | + validateBasicStroke((BasicStroke) stroke); | |
| 1150 | + } | |
| 1151 | + } | |
| 1152 | + break; | |
| 1153 | + case SunHints.INTKEY_TEXT_ANTIALIASING: | |
| 1154 | + stateChanged = (textAntialiasHint != newHint); | |
| 1155 | + textStateChanged = stateChanged; | |
| 1156 | + textAntialiasHint = newHint; | |
| 1157 | + break; | |
| 1158 | + case SunHints.INTKEY_FRACTIONALMETRICS: | |
| 1159 | + stateChanged = (fractionalMetricsHint != newHint); | |
| 1160 | + textStateChanged = stateChanged; | |
| 1161 | + fractionalMetricsHint = newHint; | |
| 1162 | + break; | |
| 1163 | + case SunHints.INTKEY_AATEXT_LCD_CONTRAST: | |
| 1164 | + stateChanged = false; | |
| 1165 | + /* Already have validated it is an int 100 <= newHint <= 250 */ | |
| 1166 | + lcdTextContrast = newHint; | |
| 1167 | + break; | |
| 1168 | + case SunHints.INTKEY_INTERPOLATION: | |
| 1169 | + interpolationHint = newHint; | |
| 1170 | + switch (newHint) { | |
| 1171 | + case SunHints.INTVAL_INTERPOLATION_BICUBIC: | |
| 1172 | + newHint = AffineTransformOp.TYPE_BICUBIC; | |
| 1173 | + break; | |
| 1174 | + case SunHints.INTVAL_INTERPOLATION_BILINEAR: | |
| 1175 | + newHint = AffineTransformOp.TYPE_BILINEAR; | |
| 1176 | + break; | |
| 1177 | + default: | |
| 1178 | + case SunHints.INTVAL_INTERPOLATION_NEAREST_NEIGHBOR: | |
| 1179 | + newHint = AffineTransformOp.TYPE_NEAREST_NEIGHBOR; | |
| 1180 | + break; | |
| 1181 | + } | |
| 1182 | + stateChanged = (interpolationType != newHint); | |
| 1183 | + interpolationType = newHint; | |
| 1184 | + break; | |
| 1185 | + case SunHints.INTKEY_STROKE_CONTROL: | |
| 1186 | + stateChanged = (strokeHint != newHint); | |
| 1187 | + strokeHint = newHint; | |
| 1188 | + break; | |
| 1189 | + default: | |
| 1190 | + recognized = false; | |
| 1191 | + stateChanged = false; | |
| 1192 | + break; | |
| 1193 | + } | |
| 1194 | + if (recognized) { | |
| 1195 | + if (stateChanged) { | |
| 1196 | + invalidatePipe(); | |
| 1197 | + if (textStateChanged) { | |
| 1198 | + fontMetrics = null; | |
| 1199 | + this.cachedFRC = null; | |
| 1200 | + validFontInfo = false; | |
| 1201 | + this.glyphVectorFontInfo = null; | |
| 1202 | + } | |
| 1203 | + } | |
| 1204 | + if (hints != null) { | |
| 1205 | + hints.put(hintKey, hintValue); | |
| 1206 | + } | |
| 1207 | + return; | |
| 1208 | + } | |
| 1209 | + } | |
| 1210 | + // Nothing we recognize so none of "our state" has changed | |
| 1211 | + if (hints == null) { | |
| 1212 | + hints = makeHints(null); | |
| 1213 | + } | |
| 1214 | + hints.put(hintKey, hintValue); | |
| 1215 | + } | |
| 1216 | + | |
| 1217 | + | |
| 1218 | + /** | |
| 1219 | + * Returns the preferences for the rendering algorithms. | |
| 1220 | + * @param hintCategory The category of hint to be set. The strings | |
| 1221 | + * are defined in the RenderingHints class. | |
| 1222 | + * @return The preferences for rendering algorithms. The strings | |
| 1223 | + * are defined in the RenderingHints class. | |
| 1224 | + * @see RenderingHints | |
| 1225 | + */ | |
| 1226 | + public Object getRenderingHint(Key hintKey) { | |
| 1227 | + if (hints != null) { | |
| 1228 | + return hints.get(hintKey); | |
| 1229 | + } | |
| 1230 | + if (!(hintKey instanceof SunHints.Key)) { | |
| 1231 | + return null; | |
| 1232 | + } | |
| 1233 | + int keyindex = ((SunHints.Key)hintKey).getIndex(); | |
| 1234 | + switch (keyindex) { | |
| 1235 | + case SunHints.INTKEY_RENDERING: | |
| 1236 | + return SunHints.Value.get(SunHints.INTKEY_RENDERING, | |
| 1237 | + renderHint); | |
| 1238 | + case SunHints.INTKEY_ANTIALIASING: | |
| 1239 | + return SunHints.Value.get(SunHints.INTKEY_ANTIALIASING, | |
| 1240 | + antialiasHint); | |
| 1241 | + case SunHints.INTKEY_TEXT_ANTIALIASING: | |
| 1242 | + return SunHints.Value.get(SunHints.INTKEY_TEXT_ANTIALIASING, | |
| 1243 | + textAntialiasHint); | |
| 1244 | + case SunHints.INTKEY_FRACTIONALMETRICS: | |
| 1245 | + return SunHints.Value.get(SunHints.INTKEY_FRACTIONALMETRICS, | |
| 1246 | + fractionalMetricsHint); | |
| 1247 | + case SunHints.INTKEY_AATEXT_LCD_CONTRAST: | |
| 1248 | + return new Integer(lcdTextContrast); | |
| 1249 | + case SunHints.INTKEY_INTERPOLATION: | |
| 1250 | + switch (interpolationHint) { | |
| 1251 | + case SunHints.INTVAL_INTERPOLATION_NEAREST_NEIGHBOR: | |
| 1252 | + return SunHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR; | |
| 1253 | + case SunHints.INTVAL_INTERPOLATION_BILINEAR: | |
| 1254 | + return SunHints.VALUE_INTERPOLATION_BILINEAR; | |
| 1255 | + case SunHints.INTVAL_INTERPOLATION_BICUBIC: | |
| 1256 | + return SunHints.VALUE_INTERPOLATION_BICUBIC; | |
| 1257 | + } | |
| 1258 | + return null; | |
| 1259 | + case SunHints.INTKEY_STROKE_CONTROL: | |
| 1260 | + return SunHints.Value.get(SunHints.INTKEY_STROKE_CONTROL, | |
| 1261 | + strokeHint); | |
| 1262 | + } | |
| 1263 | + return null; | |
| 1264 | + } | |
| 1265 | + | |
| 1266 | + /** | |
| 1267 | + * Sets the preferences for the rendering algorithms. | |
| 1268 | + * Hint categories include controls for rendering quality and | |
| 1269 | + * overall time/quality trade-off in the rendering process. | |
| 1270 | + * @param hints The rendering hints to be set | |
| 1271 | + * @see RenderingHints | |
| 1272 | + */ | |
| 1273 | + public void setRenderingHints(Map<?,?> hints) { | |
| 1274 | + this.hints = null; | |
| 1275 | + renderHint = SunHints.INTVAL_RENDER_DEFAULT; | |
| 1276 | + antialiasHint = SunHints.INTVAL_ANTIALIAS_OFF; | |
| 1277 | + textAntialiasHint = SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT; | |
| 1278 | + fractionalMetricsHint = SunHints.INTVAL_FRACTIONALMETRICS_OFF; | |
| 1279 | + lcdTextContrast = lcdTextContrastDefaultValue; | |
| 1280 | + interpolationHint = -1; | |
| 1281 | + interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR; | |
| 1282 | + boolean customHintPresent = false; | |
| 1283 | + Iterator iter = hints.keySet().iterator(); | |
| 1284 | + while (iter.hasNext()) { | |
| 1285 | + Object key = iter.next(); | |
| 1286 | + if (key == SunHints.KEY_RENDERING || | |
| 1287 | + key == SunHints.KEY_ANTIALIASING || | |
| 1288 | + key == SunHints.KEY_TEXT_ANTIALIASING || | |
| 1289 | + key == SunHints.KEY_FRACTIONALMETRICS || | |
| 1290 | + key == SunHints.KEY_TEXT_ANTIALIAS_LCD_CONTRAST || | |
| 1291 | + key == SunHints.KEY_STROKE_CONTROL || | |
| 1292 | + key == SunHints.KEY_INTERPOLATION) | |
| 1293 | + { | |
| 1294 | + setRenderingHint((Key) key, hints.get(key)); | |
| 1295 | + } else { | |
| 1296 | + customHintPresent = true; | |
| 1297 | + } | |
| 1298 | + } | |
| 1299 | + if (customHintPresent) { | |
| 1300 | + this.hints = makeHints(hints); | |
| 1301 | + } | |
| 1302 | + invalidatePipe(); | |
| 1303 | + } | |
| 1304 | + | |
| 1305 | + /** | |
| 1306 | + * Adds a number of preferences for the rendering algorithms. | |
| 1307 | + * Hint categories include controls for rendering quality and | |
| 1308 | + * overall time/quality trade-off in the rendering process. | |
| 1309 | + * @param hints The rendering hints to be set | |
| 1310 | + * @see RenderingHints | |
| 1311 | + */ | |
| 1312 | + public void addRenderingHints(Map<?,?> hints) { | |
| 1313 | + boolean customHintPresent = false; | |
| 1314 | + Iterator iter = hints.keySet().iterator(); | |
| 1315 | + while (iter.hasNext()) { | |
| 1316 | + Object key = iter.next(); | |
| 1317 | + if (key == SunHints.KEY_RENDERING || | |
| 1318 | + key == SunHints.KEY_ANTIALIASING || | |
| 1319 | + key == SunHints.KEY_TEXT_ANTIALIASING || | |
| 1320 | + key == SunHints.KEY_FRACTIONALMETRICS || | |
| 1321 | + key == SunHints.KEY_TEXT_ANTIALIAS_LCD_CONTRAST || | |
| 1322 | + key == SunHints.KEY_STROKE_CONTROL || | |
| 1323 | + key == SunHints.KEY_INTERPOLATION) | |
| 1324 | + { | |
| 1325 | + setRenderingHint((Key) key, hints.get(key)); | |
| 1326 | + } else { | |
| 1327 | + customHintPresent = true; | |
| 1328 | + } | |
| 1329 | + } | |
| 1330 | + if (customHintPresent) { | |
| 1331 | + if (this.hints == null) { | |
| 1332 | + this.hints = makeHints(hints); | |
| 1333 | + } else { | |
| 1334 | + this.hints.putAll(hints); | |
| 1335 | + } | |
| 1336 | + } | |
| 1337 | + } | |
| 1338 | + | |
| 1339 | + /** | |
| 1340 | + * Gets the preferences for the rendering algorithms. | |
| 1341 | + * Hint categories include controls for rendering quality and | |
| 1342 | + * overall time/quality trade-off in the rendering process. | |
| 1343 | + * @see RenderingHints | |
| 1344 | + */ | |
| 1345 | + public RenderingHints getRenderingHints() { | |
| 1346 | + if (hints == null) { | |
| 1347 | + return makeHints(null); | |
| 1348 | + } else { | |
| 1349 | + return (RenderingHints) hints.clone(); | |
| 1350 | + } | |
| 1351 | + } | |
| 1352 | + | |
| 1353 | + RenderingHints makeHints(Map hints) { | |
| 1354 | + RenderingHints model = new RenderingHints(hints); | |
| 1355 | + model.put(SunHints.KEY_RENDERING, | |
| 1356 | + SunHints.Value.get(SunHints.INTKEY_RENDERING, | |
| 1357 | + renderHint)); | |
| 1358 | + model.put(SunHints.KEY_ANTIALIASING, | |
| 1359 | + SunHints.Value.get(SunHints.INTKEY_ANTIALIASING, | |
| 1360 | + antialiasHint)); | |
| 1361 | + model.put(SunHints.KEY_TEXT_ANTIALIASING, | |
| 1362 | + SunHints.Value.get(SunHints.INTKEY_TEXT_ANTIALIASING, | |
| 1363 | + textAntialiasHint)); | |
| 1364 | + model.put(SunHints.KEY_FRACTIONALMETRICS, | |
| 1365 | + SunHints.Value.get(SunHints.INTKEY_FRACTIONALMETRICS, | |
| 1366 | + fractionalMetricsHint)); | |
| 1367 | + model.put(SunHints.KEY_TEXT_ANTIALIAS_LCD_CONTRAST, | |
| 1368 | + Integer.valueOf(lcdTextContrast)); | |
| 1369 | + Object value; | |
| 1370 | + switch (interpolationHint) { | |
| 1371 | + case SunHints.INTVAL_INTERPOLATION_NEAREST_NEIGHBOR: | |
| 1372 | + value = SunHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR; | |
| 1373 | + break; | |
| 1374 | + case SunHints.INTVAL_INTERPOLATION_BILINEAR: | |
| 1375 | + value = SunHints.VALUE_INTERPOLATION_BILINEAR; | |
| 1376 | + break; | |
| 1377 | + case SunHints.INTVAL_INTERPOLATION_BICUBIC: | |
| 1378 | + value = SunHints.VALUE_INTERPOLATION_BICUBIC; | |
| 1379 | + break; | |
| 1380 | + default: | |
| 1381 | + value = null; | |
| 1382 | + break; | |
| 1383 | + } | |
| 1384 | + if (value != null) { | |
| 1385 | + model.put(SunHints.KEY_INTERPOLATION, value); | |
| 1386 | + } | |
| 1387 | + model.put(SunHints.KEY_STROKE_CONTROL, | |
| 1388 | + SunHints.Value.get(SunHints.INTKEY_STROKE_CONTROL, | |
| 1389 | + strokeHint)); | |
| 1390 | + return model; | |
| 1391 | + } | |
| 1392 | + | |
| 1393 | + /** | |
| 1394 | + * Concatenates the current transform of this Graphics2D with a | |
| 1395 | + * translation transformation. | |
| 1396 | + * This is equivalent to calling transform(T), where T is an | |
| 1397 | + * AffineTransform represented by the following matrix: | |
| 1398 | + * <pre> | |
| 1399 | + * [ 1 0 tx ] | |
| 1400 | + * [ 0 1 ty ] | |
| 1401 | + * [ 0 0 1 ] | |
| 1402 | + * </pre> | |
| 1403 | + */ | |
| 1404 | + public void translate(double tx, double ty) { | |
| 1405 | + transform.translate(tx, ty); | |
| 1406 | + invalidateTransform(); | |
| 1407 | + } | |
| 1408 | + | |
| 1409 | + /** | |
| 1410 | + * Concatenates the current transform of this Graphics2D with a | |
| 1411 | + * rotation transformation. | |
| 1412 | + * This is equivalent to calling transform(R), where R is an | |
| 1413 | + * AffineTransform represented by the following matrix: | |
| 1414 | + * <pre> | |
| 1415 | + * [ cos(theta) -sin(theta) 0 ] | |
| 1416 | + * [ sin(theta) cos(theta) 0 ] | |
| 1417 | + * [ 0 0 1 ] | |
| 1418 | + * </pre> | |
| 1419 | + * Rotating with a positive angle theta rotates points on the positive | |
| 1420 | + * x axis toward the positive y axis. | |
| 1421 | + * @param theta The angle of rotation in radians. | |
| 1422 | + */ | |
| 1423 | + public void rotate(double theta) { | |
| 1424 | + transform.rotate(theta); | |
| 1425 | + invalidateTransform(); | |
| 1426 | + } | |
| 1427 | + | |
| 1428 | + /** | |
| 1429 | + * Concatenates the current transform of this Graphics2D with a | |
| 1430 | + * translated rotation transformation. | |
| 1431 | + * This is equivalent to the following sequence of calls: | |
| 1432 | + * <pre> | |
| 1433 | + * translate(x, y); | |
| 1434 | + * rotate(theta); | |
| 1435 | + * translate(-x, -y); | |
| 1436 | + * </pre> | |
| 1437 | + * Rotating with a positive angle theta rotates points on the positive | |
| 1438 | + * x axis toward the positive y axis. | |
| 1439 | + * @param theta The angle of rotation in radians. | |
| 1440 | + * @param x The x coordinate of the origin of the rotation | |
| 1441 | + * @param y The x coordinate of the origin of the rotation | |
| 1442 | + */ | |
| 1443 | + public void rotate(double theta, double x, double y) { | |
| 1444 | + transform.rotate(theta, x, y); | |
| 1445 | + invalidateTransform(); | |
| 1446 | + } | |
| 1447 | + | |
| 1448 | + /** | |
| 1449 | + * Concatenates the current transform of this Graphics2D with a | |
| 1450 | + * scaling transformation. | |
| 1451 | + * This is equivalent to calling transform(S), where S is an | |
| 1452 | + * AffineTransform represented by the following matrix: | |
| 1453 | + * <pre> | |
| 1454 | + * [ sx 0 0 ] | |
| 1455 | + * [ 0 sy 0 ] | |
| 1456 | + * [ 0 0 1 ] | |
| 1457 | + * </pre> | |
| 1458 | + */ | |
| 1459 | + public void scale(double sx, double sy) { | |
| 1460 | + transform.scale(sx, sy); | |
| 1461 | + invalidateTransform(); | |
| 1462 | + } | |
| 1463 | + | |
| 1464 | + /** | |
| 1465 | + * Concatenates the current transform of this Graphics2D with a | |
| 1466 | + * shearing transformation. | |
| 1467 | + * This is equivalent to calling transform(SH), where SH is an | |
| 1468 | + * AffineTransform represented by the following matrix: | |
| 1469 | + * <pre> | |
| 1470 | + * [ 1 shx 0 ] | |
| 1471 | + * [ shy 1 0 ] | |
| 1472 | + * [ 0 0 1 ] | |
| 1473 | + * </pre> | |
| 1474 | + * @param shx The factor by which coordinates are shifted towards the | |
| 1475 | + * positive X axis direction according to their Y coordinate | |
| 1476 | + * @param shy The factor by which coordinates are shifted towards the | |
| 1477 | + * positive Y axis direction according to their X coordinate | |
| 1478 | + */ | |
| 1479 | + public void shear(double shx, double shy) { | |
| 1480 | + transform.shear(shx, shy); | |
| 1481 | + invalidateTransform(); | |
| 1482 | + } | |
| 1483 | + | |
| 1484 | + /** | |
| 1485 | + * Composes a Transform object with the transform in this | |
| 1486 | + * Graphics2D according to the rule last-specified-first-applied. | |
| 1487 | + * If the currrent transform is Cx, the result of composition | |
| 1488 | + * with Tx is a new transform Cx'. Cx' becomes the current | |
| 1489 | + * transform for this Graphics2D. | |
| 1490 | + * Transforming a point p by the updated transform Cx' is | |
| 1491 | + * equivalent to first transforming p by Tx and then transforming | |
| 1492 | + * the result by the original transform Cx. In other words, | |
| 1493 | + * Cx'(p) = Cx(Tx(p)). | |
| 1494 | + * A copy of the Tx is made, if necessary, so further | |
| 1495 | + * modifications to Tx do not affect rendering. | |
| 1496 | + * @param Tx The Transform object to be composed with the current | |
| 1497 | + * transform. | |
| 1498 | + * @see #setTransform | |
| 1499 | + * @see AffineTransform | |
| 1500 | + */ | |
| 1501 | + public void transform(AffineTransform xform) { | |
| 1502 | + this.transform.concatenate(xform); | |
| 1503 | + invalidateTransform(); | |
| 1504 | + } | |
| 1505 | + | |
| 1506 | + /** | |
| 1507 | + * Translate | |
| 1508 | + */ | |
| 1509 | + public void translate(int x, int y) { | |
| 1510 | + transform.translate(x, y); | |
| 1511 | + if (transformState <= TRANSFORM_INT_TRANSLATE) { | |
| 1512 | + transX += x; | |
| 1513 | + transY += y; | |
| 1514 | + transformState = (((transX | transY) == 0) ? | |
| 1515 | + TRANSFORM_ISIDENT : TRANSFORM_INT_TRANSLATE); | |
| 1516 | + } else { | |
| 1517 | + invalidateTransform(); | |
| 1518 | + } | |
| 1519 | + } | |
| 1520 | + | |
| 1521 | + /** | |
| 1522 | + * Sets the Transform in the current graphics state. | |
| 1523 | + * @param Tx The Transform object to be used in the rendering process. | |
| 1524 | + * @see #transform | |
| 1525 | + * @see TransformChain | |
| 1526 | + * @see AffineTransform | |
| 1527 | + */ | |
| 1528 | + public void setTransform(AffineTransform Tx) { | |
| 1529 | + if ((constrainX|constrainY) == 0) { | |
| 1530 | + transform.setTransform(Tx); | |
| 1531 | + } else { | |
| 1532 | + transform.setToTranslation(constrainX, constrainY); | |
| 1533 | + transform.concatenate(Tx); | |
| 1534 | + } | |
| 1535 | + invalidateTransform(); | |
| 1536 | + } | |
| 1537 | + | |
| 1538 | + protected void invalidateTransform() { | |
| 1539 | + int type = transform.getType(); | |
| 1540 | + int origTransformState = transformState; | |
| 1541 | + if (type == AffineTransform.TYPE_IDENTITY) { | |
| 1542 | + transformState = TRANSFORM_ISIDENT; | |
| 1543 | + transX = transY = 0; | |
| 1544 | + } else if (type == AffineTransform.TYPE_TRANSLATION) { | |
| 1545 | + double dtx = transform.getTranslateX(); | |
| 1546 | + double dty = transform.getTranslateY(); | |
| 1547 | + transX = (int) Math.floor(dtx + 0.5); | |
| 1548 | + transY = (int) Math.floor(dty + 0.5); | |
| 1549 | + if (dtx == transX && dty == transY) { | |
| 1550 | + transformState = TRANSFORM_INT_TRANSLATE; | |
| 1551 | + } else { | |
| 1552 | + transformState = TRANSFORM_ANY_TRANSLATE; | |
| 1553 | + } | |
| 1554 | + } else if ((type & (AffineTransform.TYPE_FLIP | | |
| 1555 | + AffineTransform.TYPE_MASK_ROTATION | | |
| 1556 | + AffineTransform.TYPE_GENERAL_TRANSFORM)) == 0) | |
| 1557 | + { | |
| 1558 | + transformState = TRANSFORM_TRANSLATESCALE; | |
| 1559 | + transX = transY = 0; | |
| 1560 | + } else { | |
| 1561 | + transformState = TRANSFORM_GENERIC; | |
| 1562 | + transX = transY = 0; | |
| 1563 | + } | |
| 1564 | + | |
| 1565 | + if (transformState >= TRANSFORM_TRANSLATESCALE || | |
| 1566 | + origTransformState >= TRANSFORM_TRANSLATESCALE) | |
| 1567 | + { | |
| 1568 | + /* Its only in this case that the previous or current transform | |
| 1569 | + * was more than a translate that font info is invalidated | |
| 1570 | + */ | |
| 1571 | + cachedFRC = null; | |
| 1572 | + this.validFontInfo = false; | |
| 1573 | + this.fontMetrics = null; | |
| 1574 | + this.glyphVectorFontInfo = null; | |
| 1575 | + | |
| 1576 | + if (transformState != origTransformState) { | |
| 1577 | + invalidatePipe(); | |
| 1578 | + } | |
| 1579 | + } | |
| 1580 | + if (strokeState != STROKE_CUSTOM) { | |
| 1581 | + validateBasicStroke((BasicStroke) stroke); | |
| 1582 | + } | |
| 1583 | + } | |
| 1584 | + | |
| 1585 | + /** | |
| 1586 | + * Returns the current Transform in the Graphics2D state. | |
| 1587 | + * @see #transform | |
| 1588 | + * @see #setTransform | |
| 1589 | + */ | |
| 1590 | + public AffineTransform getTransform() { | |
| 1591 | + if ((constrainX|constrainY) == 0) { | |
| 1592 | + return new AffineTransform(transform); | |
| 1593 | + } | |
| 1594 | + AffineTransform tx = | |
| 1595 | + AffineTransform.getTranslateInstance(-constrainX, -constrainY); | |
| 1596 | + tx.concatenate(transform); | |
| 1597 | + return tx; | |
| 1598 | + } | |
| 1599 | + | |
| 1600 | + /** | |
| 1601 | + * Returns the current Transform ignoring the "constrain" | |
| 1602 | + * rectangle. | |
| 1603 | + */ | |
| 1604 | + public AffineTransform cloneTransform() { | |
| 1605 | + return new AffineTransform(transform); | |
| 1606 | + } | |
| 1607 | + | |
| 1608 | + /** | |
| 1609 | + * Returns the current Paint in the Graphics2D state. | |
| 1610 | + * @see #setPaint | |
| 1611 | + * @see java.awt.Graphics#setColor | |
| 1612 | + */ | |
| 1613 | + public Paint getPaint() { | |
| 1614 | + return paint; | |
| 1615 | + } | |
| 1616 | + | |
| 1617 | + /** | |
| 1618 | + * Returns the current Composite in the Graphics2D state. | |
| 1619 | + * @see #setComposite | |
| 1620 | + */ | |
| 1621 | + public Composite getComposite() { | |
| 1622 | + return composite; | |
| 1623 | + } | |
| 1624 | + | |
| 1625 | + public Color getColor() { | |
| 1626 | + return foregroundColor; | |
| 1627 | + } | |
| 1628 | + | |
| 1629 | + /* | |
| 1630 | + * Validate the eargb and pixel fields against the current color. | |
| 1631 | + * | |
| 1632 | + * The eargb field must take into account the extraAlpha | |
| 1633 | + * value of an AlphaComposite. It may also take into account | |
| 1634 | + * the Fsrc Porter-Duff blending function if such a function is | |
| 1635 | + * a constant (see handling of Clear mode below). For instance, | |
| 1636 | + * by factoring in the (Fsrc == 0) state of the Clear mode we can | |
| 1637 | + * use a SrcNoEa loop just as easily as a general Alpha loop | |
| 1638 | + * since the math will be the same in both cases. | |
| 1639 | + * | |
| 1640 | + * The pixel field will always be the best pixel data choice for | |
| 1641 | + * the final result of all calculations applied to the eargb field. | |
| 1642 | + * | |
| 1643 | + * Note that this method is only necessary under the following | |
| 1644 | + * conditions: | |
| 1645 | + * (paintState <= PAINT_ALPHA_COLOR && | |
| 1646 | + * compositeState <= COMP_CUSTOM) | |
| 1647 | + * though nothing bad will happen if it is run in other states. | |
| 1648 | + */ | |
| 1649 | + final void validateColor() { | |
| 1650 | + int eargb; | |
| 1651 | + if (imageComp == CompositeType.Clear) { | |
| 1652 | + eargb = 0; | |
| 1653 | + } else { | |
| 1654 | + eargb = foregroundColor.getRGB(); | |
| 1655 | + if (compositeState <= COMP_ALPHA && | |
| 1656 | + imageComp != CompositeType.SrcNoEa && | |
| 1657 | + imageComp != CompositeType.SrcOverNoEa) | |
| 1658 | + { | |
| 1659 | + AlphaComposite alphacomp = (AlphaComposite) composite; | |
| 1660 | + int a = Math.round(alphacomp.getAlpha() * (eargb >>> 24)); | |
| 1661 | + eargb = (eargb & 0x00ffffff) | (a << 24); | |
| 1662 | + } | |
| 1663 | + } | |
| 1664 | + this.eargb = eargb; | |
| 1665 | + this.pixel = surfaceData.pixelFor(eargb); | |
| 1666 | + } | |
| 1667 | + | |
| 1668 | + public void setColor(Color color) { | |
| 1669 | + if (color == null || color == paint) { | |
| 1670 | + return; | |
| 1671 | + } | |
| 1672 | + this.paint = foregroundColor = color; | |
| 1673 | + validateColor(); | |
| 1674 | + if ((eargb >> 24) == -1) { | |
| 1675 | + if (paintState == PAINT_OPAQUECOLOR) { | |
| 1676 | + return; | |
| 1677 | + } | |
| 1678 | + paintState = PAINT_OPAQUECOLOR; | |
| 1679 | + if (imageComp == CompositeType.SrcOverNoEa) { | |
| 1680 | + // special case where compState depends on opacity of paint | |
| 1681 | + compositeState = COMP_ISCOPY; | |
| 1682 | + } | |
| 1683 | + } else { | |
| 1684 | + if (paintState == PAINT_ALPHACOLOR) { | |
| 1685 | + return; | |
| 1686 | + } | |
| 1687 | + paintState = PAINT_ALPHACOLOR; | |
| 1688 | + if (imageComp == CompositeType.SrcOverNoEa) { | |
| 1689 | + // special case where compState depends on opacity of paint | |
| 1690 | + compositeState = COMP_ALPHA; | |
| 1691 | + } | |
| 1692 | + } | |
| 1693 | + validFontInfo = false; | |
| 1694 | + invalidatePipe(); | |
| 1695 | + } | |
| 1696 | + | |
| 1697 | + /** | |
| 1698 | + * Sets the background color in this context used for clearing a region. | |
| 1699 | + * When Graphics2D is constructed for a component, the backgroung color is | |
| 1700 | + * inherited from the component. Setting the background color in the | |
| 1701 | + * Graphics2D context only affects the subsequent clearRect() calls and | |
| 1702 | + * not the background color of the component. To change the background | |
| 1703 | + * of the component, use appropriate methods of the component. | |
| 1704 | + * @param color The background color that should be used in | |
| 1705 | + * subsequent calls to clearRect(). | |
| 1706 | + * @see getBackground | |
| 1707 | + * @see Graphics.clearRect() | |
| 1708 | + */ | |
| 1709 | + public void setBackground(Color color) { | |
| 1710 | + backgroundColor = color; | |
| 1711 | + } | |
| 1712 | + | |
| 1713 | + /** | |
| 1714 | + * Returns the background color used for clearing a region. | |
| 1715 | + * @see setBackground | |
| 1716 | + */ | |
| 1717 | + public Color getBackground() { | |
| 1718 | + return backgroundColor; | |
| 1719 | + } | |
| 1720 | + | |
| 1721 | + /** | |
| 1722 | + * Returns the current Stroke in the Graphics2D state. | |
| 1723 | + * @see setStroke | |
| 1724 | + */ | |
| 1725 | + public Stroke getStroke() { | |
| 1726 | + return stroke; | |
| 1727 | + } | |
| 1728 | + | |
| 1729 | + public Rectangle getClipBounds() { | |
| 1730 | + Rectangle r; | |
| 1731 | + if (clipState == CLIP_DEVICE) { | |
| 1732 | + r = null; | |
| 1733 | + } else if (transformState <= TRANSFORM_INT_TRANSLATE) { | |
| 1734 | + if (usrClip instanceof Rectangle) { | |
| 1735 | + r = new Rectangle((Rectangle) usrClip); | |
| 1736 | + } else { | |
| 1737 | + r = usrClip.getBounds(); | |
| 1738 | + } | |
| 1739 | + r.translate(-transX, -transY); | |
| 1740 | + } else { | |
| 1741 | + r = getClip().getBounds(); | |
| 1742 | + } | |
| 1743 | + return r; | |
| 1744 | + } | |
| 1745 | + | |
| 1746 | + public Rectangle getClipBounds(Rectangle r) { | |
| 1747 | + if (clipState != CLIP_DEVICE) { | |
| 1748 | + if (transformState <= TRANSFORM_INT_TRANSLATE) { | |
| 1749 | + if (usrClip instanceof Rectangle) { | |
| 1750 | + r.setBounds((Rectangle) usrClip); | |
| 1751 | + } else { | |
| 1752 | + r.setBounds(usrClip.getBounds()); | |
| 1753 | + } | |
| 1754 | + r.translate(-transX, -transY); | |
| 1755 | + } else { | |
| 1756 | + r.setBounds(getClip().getBounds()); | |
| 1757 | + } | |
| 1758 | + } else if (r == null) { | |
| 1759 | + throw new NullPointerException("null rectangle parameter"); | |
| 1760 | + } | |
| 1761 | + return r; | |
| 1762 | + } | |
| 1763 | + | |
| 1764 | + public boolean hitClip(int x, int y, int width, int height) { | |
| 1765 | + if (width <= 0 || height <= 0) { | |
| 1766 | + return false; | |
| 1767 | + } | |
| 1768 | + if (transformState > TRANSFORM_INT_TRANSLATE) { | |
| 1769 | + // Note: Technically the most accurate test would be to | |
| 1770 | + // raster scan the parallelogram of the transformed rectangle | |
| 1771 | + // and do a span for span hit test against the clip, but for | |
| 1772 | + // speed we approximate the test with a bounding box of the | |
| 1773 | + // transformed rectangle. The cost of rasterizing the | |
| 1774 | + // transformed rectangle is probably high enough that it is | |
| 1775 | + // not worth doing so to save the caller from having to call | |
| 1776 | + // a rendering method where we will end up discovering the | |
| 1777 | + // same answer in about the same amount of time anyway. | |
| 1778 | + // This logic breaks down if this hit test is being performed | |
| 1779 | + // on the bounds of a group of shapes in which case it might | |
| 1780 | + // be beneficial to be a little more accurate to avoid lots | |
| 1781 | + // of subsequent rendering calls. In either case, this relaxed | |
| 1782 | + // test should not be significantly less accurate than the | |
| 1783 | + // optimal test for most transforms and so the conservative | |
| 1784 | + // answer should not cause too much extra work. | |
| 1785 | + | |
| 1786 | + double d[] = { | |
| 1787 | + x, y, | |
| 1788 | + x+width, y, | |
| 1789 | + x, y+height, | |
| 1790 | + x+width, y+height | |
| 1791 | + }; | |
| 1792 | + transform.transform(d, 0, d, 0, 4); | |
| 1793 | + x = (int) Math.floor(Math.min(Math.min(d[0], d[2]), | |
| 1794 | + Math.min(d[4], d[6]))); | |
| 1795 | + y = (int) Math.floor(Math.min(Math.min(d[1], d[3]), | |
| 1796 | + Math.min(d[5], d[7]))); | |
| 1797 | + width = (int) Math.ceil(Math.max(Math.max(d[0], d[2]), | |
| 1798 | + Math.max(d[4], d[6]))); | |
| 1799 | + height = (int) Math.ceil(Math.max(Math.max(d[1], d[3]), | |
| 1800 | + Math.max(d[5], d[7]))); | |
| 1801 | + } else { | |
| 1802 | + x += transX; | |
| 1803 | + y += transY; | |
| 1804 | + width += x; | |
| 1805 | + height += y; | |
| 1806 | + } | |
| 1807 | + if (!getCompClip().intersectsQuickCheckXYXY(x, y, width, height)) { | |
| 1808 | + return false; | |
| 1809 | + } | |
| 1810 | + // REMIND: We could go one step further here and examine the | |
| 1811 | + // non-rectangular clip shape more closely if there is one. | |
| 1812 | + // Since the clip has already been rasterized, the performance | |
| 1813 | + // penalty of doing the scan is probably still within the bounds | |
| 1814 | + // of a good tradeoff between speed and quality of the answer. | |
| 1815 | + return true; | |
| 1816 | + } | |
| 1817 | + | |
| 1818 | + protected void validateCompClip() { | |
| 1819 | + int origClipState = clipState; | |
| 1820 | + if (usrClip == null) { | |
| 1821 | + clipState = CLIP_DEVICE; | |
| 1822 | + clipRegion = devClip; | |
| 1823 | + } else if (usrClip instanceof Rectangle2D) { | |
| 1824 | + clipState = CLIP_RECTANGULAR; | |
| 1825 | + if (usrClip instanceof Rectangle) { | |
| 1826 | + clipRegion = devClip.getIntersection((Rectangle)usrClip); | |
| 1827 | + } else { | |
| 1828 | + clipRegion = devClip.getIntersection(usrClip.getBounds()); | |
| 1829 | + } | |
| 1830 | + } else { | |
| 1831 | + PathIterator cpi = usrClip.getPathIterator(null); | |
| 1832 | + int box[] = new int[4]; | |
| 1833 | + ShapeSpanIterator sr = LoopPipe.getFillSSI(this); | |
| 1834 | + try { | |
| 1835 | + sr.setOutputArea(devClip); | |
| 1836 | + sr.appendPath(cpi); | |
| 1837 | + sr.getPathBox(box); | |
| 1838 | + Region r = Region.getInstance(box); | |
| 1839 | + r.appendSpans(sr); | |
| 1840 | + clipRegion = r; | |
| 1841 | + clipState = | |
| 1842 | + r.isRectangular() ? CLIP_RECTANGULAR : CLIP_SHAPE; | |
| 1843 | + } finally { | |
| 1844 | + sr.dispose(); | |
| 1845 | + } | |
| 1846 | + } | |
| 1847 | + if (origClipState != clipState && | |
| 1848 | + (clipState == CLIP_SHAPE || origClipState == CLIP_SHAPE)) | |
| 1849 | + { | |
| 1850 | + validFontInfo = false; | |
| 1851 | + invalidatePipe(); | |
| 1852 | + } | |
| 1853 | + } | |
| 1854 | + | |
| 1855 | + static final int NON_RECTILINEAR_TRANSFORM_MASK = | |
| 1856 | + (AffineTransform.TYPE_GENERAL_TRANSFORM | | |
| 1857 | + AffineTransform.TYPE_GENERAL_ROTATION); | |
| 1858 | + | |
| 1859 | + protected Shape transformShape(Shape s) { | |
| 1860 | + if (s == null) { | |
| 1861 | + return null; | |
| 1862 | + } | |
| 1863 | + if (transformState > TRANSFORM_INT_TRANSLATE) { | |
| 1864 | + return transformShape(transform, s); | |
| 1865 | + } else { | |
| 1866 | + return transformShape(transX, transY, s); | |
| 1867 | + } | |
| 1868 | + } | |
| 1869 | + | |
| 1870 | + public Shape untransformShape(Shape s) { | |
| 1871 | + if (s == null) { | |
| 1872 | + return null; | |
| 1873 | + } | |
| 1874 | + if (transformState > TRANSFORM_INT_TRANSLATE) { | |
| 1875 | + try { | |
| 1876 | + return transformShape(transform.createInverse(), s); | |
| 1877 | + } catch (NoninvertibleTransformException e) { | |
| 1878 | + return null; | |
| 1879 | + } | |
| 1880 | + } else { | |
| 1881 | + return transformShape(-transX, -transY, s); | |
| 1882 | + } | |
| 1883 | + } | |
| 1884 | + | |
| 1885 | + protected static Shape transformShape(int tx, int ty, Shape s) { | |
| 1886 | + if (s == null) { | |
| 1887 | + return null; | |
| 1888 | + } | |
| 1889 | + | |
| 1890 | + if (s instanceof Rectangle) { | |
| 1891 | + Rectangle r = s.getBounds(); | |
| 1892 | + r.translate(tx, ty); | |
| 1893 | + return r; | |
| 1894 | + } | |
| 1895 | + if (s instanceof Rectangle2D) { | |
| 1896 | + Rectangle2D rect = (Rectangle2D) s; | |
| 1897 | + return new Rectangle2D.Double(rect.getX() + tx, | |
| 1898 | + rect.getY() + ty, | |
| 1899 | + rect.getWidth(), | |
| 1900 | + rect.getHeight()); | |
| 1901 | + } | |
| 1902 | + | |
| 1903 | + if (tx == 0 && ty == 0) { | |
| 1904 | + return cloneShape(s); | |
| 1905 | + } | |
| 1906 | + | |
| 1907 | + AffineTransform mat = AffineTransform.getTranslateInstance(tx, ty); | |
| 1908 | + return mat.createTransformedShape(s); | |
| 1909 | + } | |
| 1910 | + | |
| 1911 | + protected static Shape transformShape(AffineTransform tx, Shape clip) { | |
| 1912 | + if (clip == null) { | |
| 1913 | + return null; | |
| 1914 | + } | |
| 1915 | + | |
| 1916 | + if (clip instanceof Rectangle2D && | |
| 1917 | + (tx.getType() & NON_RECTILINEAR_TRANSFORM_MASK) == 0) | |
| 1918 | + { | |
| 1919 | + Rectangle2D rect = (Rectangle2D) clip; | |
| 1920 | + double matrix[] = new double[4]; | |
| 1921 | + matrix[0] = rect.getX(); | |
| 1922 | + matrix[1] = rect.getY(); | |
| 1923 | + matrix[2] = matrix[0] + rect.getWidth(); | |
| 1924 | + matrix[3] = matrix[1] + rect.getHeight(); | |
| 1925 | + tx.transform(matrix, 0, matrix, 0, 2); | |
| 1926 | + rect = new Rectangle2D.Float(); | |
| 1927 | + rect.setFrameFromDiagonal(matrix[0], matrix[1], | |
| 1928 | + matrix[2], matrix[3]); | |
| 1929 | + return rect; | |
| 1930 | + } | |
| 1931 | + | |
| 1932 | + if (tx.isIdentity()) { | |
| 1933 | + return cloneShape(clip); | |
| 1934 | + } | |
| 1935 | + | |
| 1936 | + return tx.createTransformedShape(clip); | |
| 1937 | + } | |
| 1938 | + | |
| 1939 | + public void clipRect(int x, int y, int w, int h) { | |
| 1940 | + clip(new Rectangle(x, y, w, h)); | |
| 1941 | + } | |
| 1942 | + | |
| 1943 | + public void setClip(int x, int y, int w, int h) { | |
| 1944 | + setClip(new Rectangle(x, y, w, h)); | |
| 1945 | + } | |
| 1946 | + | |
| 1947 | + public Shape getClip() { | |
| 1948 | + return untransformShape(usrClip); | |
| 1949 | + } | |
| 1950 | + | |
| 1951 | + public void setClip(Shape sh) { | |
| 1952 | + usrClip = transformShape(sh); | |
| 1953 | + validateCompClip(); | |
| 1954 | + } | |
| 1955 | + | |
| 1956 | + /** | |
| 1957 | + * Intersects the current clip with the specified Path and sets the | |
| 1958 | + * current clip to the resulting intersection. The clip is transformed | |
| 1959 | + * with the current transform in the Graphics2D state before being | |
| 1960 | + * intersected with the current clip. This method is used to make the | |
| 1961 | + * current clip smaller. To make the clip larger, use any setClip method. | |
| 1962 | + * @param p The Path to be intersected with the current clip. | |
| 1963 | + */ | |
| 1964 | + public void clip(Shape s) { | |
| 1965 | + s = transformShape(s); | |
| 1966 | + if (usrClip != null) { | |
| 1967 | + s = intersectShapes(usrClip, s, true, true); | |
| 1968 | + } | |
| 1969 | + usrClip = s; | |
| 1970 | + validateCompClip(); | |
| 1971 | + } | |
| 1972 | + | |
| 1973 | + public void setPaintMode() { | |
| 1974 | + setComposite(AlphaComposite.SrcOver); | |
| 1975 | + } | |
| 1976 | + | |
| 1977 | + public void setXORMode(Color c) { | |
| 1978 | + if (c == null) { | |
| 1979 | + throw new IllegalArgumentException("null XORColor"); | |
| 1980 | + } | |
| 1981 | + setComposite(new XORComposite(c, surfaceData)); | |
| 1982 | + } | |
| 1983 | + | |
| 1984 | + Blit lastCAblit; | |
| 1985 | + Composite lastCAcomp; | |
| 1986 | + | |
| 1987 | + public void copyArea(int x, int y, int w, int h, int dx, int dy) { | |
| 1988 | + try { | |
| 1989 | + doCopyArea(x, y, w, h, dx, dy); | |
| 1990 | + } catch (InvalidPipeException e) { | |
| 1991 | + revalidateAll(); | |
| 1992 | + try { | |
| 1993 | + doCopyArea(x, y, w, h, dx, dy); | |
| 1994 | + } catch (InvalidPipeException e2) { | |
| 1995 | + // Still catching the exception; we are not yet ready to | |
| 1996 | + // validate the surfaceData correctly. Fail for now and | |
| 1997 | + // try again next time around. | |
| 1998 | + } | |
| 1999 | + } finally { | |
| 2000 | + surfaceData.markDirty(); | |
| 2001 | + } | |
| 2002 | + } | |
| 2003 | + | |
| 2004 | + private void doCopyArea(int x, int y, int w, int h, int dx, int dy) { | |
| 2005 | + if (w <= 0 || h <= 0) { | |
| 2006 | + return; | |
| 2007 | + } | |
| 2008 | + SurfaceData theData = surfaceData; | |
| 2009 | + if (theData.copyArea(this, x, y, w, h, dx, dy)) { | |
| 2010 | + return; | |
| 2011 | + } | |
| 2012 | + if (transformState >= TRANSFORM_TRANSLATESCALE) { | |
| 2013 | + throw new InternalError("transformed copyArea not implemented yet"); | |
| 2014 | + } | |
| 2015 | + // REMIND: This method does not deal with missing data from the | |
| 2016 | + // source object (i.e. it does not send exposure events...) | |
| 2017 | + | |
| 2018 | + Region clip = getCompClip(); | |
| 2019 | + | |
| 2020 | + Composite comp = composite; | |
| 2021 | + if (lastCAcomp != comp) { | |
| 2022 | + SurfaceType dsttype = theData.getSurfaceType(); | |
| 2023 | + CompositeType comptype = imageComp; | |
| 2024 | + if (CompositeType.SrcOverNoEa.equals(comptype) && | |
| 2025 | + theData.getTransparency() == Transparency.OPAQUE) | |
| 2026 | + { | |
| 2027 | + comptype = CompositeType.SrcNoEa; | |
| 2028 | + } | |
| 2029 | + lastCAblit = Blit.locate(dsttype, comptype, dsttype); | |
| 2030 | + lastCAcomp = comp; | |
| 2031 | + } | |
| 2032 | + | |
| 2033 | + x += transX; | |
| 2034 | + y += transY; | |
| 2035 | + | |
| 2036 | + Blit ob = lastCAblit; | |
| 2037 | + if (dy == 0 && dx > 0 && dx < w) { | |
| 2038 | + while (w > 0) { | |
| 2039 | + int partW = Math.min(w, dx); | |
| 2040 | + w -= partW; | |
| 2041 | + int sx = x + w; | |
| 2042 | + ob.Blit(theData, theData, comp, clip, | |
| 2043 | + sx, y, sx+dx, y+dy, partW, h); | |
| 2044 | + } | |
| 2045 | + return; | |
| 2046 | + } | |
| 2047 | + if (dy > 0 && dy < h && dx > -w && dx < w) { | |
| 2048 | + while (h > 0) { | |
| 2049 | + int partH = Math.min(h, dy); | |
| 2050 | + h -= partH; | |
| 2051 | + int sy = y + h; | |
| 2052 | + ob.Blit(theData, theData, comp, clip, | |
| 2053 | + x, sy, x+dx, sy+dy, w, partH); | |
| 2054 | + } | |
| 2055 | + return; | |
| 2056 | + } | |
| 2057 | + ob.Blit(theData, theData, comp, clip, x, y, x+dx, y+dy, w, h); | |
| 2058 | + } | |
| 2059 | + | |
| 2060 | + /* | |
| 2061 | + public void XcopyArea(int x, int y, int w, int h, int dx, int dy) { | |
| 2062 | + Rectangle rect = new Rectangle(x, y, w, h); | |
| 2063 | + rect = transformBounds(rect, transform); | |
| 2064 | + Point2D point = new Point2D.Float(dx, dy); | |
| 2065 | + Point2D root = new Point2D.Float(0, 0); | |
| 2066 | + point = transform.transform(point, point); | |
| 2067 | + root = transform.transform(root, root); | |
| 2068 | + int fdx = (int)(point.getX()-root.getX()); | |
| 2069 | + int fdy = (int)(point.getY()-root.getY()); | |
| 2070 | + | |
| 2071 | + Rectangle r = getCompBounds().intersection(rect.getBounds()); | |
| 2072 | + | |
| 2073 | + if (r.isEmpty()) { | |
| 2074 | + return; | |
| 2075 | + } | |
| 2076 | + | |
| 2077 | + // Begin Rasterizer for Clip Shape | |
| 2078 | + boolean skipClip = true; | |
| 2079 | + byte[] clipAlpha = null; | |
| 2080 | + | |
| 2081 | + if (clipState == CLIP_SHAPE) { | |
| 2082 | + | |
| 2083 | + int box[] = new int[4]; | |
| 2084 | + | |
| 2085 | + clipRegion.getBounds(box); | |
| 2086 | + Rectangle devR = new Rectangle(box[0], box[1], | |
| 2087 | + box[2] - box[0], | |
| 2088 | + box[3] - box[1]); | |
| 2089 | + if (!devR.isEmpty()) { | |
| 2090 | + OutputManager mgr = getOutputManager(); | |
| 2091 | + RegionIterator ri = clipRegion.getIterator(); | |
| 2092 | + while (ri.nextYRange(box)) { | |
| 2093 | + int spany = box[1]; | |
| 2094 | + int spanh = box[3] - spany; | |
| 2095 | + while (ri.nextXBand(box)) { | |
| 2096 | + int spanx = box[0]; | |
| 2097 | + int spanw = box[2] - spanx; | |
| 2098 | + mgr.copyArea(this, null, | |
| 2099 | + spanw, 0, | |
| 2100 | + spanx, spany, | |
| 2101 | + spanw, spanh, | |
| 2102 | + fdx, fdy, | |
| 2103 | + null); | |
| 2104 | + } | |
| 2105 | + } | |
| 2106 | + } | |
| 2107 | + return; | |
| 2108 | + } | |
| 2109 | + // End Rasterizer for Clip Shape | |
| 2110 | + | |
| 2111 | + getOutputManager().copyArea(this, null, | |
| 2112 | + r.width, 0, | |
| 2113 | + r.x, r.y, r.width, | |
| 2114 | + r.height, fdx, fdy, | |
| 2115 | + null); | |
| 2116 | + } | |
| 2117 | + */ | |
| 2118 | + | |
| 2119 | + public void drawLine(int x1, int y1, int x2, int y2) { | |
| 2120 | + try { | |
| 2121 | + drawpipe.drawLine(this, x1, y1, x2, y2); | |
| 2122 | + } catch (InvalidPipeException e) { | |
| 2123 | + revalidateAll(); | |
| 2124 | + try { | |
| 2125 | + drawpipe.drawLine(this, x1, y1, x2, y2); | |
| 2126 | + } catch (InvalidPipeException e2) { | |
| 2127 | + // Still catching the exception; we are not yet ready to | |
| 2128 | + // validate the surfaceData correctly. Fail for now and | |
| 2129 | + // try again next time around. | |
| 2130 | + } | |
| 2131 | + } finally { | |
| 2132 | + surfaceData.markDirty(); | |
| 2133 | + } | |
| 2134 | + } | |
| 2135 | + | |
| 2136 | + public void drawRoundRect(int x, int y, int w, int h, int arcW, int arcH) { | |
| 2137 | + try { | |
| 2138 | + drawpipe.drawRoundRect(this, x, y, w, h, arcW, arcH); | |
| 2139 | + } catch (InvalidPipeException e) { | |
| 2140 | + revalidateAll(); | |
| 2141 | + try { | |
| 2142 | + drawpipe.drawRoundRect(this, x, y, w, h, arcW, arcH); | |
| 2143 | + } catch (InvalidPipeException e2) { | |
| 2144 | + // Still catching the exception; we are not yet ready to | |
| 2145 | + // validate the surfaceData correctly. Fail for now and | |
| 2146 | + // try again next time around. | |
| 2147 | + } | |
| 2148 | + } finally { | |
| 2149 | + surfaceData.markDirty(); | |
| 2150 | + } | |
| 2151 | + } | |
| 2152 | + | |
| 2153 | + public void fillRoundRect(int x, int y, int w, int h, int arcW, int arcH) { | |
| 2154 | + try { | |
| 2155 | + fillpipe.fillRoundRect(this, x, y, w, h, arcW, arcH); | |
| 2156 | + } catch (InvalidPipeException e) { | |
| 2157 | + revalidateAll(); | |
| 2158 | + try { | |
| 2159 | + fillpipe.fillRoundRect(this, x, y, w, h, arcW, arcH); | |
| 2160 | + } catch (InvalidPipeException e2) { | |
| 2161 | + // Still catching the exception; we are not yet ready to | |
| 2162 | + // validate the surfaceData correctly. Fail for now and | |
| 2163 | + // try again next time around. | |
| 2164 | + } | |
| 2165 | + } finally { | |
| 2166 | + surfaceData.markDirty(); | |
| 2167 | + } | |
| 2168 | + } | |
| 2169 | + | |
| 2170 | + public void drawOval(int x, int y, int w, int h) { | |
| 2171 | + try { | |
| 2172 | + drawpipe.drawOval(this, x, y, w, h); | |
| 2173 | + } catch (InvalidPipeException e) { | |
| 2174 | + revalidateAll(); | |
| 2175 | + try { | |
| 2176 | + drawpipe.drawOval(this, x, y, w, h); | |
| 2177 | + } catch (InvalidPipeException e2) { | |
| 2178 | + // Still catching the exception; we are not yet ready to | |
| 2179 | + // validate the surfaceData correctly. Fail for now and | |
| 2180 | + // try again next time around. | |
| 2181 | + } | |
| 2182 | + } finally { | |
| 2183 | + surfaceData.markDirty(); | |
| 2184 | + } | |
| 2185 | + } | |
| 2186 | + | |
| 2187 | + public void fillOval(int x, int y, int w, int h) { | |
| 2188 | + try { | |
| 2189 | + fillpipe.fillOval(this, x, y, w, h); | |
| 2190 | + } catch (InvalidPipeException e) { | |
| 2191 | + revalidateAll(); | |
| 2192 | + try { | |
| 2193 | + fillpipe.fillOval(this, x, y, w, h); | |
| 2194 | + } catch (InvalidPipeException e2) { | |
| 2195 | + // Still catching the exception; we are not yet ready to | |
| 2196 | + // validate the surfaceData correctly. Fail for now and | |
| 2197 | + // try again next time around. | |
| 2198 | + } | |
| 2199 | + } finally { | |
| 2200 | + surfaceData.markDirty(); | |
| 2201 | + } | |
| 2202 | + } | |
| 2203 | + | |
| 2204 | + public void drawArc(int x, int y, int w, int h, | |
| 2205 | + int startAngl, int arcAngl) { | |
| 2206 | + try { | |
| 2207 | + drawpipe.drawArc(this, x, y, w, h, startAngl, arcAngl); | |
| 2208 | + } catch (InvalidPipeException e) { | |
| 2209 | + revalidateAll(); | |
| 2210 | + try { | |
| 2211 | + drawpipe.drawArc(this, x, y, w, h, startAngl, arcAngl); | |
| 2212 | + } catch (InvalidPipeException e2) { | |
| 2213 | + // Still catching the exception; we are not yet ready to | |
| 2214 | + // validate the surfaceData correctly. Fail for now and | |
| 2215 | + // try again next time around. | |
| 2216 | + } | |
| 2217 | + } finally { | |
| 2218 | + surfaceData.markDirty(); | |
| 2219 | + } | |
| 2220 | + } | |
| 2221 | + | |
| 2222 | + public void fillArc(int x, int y, int w, int h, | |
| 2223 | + int startAngl, int arcAngl) { | |
| 2224 | + try { | |
| 2225 | + fillpipe.fillArc(this, x, y, w, h, startAngl, arcAngl); | |
| 2226 | + } catch (InvalidPipeException e) { | |
| 2227 | + revalidateAll(); | |
| 2228 | + try { | |
| 2229 | + fillpipe.fillArc(this, x, y, w, h, startAngl, arcAngl); | |
| 2230 | + } catch (InvalidPipeException e2) { | |
| 2231 | + // Still catching the exception; we are not yet ready to | |
| 2232 | + // validate the surfaceData correctly. Fail for now and | |
| 2233 | + // try again next time around. | |
| 2234 | + } | |
| 2235 | + } finally { | |
| 2236 | + surfaceData.markDirty(); | |
| 2237 | + } | |
| 2238 | + } | |
| 2239 | + | |
| 2240 | + public void drawPolyline(int xPoints[], int yPoints[], int nPoints) { | |
| 2241 | + try { | |
| 2242 | + drawpipe.drawPolyline(this, xPoints, yPoints, nPoints); | |
| 2243 | + } catch (InvalidPipeException e) { | |
| 2244 | + revalidateAll(); | |
| 2245 | + try { | |
| 2246 | + drawpipe.drawPolyline(this, xPoints, yPoints, nPoints); | |
| 2247 | + } catch (InvalidPipeException e2) { | |
| 2248 | + // Still catching the exception; we are not yet ready to | |
| 2249 | + // validate the surfaceData correctly. Fail for now and | |
| 2250 | + // try again next time around. | |
| 2251 | + } | |
| 2252 | + } finally { | |
| 2253 | + surfaceData.markDirty(); | |
| 2254 | + } | |
| 2255 | + } | |
| 2256 | + | |
| 2257 | + public void drawPolygon(int xPoints[], int yPoints[], int nPoints) { | |
| 2258 | + try { | |
| 2259 | + drawpipe.drawPolygon(this, xPoints, yPoints, nPoints); | |
| 2260 | + } catch (InvalidPipeException e) { | |
| 2261 | + revalidateAll(); | |
| 2262 | + try { | |
| 2263 | + drawpipe.drawPolygon(this, xPoints, yPoints, nPoints); | |
| 2264 | + } catch (InvalidPipeException e2) { | |
| 2265 | + // Still catching the exception; we are not yet ready to | |
| 2266 | + // validate the surfaceData correctly. Fail for now and | |
| 2267 | + // try again next time around. | |
| 2268 | + } | |
| 2269 | + } finally { | |
| 2270 | + surfaceData.markDirty(); | |
| 2271 | + } | |
| 2272 | + } | |
| 2273 | + | |
| 2274 | + public void fillPolygon(int xPoints[], int yPoints[], int nPoints) { | |
| 2275 | + try { | |
| 2276 | + fillpipe.fillPolygon(this, xPoints, yPoints, nPoints); | |
| 2277 | + } catch (InvalidPipeException e) { | |
| 2278 | + revalidateAll(); | |
| 2279 | + try { | |
| 2280 | + fillpipe.fillPolygon(this, xPoints, yPoints, nPoints); | |
| 2281 | + } catch (InvalidPipeException e2) { | |
| 2282 | + // Still catching the exception; we are not yet ready to | |
| 2283 | + // validate the surfaceData correctly. Fail for now and | |
| 2284 | + // try again next time around. | |
| 2285 | + } | |
| 2286 | + } finally { | |
| 2287 | + surfaceData.markDirty(); | |
| 2288 | + } | |
| 2289 | + } | |
| 2290 | + | |
| 2291 | + public void drawRect (int x, int y, int w, int h) { | |
| 2292 | + try { | |
| 2293 | + drawpipe.drawRect(this, x, y, w, h); | |
| 2294 | + } catch (InvalidPipeException e) { | |
| 2295 | + revalidateAll(); | |
| 2296 | + try { | |
| 2297 | + drawpipe.drawRect(this, x, y, w, h); | |
| 2298 | + } catch (InvalidPipeException e2) { | |
| 2299 | + // Still catching the exception; we are not yet ready to | |
| 2300 | + // validate the surfaceData correctly. Fail for now and | |
| 2301 | + // try again next time around. | |
| 2302 | + } | |
| 2303 | + } finally { | |
| 2304 | + surfaceData.markDirty(); | |
| 2305 | + } | |
| 2306 | + } | |
| 2307 | + | |
| 2308 | + public void fillRect (int x, int y, int w, int h) { | |
| 2309 | + try { | |
| 2310 | + fillpipe.fillRect(this, x, y, w, h); | |
| 2311 | + } catch (InvalidPipeException e) { | |
| 2312 | + revalidateAll(); | |
| 2313 | + try { | |
| 2314 | + fillpipe.fillRect(this, x, y, w, h); | |
| 2315 | + } catch (InvalidPipeException e2) { | |
| 2316 | + // Still catching the exception; we are not yet ready to | |
| 2317 | + // validate the surfaceData correctly. Fail for now and | |
| 2318 | + // try again next time around. | |
| 2319 | + } | |
| 2320 | + } finally { | |
| 2321 | + surfaceData.markDirty(); | |
| 2322 | + } | |
| 2323 | + } | |
| 2324 | + | |
| 2325 | + private void revalidateAll() { | |
| 2326 | + try { | |
| 2327 | + // REMIND: This locking needs to be done around the | |
| 2328 | + // caller of this method so that the pipe stays valid | |
| 2329 | + // long enough to call the new primitive. | |
| 2330 | + // REMIND: No locking yet in screen SurfaceData objects! | |
| 2331 | + // surfaceData.lock(); | |
| 2332 | + surfaceData = surfaceData.getReplacement(); | |
| 2333 | + if (surfaceData == null) { | |
| 2334 | + surfaceData = NullSurfaceData.theInstance; | |
| 2335 | + } | |
| 2336 | + | |
| 2337 | + // this will recalculate the composite clip | |
| 2338 | + setDevClip(surfaceData.getBounds()); | |
| 2339 | + | |
| 2340 | + if (paintState <= PAINT_ALPHACOLOR) { | |
| 2341 | + validateColor(); | |
| 2342 | + } | |
| 2343 | + if (composite instanceof XORComposite) { | |
| 2344 | + Color c = ((XORComposite) composite).getXorColor(); | |
| 2345 | + setComposite(new XORComposite(c, surfaceData)); | |
| 2346 | + } | |
| 2347 | + validatePipe(); | |
| 2348 | + } finally { | |
| 2349 | + // REMIND: No locking yet in screen SurfaceData objects! | |
| 2350 | + // surfaceData.unlock(); | |
| 2351 | + } | |
| 2352 | + } | |
| 2353 | + | |
| 2354 | + public void clearRect(int x, int y, int w, int h) { | |
| 2355 | + // REMIND: has some "interesting" consequences if threads are | |
| 2356 | + // not synchronized | |
| 2357 | + Composite c = composite; | |
| 2358 | + Paint p = paint; | |
| 2359 | + setComposite(AlphaComposite.Src); | |
| 2360 | + setColor(getBackground()); | |
| 2361 | + validatePipe(); | |
| 2362 | + fillRect(x, y, w, h); | |
| 2363 | + setPaint(p); | |
| 2364 | + setComposite(c); | |
| 2365 | + } | |
| 2366 | + | |
| 2367 | + /** | |
| 2368 | + * Strokes the outline of a Path using the settings of the current | |
| 2369 | + * graphics state. The rendering attributes applied include the | |
| 2370 | + * clip, transform, paint or color, composite and stroke attributes. | |
| 2371 | + * @param p The path to be drawn. | |
| 2372 | + * @see #setStroke | |
| 2373 | + * @see #setPaint | |
| 2374 | + * @see java.awt.Graphics#setColor | |
| 2375 | + * @see #transform | |
| 2376 | + * @see #setTransform | |
| 2377 | + * @see #clip | |
| 2378 | + * @see #setClip | |
| 2379 | + * @see #setComposite | |
| 2380 | + */ | |
| 2381 | + public void draw(Shape s) { | |
| 2382 | + try { | |
| 2383 | + shapepipe.draw(this, s); | |
| 2384 | + } catch (InvalidPipeException e) { | |
| 2385 | + revalidateAll(); | |
| 2386 | + try { | |
| 2387 | + shapepipe.draw(this, s); | |
| 2388 | + } catch (InvalidPipeException e2) { | |
| 2389 | + // Still catching the exception; we are not yet ready to | |
| 2390 | + // validate the surfaceData correctly. Fail for now and | |
| 2391 | + // try again next time around. | |
| 2392 | + } | |
| 2393 | + } finally { | |
| 2394 | + surfaceData.markDirty(); | |
| 2395 | + } | |
| 2396 | + } | |
| 2397 | + | |
| 2398 | + | |
| 2399 | + /** | |
| 2400 | + * Fills the interior of a Path using the settings of the current | |
| 2401 | + * graphics state. The rendering attributes applied include the | |
| 2402 | + * clip, transform, paint or color, and composite. | |
| 2403 | + * @see #setPaint | |
| 2404 | + * @see java.awt.Graphics#setColor | |
| 2405 | + * @see #transform | |
| 2406 | + * @see #setTransform | |
| 2407 | + * @see #setComposite | |
| 2408 | + * @see #clip | |
| 2409 | + * @see #setClip | |
| 2410 | + */ | |
| 2411 | + public void fill(Shape s) { | |
| 2412 | + try { | |
| 2413 | + shapepipe.fill(this, s); | |
| 2414 | + } catch (InvalidPipeException e) { | |
| 2415 | + revalidateAll(); | |
| 2416 | + try { | |
| 2417 | + shapepipe.fill(this, s); | |
| 2418 | + } catch (InvalidPipeException e2) { | |
| 2419 | + // Still catching the exception; we are not yet ready to | |
| 2420 | + // validate the surfaceData correctly. Fail for now and | |
| 2421 | + // try again next time around. | |
| 2422 | + } | |
| 2423 | + } finally { | |
| 2424 | + surfaceData.markDirty(); | |
| 2425 | + } | |
| 2426 | + } | |
| 2427 | + | |
| 2428 | + /** | |
| 2429 | + * Returns true if the given AffineTransform is an integer | |
| 2430 | + * translation. | |
| 2431 | + */ | |
| 2432 | + private static boolean isIntegerTranslation(AffineTransform xform) { | |
| 2433 | + if (xform.isIdentity()) { | |
| 2434 | + return true; | |
| 2435 | + } | |
| 2436 | + if (xform.getType() == AffineTransform.TYPE_TRANSLATION) { | |
| 2437 | + double tx = xform.getTranslateX(); | |
| 2438 | + double ty = xform.getTranslateY(); | |
| 2439 | + return (tx == (int)tx && ty == (int)ty); | |
| 2440 | + } | |
| 2441 | + return false; | |
| 2442 | + } | |
| 2443 | + | |
| 2444 | + /** | |
| 2445 | + * Returns the index of the tile corresponding to the supplied position | |
| 2446 | + * given the tile grid offset and size along the same axis. | |
| 2447 | + */ | |
| 2448 | + private static int getTileIndex(int p, int tileGridOffset, int tileSize) { | |
| 2449 | + p -= tileGridOffset; | |
| 2450 | + if (p < 0) { | |
| 2451 | + p += 1 - tileSize; // force round to -infinity (ceiling) | |
| 2452 | + } | |
| 2453 | + return p/tileSize; | |
| 2454 | + } | |
| 2455 | + | |
| 2456 | + /** | |
| 2457 | + * Returns a rectangle in image coordinates that may be required | |
| 2458 | + * in order to draw the given image into the given clipping region | |
| 2459 | + * through a pair of AffineTransforms. In addition, horizontal and | |
| 2460 | + * vertical padding factors for antialising and interpolation may | |
| 2461 | + * be used. | |
| 2462 | + */ | |
| 2463 | + private static Rectangle getImageRegion(RenderedImage img, | |
| 2464 | + Region compClip, | |
| 2465 | + AffineTransform transform, | |
| 2466 | + AffineTransform xform, | |
| 2467 | + int padX, int padY) { | |
| 2468 | + Rectangle imageRect = | |
| 2469 | + new Rectangle(img.getMinX(), img.getMinY(), | |
| 2470 | + img.getWidth(), img.getHeight()); | |
| 2471 | + | |
| 2472 | + Rectangle result = null; | |
| 2473 | + try { | |
| 2474 | + double p[] = new double[8]; | |
| 2475 | + p[0] = p[2] = compClip.getLoX(); | |
| 2476 | + p[4] = p[6] = compClip.getHiX(); | |
| 2477 | + p[1] = p[5] = compClip.getLoY(); | |
| 2478 | + p[3] = p[7] = compClip.getHiY(); | |
| 2479 | + | |
| 2480 | + // Inverse transform the output bounding rect | |
| 2481 | + transform.inverseTransform(p, 0, p, 0, 4); | |
| 2482 | + xform.inverseTransform(p, 0, p, 0, 4); | |
| 2483 | + | |
| 2484 | + // Determine a bounding box for the inverse transformed region | |
| 2485 | + double x0,x1,y0,y1; | |
| 2486 | + x0 = x1 = p[0]; | |
| 2487 | + y0 = y1 = p[1]; | |
| 2488 | + | |
| 2489 | + for (int i = 2; i < 8; ) { | |
| 2490 | + double pt = p[i++]; | |
| 2491 | + if (pt < x0) { | |
| 2492 | + x0 = pt; | |
| 2493 | + } else if (pt > x1) { | |
| 2494 | + x1 = pt; | |
| 2495 | + } | |
| 2496 | + pt = p[i++]; | |
| 2497 | + if (pt < y0) { | |
| 2498 | + y0 = pt; | |
| 2499 | + } else if (pt > y1) { | |
| 2500 | + y1 = pt; | |
| 2501 | + } | |
| 2502 | + } | |
| 2503 | + | |
| 2504 | + // This is padding for anti-aliasing and such. It may | |
| 2505 | + // be more than is needed. | |
| 2506 | + int x = (int)x0 - padX; | |
| 2507 | + int w = (int)(x1 - x0 + 2*padX); | |
| 2508 | + int y = (int)y0 - padY; | |
| 2509 | + int h = (int)(y1 - y0 + 2*padY); | |
| 2510 | + | |
| 2511 | + Rectangle clipRect = new Rectangle(x,y,w,h); | |
| 2512 | + result = clipRect.intersection(imageRect); | |
| 2513 | + } catch (NoninvertibleTransformException nte) { | |
| 2514 | + // Worst case bounds are the bounds of the image. | |
| 2515 | + result = imageRect; | |
| 2516 | + } | |
| 2517 | + | |
| 2518 | + return result; | |
| 2519 | + } | |
| 2520 | + | |
| 2521 | + /** | |
| 2522 | + * Draws an image, applying a transform from image space into user space | |
| 2523 | + * before drawing. | |
| 2524 | + * The transformation from user space into device space is done with | |
| 2525 | + * the current transform in the Graphics2D. | |
| 2526 | + * The given transformation is applied to the image before the | |
| 2527 | + * transform attribute in the Graphics2D state is applied. | |
| 2528 | + * The rendering attributes applied include the clip, transform, | |
| 2529 | + * and composite attributes. Note that the result is | |
| 2530 | + * undefined, if the given transform is noninvertible. | |
| 2531 | + * @param img The image to be drawn. Does nothing if img is null. | |
| 2532 | + * @param xform The transformation from image space into user space. | |
| 2533 | + * @see #transform | |
| 2534 | + * @see #setTransform | |
| 2535 | + * @see #setComposite | |
| 2536 | + * @see #clip | |
| 2537 | + * @see #setClip | |
| 2538 | + */ | |
| 2539 | + public void drawRenderedImage(RenderedImage img, | |
| 2540 | + AffineTransform xform) { | |
| 2541 | + | |
| 2542 | + if (img == null) { | |
| 2543 | + return; | |
| 2544 | + } | |
| 2545 | + | |
| 2546 | + // BufferedImage case: use a simple drawImage call | |
| 2547 | + if (img instanceof BufferedImage) { | |
| 2548 | + BufferedImage bufImg = (BufferedImage)img; | |
| 2549 | + drawImage(bufImg,xform,null); | |
| 2550 | + return; | |
| 2551 | + } | |
| 2552 | + | |
| 2553 | + // transformState tracks the state of transform and | |
| 2554 | + // transX, transY contain the integer casts of the | |
| 2555 | + // translation factors | |
| 2556 | + boolean isIntegerTranslate = | |
| 2557 | + (transformState <= TRANSFORM_INT_TRANSLATE) && | |
| 2558 | + isIntegerTranslation(xform); | |
| 2559 | + | |
| 2560 | + // Include padding for interpolation/antialiasing if necessary | |
| 2561 | + int pad = isIntegerTranslate ? 0 : 3; | |
| 2562 | + | |
| 2563 | + // Determine the region of the image that may contribute to | |
| 2564 | + // the clipped drawing area | |
| 2565 | + Rectangle region = getImageRegion(img, | |
| 2566 | + getCompClip(), | |
| 2567 | + transform, | |
| 2568 | + xform, | |
| 2569 | + pad, pad); | |
| 2570 | + if (region.width <= 0 || region.height <= 0) { | |
| 2571 | + return; | |
| 2572 | + } | |
| 2573 | + | |
| 2574 | + // Attempt to optimize integer translation of tiled images. | |
| 2575 | + // Although theoretically we are O.K. if the concatenation of | |
| 2576 | + // the user transform and the device transform is an integer | |
| 2577 | + // translation, we'll play it safe and only optimize the case | |
| 2578 | + // where both are integer translations. | |
| 2579 | + if (isIntegerTranslate) { | |
| 2580 | + // Use optimized code | |
| 2581 | + // Note that drawTranslatedRenderedImage calls copyImage | |
| 2582 | + // which takes the user space to device space transform into | |
| 2583 | + // account, but we need to provide the image space to user space | |
| 2584 | + // translations. | |
| 2585 | + | |
| 2586 | + drawTranslatedRenderedImage(img, region, | |
| 2587 | + (int) xform.getTranslateX(), | |
| 2588 | + (int) xform.getTranslateY()); | |
| 2589 | + return; | |
| 2590 | + } | |
| 2591 | + | |
| 2592 | + // General case: cobble the necessary region into a single Raster | |
| 2593 | + Raster raster = img.getData(region); | |
| 2594 | + | |
| 2595 | + // Make a new Raster with the same contents as raster | |
| 2596 | + // but starting at (0, 0). This raster is thus in the same | |
| 2597 | + // coordinate system as the SampleModel of the original raster. | |
| 2598 | + WritableRaster wRaster = | |
| 2599 | + Raster.createWritableRaster(raster.getSampleModel(), | |
| 2600 | + raster.getDataBuffer(), | |
| 2601 | + null); | |
| 2602 | + | |
| 2603 | + // If the original raster was in a different coordinate | |
| 2604 | + // system than its SampleModel, we need to perform an | |
| 2605 | + // additional translation in order to get the (minX, minY) | |
| 2606 | + // pixel of raster to be pixel (0, 0) of wRaster. We also | |
| 2607 | + // have to have the correct width and height. | |
| 2608 | + int minX = raster.getMinX(); | |
| 2609 | + int minY = raster.getMinY(); | |
| 2610 | + int width = raster.getWidth(); | |
| 2611 | + int height = raster.getHeight(); | |
| 2612 | + int px = minX - raster.getSampleModelTranslateX(); | |
| 2613 | + int py = minY - raster.getSampleModelTranslateY(); | |
| 2614 | + if (px != 0 || py != 0 || width != wRaster.getWidth() || | |
| 2615 | + height != wRaster.getHeight()) { | |
| 2616 | + wRaster = | |
| 2617 | + wRaster.createWritableChild(px, | |
| 2618 | + py, | |
| 2619 | + width, | |
| 2620 | + height, | |
| 2621 | + 0, 0, | |
| 2622 | + null); | |
| 2623 | + } | |
| 2624 | + | |
| 2625 | + // Now we have a BufferedImage starting at (0, 0) | |
| 2626 | + // with the same contents that started at (minX, minY) | |
| 2627 | + // in raster. So we must draw the BufferedImage with a | |
| 2628 | + // translation of (minX, minY). | |
| 2629 | + AffineTransform transXform = (AffineTransform)xform.clone(); | |
| 2630 | + transXform.translate(minX, minY); | |
| 2631 | + | |
| 2632 | + ColorModel cm = img.getColorModel(); | |
| 2633 | + BufferedImage bufImg = new BufferedImage(cm, | |
| 2634 | + wRaster, | |
| 2635 | + cm.isAlphaPremultiplied(), | |
| 2636 | + null); | |
| 2637 | + drawImage(bufImg, transXform, null); | |
| 2638 | + } | |
| 2639 | + | |
| 2640 | + /** | |
| 2641 | + * Intersects <code>destRect</code> with <code>clip</code> and | |
| 2642 | + * overwrites <code>destRect</code> with the result. | |
| 2643 | + * Returns false if the intersection was empty, true otherwise. | |
| 2644 | + */ | |
| 2645 | + private boolean clipTo(Rectangle destRect, Rectangle clip) { | |
| 2646 | + int x1 = Math.max(destRect.x, clip.x); | |
| 2647 | + int x2 = Math.min(destRect.x + destRect.width, clip.x + clip.width); | |
| 2648 | + int y1 = Math.max(destRect.y, clip.y); | |
| 2649 | + int y2 = Math.min(destRect.y + destRect.height, clip.y + clip.height); | |
| 2650 | + if (((x2 - x1) < 0) || ((y2 - y1) < 0)) { | |
| 2651 | + destRect.width = -1; // Set both just to be safe | |
| 2652 | + destRect.height = -1; | |
| 2653 | + return false; | |
| 2654 | + } else { | |
| 2655 | + destRect.x = x1; | |
| 2656 | + destRect.y = y1; | |
| 2657 | + destRect.width = x2 - x1; | |
| 2658 | + destRect.height = y2 - y1; | |
| 2659 | + return true; | |
| 2660 | + } | |
| 2661 | + } | |
| 2662 | + | |
| 2663 | + /** | |
| 2664 | + * Draw a portion of a RenderedImage tile-by-tile with a given | |
| 2665 | + * integer image to user space translation. The user to | |
| 2666 | + * device transform must also be an integer translation. | |
| 2667 | + */ | |
| 2668 | + private void drawTranslatedRenderedImage(RenderedImage img, | |
| 2669 | + Rectangle region, | |
| 2670 | + int i2uTransX, | |
| 2671 | + int i2uTransY) { | |
| 2672 | + // Cache tile grid info | |
| 2673 | + int tileGridXOffset = img.getTileGridXOffset(); | |
| 2674 | + int tileGridYOffset = img.getTileGridYOffset(); | |
| 2675 | + int tileWidth = img.getTileWidth(); | |
| 2676 | + int tileHeight = img.getTileHeight(); | |
| 2677 | + | |
| 2678 | + // Determine the tile index extrema in each direction | |
| 2679 | + int minTileX = | |
| 2680 | + getTileIndex(region.x, tileGridXOffset, tileWidth); | |
| 2681 | + int minTileY = | |
| 2682 | + getTileIndex(region.y, tileGridYOffset, tileHeight); | |
| 2683 | + int maxTileX = | |
| 2684 | + getTileIndex(region.x + region.width - 1, | |
| 2685 | + tileGridXOffset, tileWidth); | |
| 2686 | + int maxTileY = | |
| 2687 | + getTileIndex(region.y + region.height - 1, | |
| 2688 | + tileGridYOffset, tileHeight); | |
| 2689 | + | |
| 2690 | + // Create a single ColorModel to use for all BufferedImages | |
| 2691 | + ColorModel colorModel = img.getColorModel(); | |
| 2692 | + | |
| 2693 | + // Reuse the same Rectangle for each iteration | |
| 2694 | + Rectangle tileRect = new Rectangle(); | |
| 2695 | + | |
| 2696 | + for (int ty = minTileY; ty <= maxTileY; ty++) { | |
| 2697 | + for (int tx = minTileX; tx <= maxTileX; tx++) { | |
| 2698 | + // Get the current tile. | |
| 2699 | + Raster raster = img.getTile(tx, ty); | |
| 2700 | + | |
| 2701 | + // Fill in tileRect with the tile bounds | |
| 2702 | + tileRect.x = tx*tileWidth + tileGridXOffset; | |
| 2703 | + tileRect.y = ty*tileHeight + tileGridYOffset; | |
| 2704 | + tileRect.width = tileWidth; | |
| 2705 | + tileRect.height = tileHeight; | |
| 2706 | + | |
| 2707 | + // Clip the tile against the image bounds and | |
| 2708 | + // backwards mapped clip region | |
| 2709 | + // The result can't be empty | |
| 2710 | + clipTo(tileRect, region); | |
| 2711 | + | |
| 2712 | + // Create a WritableRaster containing the tile | |
| 2713 | + WritableRaster wRaster = null; | |
| 2714 | + if (raster instanceof WritableRaster) { | |
| 2715 | + wRaster = (WritableRaster)raster; | |
| 2716 | + } else { | |
| 2717 | + // Create a WritableRaster in the same coordinate system | |
| 2718 | + // as the original raster. | |
| 2719 | + wRaster = | |
| 2720 | + Raster.createWritableRaster(raster.getSampleModel(), | |
| 2721 | + raster.getDataBuffer(), | |
| 2722 | + null); | |
| 2723 | + } | |
| 2724 | + | |
| 2725 | + // Translate wRaster to start at (0, 0) and to contain | |
| 2726 | + // only the relevent portion of the tile | |
| 2727 | + wRaster = wRaster.createWritableChild(tileRect.x, tileRect.y, | |
| 2728 | + tileRect.width, | |
| 2729 | + tileRect.height, | |
| 2730 | + 0, 0, | |
| 2731 | + null); | |
| 2732 | + | |
| 2733 | + // Wrap wRaster in a BufferedImage | |
| 2734 | + BufferedImage bufImg = | |
| 2735 | + new BufferedImage(colorModel, | |
| 2736 | + wRaster, | |
| 2737 | + colorModel.isAlphaPremultiplied(), | |
| 2738 | + null); | |
| 2739 | + // Now we have a BufferedImage starting at (0, 0) that | |
| 2740 | + // represents data from a Raster starting at | |
| 2741 | + // (tileRect.x, tileRect.y). Additionally, it needs | |
| 2742 | + // to be translated by (i2uTransX, i2uTransY). We call | |
| 2743 | + // copyImage to draw just the region of interest | |
| 2744 | + // without needing to create a child image. | |
| 2745 | + copyImage(bufImg, tileRect.x + i2uTransX, | |
| 2746 | + tileRect.y + i2uTransY, 0, 0, tileRect.width, | |
| 2747 | + tileRect.height, null, null); | |
| 2748 | + } | |
| 2749 | + } | |
| 2750 | + } | |
| 2751 | + | |
| 2752 | + public void drawRenderableImage(RenderableImage img, | |
| 2753 | + AffineTransform xform) { | |
| 2754 | + | |
| 2755 | + if (img == null) { | |
| 2756 | + return; | |
| 2757 | + } | |
| 2758 | + | |
| 2759 | + AffineTransform pipeTransform = transform; | |
| 2760 | + AffineTransform concatTransform = new AffineTransform(xform); | |
| 2761 | + concatTransform.concatenate(pipeTransform); | |
| 2762 | + AffineTransform reverseTransform; | |
| 2763 | + | |
| 2764 | + RenderContext rc = new RenderContext(concatTransform); | |
| 2765 | + | |
| 2766 | + try { | |
| 2767 | + reverseTransform = pipeTransform.createInverse(); | |
| 2768 | + } catch (NoninvertibleTransformException nte) { | |
| 2769 | + rc = new RenderContext(pipeTransform); | |
| 2770 | + reverseTransform = new AffineTransform(); | |
| 2771 | + } | |
| 2772 | + | |
| 2773 | + RenderedImage rendering = img.createRendering(rc); | |
| 2774 | + drawRenderedImage(rendering,reverseTransform); | |
| 2775 | + } | |
| 2776 | + | |
| 2777 | + | |
| 2778 | + | |
| 2779 | + /* | |
| 2780 | + * Transform the bounding box of the BufferedImage | |
| 2781 | + */ | |
| 2782 | + protected Rectangle transformBounds(Rectangle rect, | |
| 2783 | + AffineTransform tx) { | |
| 2784 | + if (tx.isIdentity()) { | |
| 2785 | + return rect; | |
| 2786 | + } | |
| 2787 | + | |
| 2788 | + Shape s = transformShape(tx, rect); | |
| 2789 | + return s.getBounds(); | |
| 2790 | + } | |
| 2791 | + | |
| 2792 | + // text rendering methods | |
| 2793 | + public void drawString(String str, int x, int y) { | |
| 2794 | + if (str == null) { | |
| 2795 | + throw new NullPointerException("String is null"); | |
| 2796 | + } | |
| 2797 | + | |
| 2798 | + if (font.hasLayoutAttributes()) { | |
| 2799 | + if (str.length() == 0) { | |
| 2800 | + return; | |
| 2801 | + } | |
| 2802 | + new TextLayout(str, font, getFontRenderContext()).draw(this, x, y); | |
| 2803 | + return; | |
| 2804 | + } | |
| 2805 | + | |
| 2806 | + try { | |
| 2807 | + textpipe.drawString(this, str, x, y); | |
| 2808 | + } catch (InvalidPipeException e) { | |
| 2809 | + revalidateAll(); | |
| 2810 | + try { | |
| 2811 | + textpipe.drawString(this, str, x, y); | |
| 2812 | + } catch (InvalidPipeException e2) { | |
| 2813 | + // Still catching the exception; we are not yet ready to | |
| 2814 | + // validate the surfaceData correctly. Fail for now and | |
| 2815 | + // try again next time around. | |
| 2816 | + } | |
| 2817 | + } finally { | |
| 2818 | + surfaceData.markDirty(); | |
| 2819 | + } | |
| 2820 | + } | |
| 2821 | + | |
| 2822 | + public void drawString(String str, float x, float y) { | |
| 2823 | + if (str == null) { | |
| 2824 | + throw new NullPointerException("String is null"); | |
| 2825 | + } | |
| 2826 | + | |
| 2827 | + if (font.hasLayoutAttributes()) { | |
| 2828 | + if (str.length() == 0) { | |
| 2829 | + return; | |
| 2830 | + } | |
| 2831 | + new TextLayout(str, font, getFontRenderContext()).draw(this, x, y); | |
| 2832 | + return; | |
| 2833 | + } | |
| 2834 | + | |
| 2835 | + try { | |
| 2836 | + textpipe.drawString(this, str, x, y); | |
| 2837 | + } catch (InvalidPipeException e) { | |
| 2838 | + revalidateAll(); | |
| 2839 | + try { | |
| 2840 | + textpipe.drawString(this, str, x, y); | |
| 2841 | + } catch (InvalidPipeException e2) { | |
| 2842 | + // Still catching the exception; we are not yet ready to | |
| 2843 | + // validate the surfaceData correctly. Fail for now and | |
| 2844 | + // try again next time around. | |
| 2845 | + } | |
| 2846 | + } finally { | |
| 2847 | + surfaceData.markDirty(); | |
| 2848 | + } | |
| 2849 | + } | |
| 2850 | + | |
| 2851 | + public void drawString(AttributedCharacterIterator iterator, | |
| 2852 | + int x, int y) { | |
| 2853 | + if (iterator == null) { | |
| 2854 | + throw new NullPointerException("AttributedCharacterIterator is null"); | |
| 2855 | + } | |
| 2856 | + if (iterator.getBeginIndex() == iterator.getEndIndex()) { | |
| 2857 | + return; /* nothing to draw */ | |
| 2858 | + } | |
| 2859 | + TextLayout tl = new TextLayout(iterator, getFontRenderContext()); | |
| 2860 | + tl.draw(this, (float) x, (float) y); | |
| 2861 | + } | |
| 2862 | + | |
| 2863 | + public void drawString(AttributedCharacterIterator iterator, | |
| 2864 | + float x, float y) { | |
| 2865 | + if (iterator == null) { | |
| 2866 | + throw new NullPointerException("AttributedCharacterIterator is null"); | |
| 2867 | + } | |
| 2868 | + if (iterator.getBeginIndex() == iterator.getEndIndex()) { | |
| 2869 | + return; /* nothing to draw */ | |
| 2870 | + } | |
| 2871 | + TextLayout tl = new TextLayout(iterator, getFontRenderContext()); | |
| 2872 | + tl.draw(this, x, y); | |
| 2873 | + } | |
| 2874 | + | |
| 2875 | + public void drawGlyphVector(GlyphVector gv, float x, float y) | |
| 2876 | + { | |
| 2877 | + if (gv == null) { | |
| 2878 | + throw new NullPointerException("GlyphVector is null"); | |
| 2879 | + } | |
| 2880 | + | |
| 2881 | + try { | |
| 2882 | + textpipe.drawGlyphVector(this, gv, x, y); | |
| 2883 | + } catch (InvalidPipeException e) { | |
| 2884 | + revalidateAll(); | |
| 2885 | + try { | |
| 2886 | + textpipe.drawGlyphVector(this, gv, x, y); | |
| 2887 | + } catch (InvalidPipeException e2) { | |
| 2888 | + // Still catching the exception; we are not yet ready to | |
| 2889 | + // validate the surfaceData correctly. Fail for now and | |
| 2890 | + // try again next time around. | |
| 2891 | + } | |
| 2892 | + } finally { | |
| 2893 | + surfaceData.markDirty(); | |
| 2894 | + } | |
| 2895 | + } | |
| 2896 | + | |
| 2897 | + public void drawChars(char data[], int offset, int length, int x, int y) { | |
| 2898 | + | |
| 2899 | + if (data == null) { | |
| 2900 | + throw new NullPointerException("char data is null"); | |
| 2901 | + } | |
| 2902 | + if (offset < 0 || length < 0 || offset + length > data.length) { | |
| 2903 | + throw new ArrayIndexOutOfBoundsException("bad offset/length"); | |
| 2904 | + } | |
| 2905 | + if (font.hasLayoutAttributes()) { | |
| 2906 | + if (data.length == 0) { | |
| 2907 | + return; | |
| 2908 | + } | |
| 2909 | + new TextLayout(new String(data, offset, length), | |
| 2910 | + font, getFontRenderContext()).draw(this, x, y); | |
| 2911 | + return; | |
| 2912 | + } | |
| 2913 | + | |
| 2914 | + try { | |
| 2915 | + textpipe.drawChars(this, data, offset, length, x, y); | |
| 2916 | + } catch (InvalidPipeException e) { | |
| 2917 | + revalidateAll(); | |
| 2918 | + try { | |
| 2919 | + textpipe.drawChars(this, data, offset, length, x, y); | |
| 2920 | + } catch (InvalidPipeException e2) { | |
| 2921 | + // Still catching the exception; we are not yet ready to | |
| 2922 | + // validate the surfaceData correctly. Fail for now and | |
| 2923 | + // try again next time around. | |
| 2924 | + } | |
| 2925 | + } finally { | |
| 2926 | + surfaceData.markDirty(); | |
| 2927 | + } | |
| 2928 | + } | |
| 2929 | + | |
| 2930 | + public void drawBytes(byte data[], int offset, int length, int x, int y) { | |
| 2931 | + if (data == null) { | |
| 2932 | + throw new NullPointerException("byte data is null"); | |
| 2933 | + } | |
| 2934 | + if (offset < 0 || length < 0 || offset + length > data.length) { | |
| 2935 | + throw new ArrayIndexOutOfBoundsException("bad offset/length"); | |
| 2936 | + } | |
| 2937 | + /* Byte data is interpreted as 8-bit ASCII. Re-use drawChars loops */ | |
| 2938 | + char chData[] = new char[length]; | |
| 2939 | + for (int i = length; i-- > 0; ) { | |
| 2940 | + chData[i] = (char)(data[i+offset] & 0xff); | |
| 2941 | + } | |
| 2942 | + if (font.hasLayoutAttributes()) { | |
| 2943 | + if (data.length == 0) { | |
| 2944 | + return; | |
| 2945 | + } | |
| 2946 | + new TextLayout(new String(chData), | |
| 2947 | + font, getFontRenderContext()).draw(this, x, y); | |
| 2948 | + return; | |
| 2949 | + } | |
| 2950 | + | |
| 2951 | + try { | |
| 2952 | + textpipe.drawChars(this, chData, 0, length, x, y); | |
| 2953 | + } catch (InvalidPipeException e) { | |
| 2954 | + revalidateAll(); | |
| 2955 | + try { | |
| 2956 | + textpipe.drawChars(this, chData, 0, length, x, y); | |
| 2957 | + } catch (InvalidPipeException e2) { | |
| 2958 | + // Still catching the exception; we are not yet ready to | |
| 2959 | + // validate the surfaceData correctly. Fail for now and | |
| 2960 | + // try again next time around. | |
| 2961 | + } | |
| 2962 | + } finally { | |
| 2963 | + surfaceData.markDirty(); | |
| 2964 | + } | |
| 2965 | + } | |
| 2966 | +// end of text rendering methods | |
| 2967 | + | |
| 2968 | + /** | |
| 2969 | + * Draws an image scaled to x,y,w,h in nonblocking mode with a | |
| 2970 | + * callback object. | |
| 2971 | + */ | |
| 2972 | + public boolean drawImage(Image img, int x, int y, int width, int height, | |
| 2973 | + ImageObserver observer) { | |
| 2974 | + return drawImage(img, x, y, width, height, null, observer); | |
| 2975 | + } | |
| 2976 | + | |
| 2977 | + /** | |
| 2978 | + * Not part of the advertised API but a useful utility method | |
| 2979 | + * to call internally. This is for the case where we are | |
| 2980 | + * drawing to/from given coordinates using a given width/height, | |
| 2981 | + * but we guarantee that the weidth/height of the src and dest | |
| 2982 | + * areas are equal (no scale needed). | |
| 2983 | + */ | |
| 2984 | + public boolean copyImage(Image img, int dx, int dy, int sx, int sy, | |
| 2985 | + int width, int height, Color bgcolor, | |
| 2986 | + ImageObserver observer) { | |
| 2987 | + try { | |
| 2988 | + return imagepipe.copyImage(this, img, dx, dy, sx, sy, | |
| 2989 | + width, height, bgcolor, observer); | |
| 2990 | + } catch (InvalidPipeException e) { | |
| 2991 | + revalidateAll(); | |
| 2992 | + try { | |
| 2993 | + return imagepipe.copyImage(this, img, dx, dy, sx, sy, | |
| 2994 | + width, height, bgcolor, observer); | |
| 2995 | + } catch (InvalidPipeException e2) { | |
| 2996 | + // Still catching the exception; we are not yet ready to | |
| 2997 | + // validate the surfaceData correctly. Fail for now and | |
| 2998 | + // try again next time around. | |
| 2999 | + return false; | |
| 3000 | + } | |
| 3001 | + } finally { | |
| 3002 | + surfaceData.markDirty(); | |
| 3003 | + } | |
| 3004 | + } | |
| 3005 | + | |
| 3006 | + /** | |
| 3007 | + * Draws an image scaled to x,y,w,h in nonblocking mode with a | |
| 3008 | + * solid background color and a callback object. | |
| 3009 | + */ | |
| 3010 | + public boolean drawImage(Image img, int x, int y, int width, int height, | |
| 3011 | + Color bg, ImageObserver observer) { | |
| 3012 | + | |
| 3013 | + if (img == null) { | |
| 3014 | + return true; | |
| 3015 | + } | |
| 3016 | + | |
| 3017 | + if ((width == 0) || (height == 0)) { | |
| 3018 | + return true; | |
| 3019 | + } | |
| 3020 | + if (width == img.getWidth(null) && height == img.getHeight(null)) { | |
| 3021 | + return copyImage(img, x, y, 0, 0, width, height, bg, observer); | |
| 3022 | + } | |
| 3023 | + | |
| 3024 | + try { | |
| 3025 | + return imagepipe.scaleImage(this, img, x, y, width, height, | |
| 3026 | + bg, observer); | |
| 3027 | + } catch (InvalidPipeException e) { | |
| 3028 | + revalidateAll(); | |
| 3029 | + try { | |
| 3030 | + return imagepipe.scaleImage(this, img, x, y, width, height, | |
| 3031 | + bg, observer); | |
| 3032 | + } catch (InvalidPipeException e2) { | |
| 3033 | + // Still catching the exception; we are not yet ready to | |
| 3034 | + // validate the surfaceData correctly. Fail for now and | |
| 3035 | + // try again next time around. | |
| 3036 | + return false; | |
| 3037 | + } | |
| 3038 | + } finally { | |
| 3039 | + surfaceData.markDirty(); | |
| 3040 | + } | |
| 3041 | + } | |
| 3042 | + | |
| 3043 | + /** | |
| 3044 | + * Draws an image at x,y in nonblocking mode. | |
| 3045 | + */ | |
| 3046 | + public boolean drawImage(Image img, int x, int y, ImageObserver observer) { | |
| 3047 | + return drawImage(img, x, y, null, observer); | |
| 3048 | + } | |
| 3049 | + | |
| 3050 | + /** | |
| 3051 | + * Draws an image at x,y in nonblocking mode with a solid background | |
| 3052 | + * color and a callback object. | |
| 3053 | + */ | |
| 3054 | + public boolean drawImage(Image img, int x, int y, Color bg, | |
| 3055 | + ImageObserver observer) { | |
| 3056 | + | |
| 3057 | + if (img == null) { | |
| 3058 | + return true; | |
| 3059 | + } | |
| 3060 | + | |
| 3061 | + try { | |
| 3062 | + return imagepipe.copyImage(this, img, x, y, bg, observer); | |
| 3063 | + } catch (InvalidPipeException e) { | |
| 3064 | + revalidateAll(); | |
| 3065 | + try { | |
| 3066 | + return imagepipe.copyImage(this, img, x, y, bg, observer); | |
| 3067 | + } catch (InvalidPipeException e2) { | |
| 3068 | + // Still catching the exception; we are not yet ready to | |
| 3069 | + // validate the surfaceData correctly. Fail for now and | |
| 3070 | + // try again next time around. | |
| 3071 | + return false; | |
| 3072 | + } | |
| 3073 | + } finally { | |
| 3074 | + surfaceData.markDirty(); | |
| 3075 | + } | |
| 3076 | + } | |
| 3077 | + | |
| 3078 | + /** | |
| 3079 | + * Draws a subrectangle of an image scaled to a destination rectangle | |
| 3080 | + * in nonblocking mode with a callback object. | |
| 3081 | + */ | |
| 3082 | + public boolean drawImage(Image img, | |
| 3083 | + int dx1, int dy1, int dx2, int dy2, | |
| 3084 | + int sx1, int sy1, int sx2, int sy2, | |
| 3085 | + ImageObserver observer) { | |
| 3086 | + return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, | |
| 3087 | + observer); | |
| 3088 | + } | |
| 3089 | + | |
| 3090 | + /** | |
| 3091 | + * Draws a subrectangle of an image scaled to a destination rectangle in | |
| 3092 | + * nonblocking mode with a solid background color and a callback object. | |
| 3093 | + */ | |
| 3094 | + public boolean drawImage(Image img, | |
| 3095 | + int dx1, int dy1, int dx2, int dy2, | |
| 3096 | + int sx1, int sy1, int sx2, int sy2, | |
| 3097 | + Color bgcolor, ImageObserver observer) { | |
| 3098 | + | |
| 3099 | + if (img == null) { | |
| 3100 | + return true; | |
| 3101 | + } | |
| 3102 | + | |
| 3103 | + if (dx1 == dx2 || dy1 == dy2 || | |
| 3104 | + sx1 == sx2 || sy1 == sy2) | |
| 3105 | + { | |
| 3106 | + return true; | |
| 3107 | + } | |
| 3108 | + | |
| 3109 | + if (((sx2 - sx1) == (dx2 - dx1)) && | |
| 3110 | + ((sy2 - sy1) == (dy2 - dy1))) | |
| 3111 | + { | |
| 3112 | + // Not a scale - forward it to a copy routine | |
| 3113 | + int srcX, srcY, dstX, dstY, width, height; | |
| 3114 | + if (sx2 > sx1) { | |
| 3115 | + width = sx2 - sx1; | |
| 3116 | + srcX = sx1; | |
| 3117 | + dstX = dx1; | |
| 3118 | + } else { | |
| 3119 | + width = sx1 - sx2; | |
| 3120 | + srcX = sx2; | |
| 3121 | + dstX = dx2; | |
| 3122 | + } | |
| 3123 | + if (sy2 > sy1) { | |
| 3124 | + height = sy2-sy1; | |
| 3125 | + srcY = sy1; | |
| 3126 | + dstY = dy1; | |
| 3127 | + } else { | |
| 3128 | + height = sy1-sy2; | |
| 3129 | + srcY = sy2; | |
| 3130 | + dstY = dy2; | |
| 3131 | + } | |
| 3132 | + return copyImage(img, dstX, dstY, srcX, srcY, | |
| 3133 | + width, height, bgcolor, observer); | |
| 3134 | + } | |
| 3135 | + | |
| 3136 | + try { | |
| 3137 | + return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2, | |
| 3138 | + sx1, sy1, sx2, sy2, bgcolor, | |
| 3139 | + observer); | |
| 3140 | + } catch (InvalidPipeException e) { | |
| 3141 | + revalidateAll(); | |
| 3142 | + try { | |
| 3143 | + return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2, | |
| 3144 | + sx1, sy1, sx2, sy2, bgcolor, | |
| 3145 | + observer); | |
| 3146 | + } catch (InvalidPipeException e2) { | |
| 3147 | + // Still catching the exception; we are not yet ready to | |
| 3148 | + // validate the surfaceData correctly. Fail for now and | |
| 3149 | + // try again next time around. | |
| 3150 | + return false; | |
| 3151 | + } | |
| 3152 | + } finally { | |
| 3153 | + surfaceData.markDirty(); | |
| 3154 | + } | |
| 3155 | + } | |
| 3156 | + | |
| 3157 | + /** | |
| 3158 | + * Draw an image, applying a transform from image space into user space | |
| 3159 | + * before drawing. | |
| 3160 | + * The transformation from user space into device space is done with | |
| 3161 | + * the current transform in the Graphics2D. | |
| 3162 | + * The given transformation is applied to the image before the | |
| 3163 | + * transform attribute in the Graphics2D state is applied. | |
| 3164 | + * The rendering attributes applied include the clip, transform, | |
| 3165 | + * paint or color and composite attributes. Note that the result is | |
| 3166 | + * undefined, if the given transform is non-invertible. | |
| 3167 | + * @param img The image to be drawn. | |
| 3168 | + * @param xform The transformation from image space into user space. | |
| 3169 | + * @param observer The image observer to be notified on the image producing | |
| 3170 | + * progress. | |
| 3171 | + * @see #transform | |
| 3172 | + * @see #setComposite | |
| 3173 | + * @see #setClip | |
| 3174 | + */ | |
| 3175 | + public boolean drawImage(Image img, | |
| 3176 | + AffineTransform xform, | |
| 3177 | + ImageObserver observer) { | |
| 3178 | + | |
| 3179 | + if (img == null) { | |
| 3180 | + return true; | |
| 3181 | + } | |
| 3182 | + | |
| 3183 | + if (xform == null || xform.isIdentity()) { | |
| 3184 | + return drawImage(img, 0, 0, null, observer); | |
| 3185 | + } | |
| 3186 | + | |
| 3187 | + try { | |
| 3188 | + return imagepipe.transformImage(this, img, xform, observer); | |
| 3189 | + } catch (InvalidPipeException e) { | |
| 3190 | + revalidateAll(); | |
| 3191 | + try { | |
| 3192 | + return imagepipe.transformImage(this, img, xform, observer); | |
| 3193 | + } catch (InvalidPipeException e2) { | |
| 3194 | + // Still catching the exception; we are not yet ready to | |
| 3195 | + // validate the surfaceData correctly. Fail for now and | |
| 3196 | + // try again next time around. | |
| 3197 | + return false; | |
| 3198 | + } | |
| 3199 | + } finally { | |
| 3200 | + surfaceData.markDirty(); | |
| 3201 | + } | |
| 3202 | + } | |
| 3203 | + | |
| 3204 | + public void drawImage(BufferedImage bImg, | |
| 3205 | + BufferedImageOp op, | |
| 3206 | + int x, | |
| 3207 | + int y) { | |
| 3208 | + | |
| 3209 | + if (bImg == null) { | |
| 3210 | + return; | |
| 3211 | + } | |
| 3212 | + | |
| 3213 | + try { | |
| 3214 | + imagepipe.transformImage(this, bImg, op, x, y); | |
| 3215 | + } catch (InvalidPipeException e) { | |
| 3216 | + revalidateAll(); | |
| 3217 | + try { | |
| 3218 | + imagepipe.transformImage(this, bImg, op, x, y); | |
| 3219 | + } catch (InvalidPipeException e2) { | |
| 3220 | + // Still catching the exception; we are not yet ready to | |
| 3221 | + // validate the surfaceData correctly. Fail for now and | |
| 3222 | + // try again next time around. | |
| 3223 | + } | |
| 3224 | + } finally { | |
| 3225 | + surfaceData.markDirty(); | |
| 3226 | + } | |
| 3227 | + } | |
| 3228 | + | |
| 3229 | + /** | |
| 3230 | + * Get the rendering context of the font | |
| 3231 | + * within this Graphics2D context. | |
| 3232 | + */ | |
| 3233 | + public FontRenderContext getFontRenderContext() { | |
| 3234 | + if (cachedFRC == null) { | |
| 3235 | + int aahint = textAntialiasHint; | |
| 3236 | + if (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT && | |
| 3237 | + antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) { | |
| 3238 | + aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON; | |
| 3239 | + } | |
| 3240 | + // Translation components should be excluded from the FRC transform | |
| 3241 | + AffineTransform tx = null; | |
| 3242 | + if (transformState >= TRANSFORM_TRANSLATESCALE) { | |
| 3243 | + if (transform.getTranslateX() == 0 && | |
| 3244 | + transform.getTranslateY() == 0) { | |
| 3245 | + tx = transform; | |
| 3246 | + } else { | |
| 3247 | + tx = new AffineTransform(transform.getScaleX(), | |
| 3248 | + transform.getShearY(), | |
| 3249 | + transform.getShearX(), | |
| 3250 | + transform.getScaleY(), | |
| 3251 | + 0, 0); | |
| 3252 | + } | |
| 3253 | + } | |
| 3254 | + cachedFRC = new FontRenderContext(tx, | |
| 3255 | + SunHints.Value.get(SunHints.INTKEY_TEXT_ANTIALIASING, aahint), | |
| 3256 | + SunHints.Value.get(SunHints.INTKEY_FRACTIONALMETRICS, | |
| 3257 | + fractionalMetricsHint)); | |
| 3258 | + } | |
| 3259 | + return cachedFRC; | |
| 3260 | + } | |
| 3261 | + private FontRenderContext cachedFRC; | |
| 3262 | + | |
| 3263 | + /** | |
| 3264 | + * This object has no resources to dispose of per se, but the | |
| 3265 | + * doc comments for the base method in java.awt.Graphics imply | |
| 3266 | + * that this object will not be useable after it is disposed. | |
| 3267 | + * So, we sabotage the object to prevent further use to prevent | |
| 3268 | + * developers from relying on behavior that may not work on | |
| 3269 | + * other, less forgiving, VMs that really need to dispose of | |
| 3270 | + * resources. | |
| 3271 | + */ | |
| 3272 | + public void dispose() { | |
| 3273 | + surfaceData = NullSurfaceData.theInstance; | |
| 3274 | + invalidatePipe(); | |
| 3275 | + } | |
| 3276 | + | |
| 3277 | + /** | |
| 3278 | + * Graphics has a finalize method that automatically calls dispose() | |
| 3279 | + * for subclasses. For SunGraphics2D we do not need to be finalized | |
| 3280 | + * so that method simply causes us to be enqueued on the Finalizer | |
| 3281 | + * queues for no good reason. Unfortunately, that method and | |
| 3282 | + * implementation are now considered part of the public contract | |
| 3283 | + * of that base class so we can not remove or gut the method. | |
| 3284 | + * We override it here with an empty method and the VM is smart | |
| 3285 | + * enough to know that if our override is empty then it should not | |
| 3286 | + * mark us as finalizeable. | |
| 3287 | + */ | |
| 3288 | + public void finalize() { | |
| 3289 | + // DO NOT REMOVE THIS METHOD | |
| 3290 | + } | |
| 3291 | + | |
| 3292 | + /** | |
| 3293 | + * Returns destination that this Graphics renders to. This could be | |
| 3294 | + * either an Image or a Component; subclasses of SurfaceData are | |
| 3295 | + * responsible for returning the appropriate object. | |
| 3296 | + */ | |
| 3297 | + public Object getDestination() { | |
| 3298 | + return surfaceData.getDestination(); | |
| 3299 | + } | |
| 3300 | + | |
| 3301 | + /** | |
| 3302 | + * {@inheritDoc} | |
| 3303 | + * | |
| 3304 | + * @see sun.java2d.DestSurfaceProvider#getDestSurface | |
| 3305 | + */ | |
| 3306 | + @Override | |
| 3307 | + public Surface getDestSurface() { | |
| 3308 | + return surfaceData; | |
| 3309 | + } | |
| 3310 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,337 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d; | |
| 27 | + | |
| 28 | +import java.awt.Color; | |
| 29 | +import java.awt.Font; | |
| 30 | +import java.awt.Graphics2D; | |
| 31 | +import java.awt.GraphicsConfiguration; | |
| 32 | +import java.awt.GraphicsDevice; | |
| 33 | +import java.awt.GraphicsEnvironment; | |
| 34 | +import java.awt.Insets; | |
| 35 | +import java.awt.Rectangle; | |
| 36 | +import java.awt.Toolkit; | |
| 37 | +import java.awt.font.TextAttribute; | |
| 38 | +import java.awt.image.BufferedImage; | |
| 39 | +import java.awt.peer.ComponentPeer; | |
| 40 | +import java.io.BufferedReader; | |
| 41 | +import java.io.File; | |
| 42 | +import java.io.FileInputStream; | |
| 43 | +import java.io.FilenameFilter; | |
| 44 | +import java.io.InputStreamReader; | |
| 45 | +import java.io.IOException; | |
| 46 | +import java.text.AttributedCharacterIterator; | |
| 47 | +import java.util.ArrayList; | |
| 48 | +import java.util.HashSet; | |
| 49 | +import java.util.Iterator; | |
| 50 | +import java.util.Locale; | |
| 51 | +import java.util.Map; | |
| 52 | +import java.util.NoSuchElementException; | |
| 53 | +import java.util.Set; | |
| 54 | +import java.util.StringTokenizer; | |
| 55 | +import java.util.TreeMap; | |
| 56 | +import java.util.Vector; | |
| 57 | +import java.util.concurrent.ConcurrentHashMap; | |
| 58 | +import sun.awt.AppContext; | |
| 59 | +import sun.awt.DisplayChangedListener; | |
| 60 | +import sun.awt.FontConfiguration; | |
| 61 | +import sun.awt.SunDisplayChanger; | |
| 62 | +import sun.font.CompositeFontDescriptor; | |
| 63 | +import sun.font.Font2D; | |
| 64 | +import sun.font.FontManager; | |
| 65 | +import sun.font.FontManagerFactory; | |
| 66 | +import sun.font.FontManagerForSGE; | |
| 67 | +import sun.font.NativeFont; | |
| 68 | + | |
| 69 | +/** | |
| 70 | + * This is an implementation of a GraphicsEnvironment object for the | |
| 71 | + * default local GraphicsEnvironment. | |
| 72 | + * | |
| 73 | + * @see GraphicsDevice | |
| 74 | + * @see GraphicsConfiguration | |
| 75 | + */ | |
| 76 | +public abstract class SunGraphicsEnvironment extends GraphicsEnvironment | |
| 77 | + implements DisplayChangedListener { | |
| 78 | + | |
| 79 | + public static boolean isOpenSolaris; | |
| 80 | + private static Font defaultFont; | |
| 81 | + | |
| 82 | + public SunGraphicsEnvironment() { | |
| 83 | + java.security.AccessController.doPrivileged( | |
| 84 | + new java.security.PrivilegedAction() { | |
| 85 | + public Object run() { | |
| 86 | + String version = System.getProperty("os.version", "0.0"); | |
| 87 | + try { | |
| 88 | + float ver = Float.parseFloat(version); | |
| 89 | + if (ver > 5.10f) { | |
| 90 | + File f = new File("/etc/release"); | |
| 91 | + FileInputStream fis = new FileInputStream(f); | |
| 92 | + InputStreamReader isr | |
| 93 | + = new InputStreamReader(fis, "ISO-8859-1"); | |
| 94 | + BufferedReader br = new BufferedReader(isr); | |
| 95 | + String line = br.readLine(); | |
| 96 | + if (line.indexOf("OpenSolaris") >= 0) { | |
| 97 | + isOpenSolaris = true; | |
| 98 | + } else { | |
| 99 | + /* We are using isOpenSolaris as meaning | |
| 100 | + * we know the Solaris commercial fonts aren't | |
| 101 | + * present. "Solaris Next" (03/10) did not | |
| 102 | + * include these even though its was not | |
| 103 | + * OpenSolaris. Need to revisit how this is | |
| 104 | + * handled but for now as in 6ux, we'll use | |
| 105 | + * the test for a standard font resource as | |
| 106 | + * being an indicator as to whether we need | |
| 107 | + * to treat this as OpenSolaris from a font | |
| 108 | + * config perspective. | |
| 109 | + */ | |
| 110 | + String courierNew = | |
| 111 | + "/usr/openwin/lib/X11/fonts/TrueType/CourierNew.ttf"; | |
| 112 | + File courierFile = new File(courierNew); | |
| 113 | + isOpenSolaris = !courierFile.exists(); | |
| 114 | + } | |
| 115 | + fis.close(); | |
| 116 | + } | |
| 117 | + } catch (Exception e) { | |
| 118 | + } | |
| 119 | + | |
| 120 | + /* Establish the default font to be used by SG2D etc */ | |
| 121 | + defaultFont = new Font(Font.DIALOG, Font.PLAIN, 12); | |
| 122 | + | |
| 123 | + return null; | |
| 124 | + } | |
| 125 | + }); | |
| 126 | + } | |
| 127 | + | |
| 128 | + protected GraphicsDevice[] screens; | |
| 129 | + | |
| 130 | + /** | |
| 131 | + * Returns an array of all of the screen devices. | |
| 132 | + */ | |
| 133 | + public synchronized GraphicsDevice[] getScreenDevices() { | |
| 134 | + GraphicsDevice[] ret = screens; | |
| 135 | + if (ret == null) { | |
| 136 | + int num = getNumScreens(); | |
| 137 | + ret = new GraphicsDevice[num]; | |
| 138 | + for (int i = 0; i < num; i++) { | |
| 139 | + ret[i] = makeScreenDevice(i); | |
| 140 | + } | |
| 141 | + screens = ret; | |
| 142 | + } | |
| 143 | + return ret; | |
| 144 | + } | |
| 145 | + | |
| 146 | + /** | |
| 147 | + * Returns the number of screen devices of this graphics environment. | |
| 148 | + * | |
| 149 | + * @return the number of screen devices of this graphics environment | |
| 150 | + */ | |
| 151 | + protected abstract int getNumScreens(); | |
| 152 | + | |
| 153 | + /** | |
| 154 | + * Create and return the screen device with the specified number. The | |
| 155 | + * device with number <code>0</code> will be the default device (returned | |
| 156 | + * by {@link #getDefaultScreenDevice()}. | |
| 157 | + * | |
| 158 | + * @param screennum the number of the screen to create | |
| 159 | + * | |
| 160 | + * @return the created screen device | |
| 161 | + */ | |
| 162 | + protected abstract GraphicsDevice makeScreenDevice(int screennum); | |
| 163 | + | |
| 164 | + /** | |
| 165 | + * Returns the default screen graphics device. | |
| 166 | + */ | |
| 167 | + public GraphicsDevice getDefaultScreenDevice() { | |
| 168 | + return getScreenDevices()[0]; | |
| 169 | + } | |
| 170 | + | |
| 171 | + /** | |
| 172 | + * Returns a Graphics2D object for rendering into the | |
| 173 | + * given BufferedImage. | |
| 174 | + * @throws NullPointerException if BufferedImage argument is null | |
| 175 | + */ | |
| 176 | + public Graphics2D createGraphics(BufferedImage img) { | |
| 177 | + if (img == null) { | |
| 178 | + throw new NullPointerException("BufferedImage cannot be null"); | |
| 179 | + } | |
| 180 | + SurfaceData sd = SurfaceData.getPrimarySurfaceData(img); | |
| 181 | + return new SunGraphics2D(sd, Color.white, Color.black, defaultFont); | |
| 182 | + } | |
| 183 | + | |
| 184 | + public static FontManagerForSGE getFontManagerForSGE() { | |
| 185 | + FontManager fm = FontManagerFactory.getInstance(); | |
| 186 | + return (FontManagerForSGE) fm; | |
| 187 | + } | |
| 188 | + | |
| 189 | + /* Modifies the behaviour of a subsequent call to preferLocaleFonts() | |
| 190 | + * to use Mincho instead of Gothic for dialoginput in JA locales | |
| 191 | + * on windows. Not needed on other platforms. | |
| 192 | + * | |
| 193 | + * DO NOT MOVE OR RENAME OR OTHERWISE ALTER THIS METHOD. | |
| 194 | + * ITS USED BY SOME NON-JRE INTERNAL CODE. | |
| 195 | + */ | |
| 196 | + public static void useAlternateFontforJALocales() { | |
| 197 | + getFontManagerForSGE().useAlternateFontforJALocales(); | |
| 198 | + } | |
| 199 | + | |
| 200 | + /** | |
| 201 | + * Returns all fonts available in this environment. | |
| 202 | + */ | |
| 203 | + public Font[] getAllFonts() { | |
| 204 | + FontManagerForSGE fm = getFontManagerForSGE(); | |
| 205 | + Font[] installedFonts = fm.getAllInstalledFonts(); | |
| 206 | + Font[] created = fm.getCreatedFonts(); | |
| 207 | + if (created == null || created.length == 0) { | |
| 208 | + return installedFonts; | |
| 209 | + } else { | |
| 210 | + int newlen = installedFonts.length + created.length; | |
| 211 | + Font [] fonts = java.util.Arrays.copyOf(installedFonts, newlen); | |
| 212 | + System.arraycopy(created, 0, fonts, | |
| 213 | + installedFonts.length, created.length); | |
| 214 | + return fonts; | |
| 215 | + } | |
| 216 | + } | |
| 217 | + | |
| 218 | + public String[] getAvailableFontFamilyNames(Locale requestedLocale) { | |
| 219 | + FontManagerForSGE fm = getFontManagerForSGE(); | |
| 220 | + String[] installed = fm.getInstalledFontFamilyNames(requestedLocale); | |
| 221 | + /* Use a new TreeMap as used in getInstalledFontFamilyNames | |
| 222 | + * and insert all the keys in lower case, so that the sort order | |
| 223 | + * is the same as the installed families. This preserves historical | |
| 224 | + * behaviour and inserts new families in the right place. | |
| 225 | + * It would have been marginally more efficient to directly obtain | |
| 226 | + * the tree map and just insert new entries, but not so much as | |
| 227 | + * to justify the extra internal interface. | |
| 228 | + */ | |
| 229 | + TreeMap<String, String> map = fm.getCreatedFontFamilyNames(); | |
| 230 | + if (map == null || map.size() == 0) { | |
| 231 | + return installed; | |
| 232 | + } else { | |
| 233 | + for (int i=0; i<installed.length; i++) { | |
| 234 | + map.put(installed[i].toLowerCase(requestedLocale), | |
| 235 | + installed[i]); | |
| 236 | + } | |
| 237 | + String[] retval = new String[map.size()]; | |
| 238 | + Object [] keyNames = map.keySet().toArray(); | |
| 239 | + for (int i=0; i < keyNames.length; i++) { | |
| 240 | + retval[i] = (String)map.get(keyNames[i]); | |
| 241 | + } | |
| 242 | + return retval; | |
| 243 | + } | |
| 244 | + } | |
| 245 | + | |
| 246 | + public String[] getAvailableFontFamilyNames() { | |
| 247 | + return getAvailableFontFamilyNames(Locale.getDefault()); | |
| 248 | + } | |
| 249 | + | |
| 250 | + /** | |
| 251 | + * Return the bounds of a GraphicsDevice, less its screen insets. | |
| 252 | + * See also java.awt.GraphicsEnvironment.getUsableBounds(); | |
| 253 | + */ | |
| 254 | + public static Rectangle getUsableBounds(GraphicsDevice gd) { | |
| 255 | + GraphicsConfiguration gc = gd.getDefaultConfiguration(); | |
| 256 | + Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc); | |
| 257 | + Rectangle usableBounds = gc.getBounds(); | |
| 258 | + | |
| 259 | + usableBounds.x += insets.left; | |
| 260 | + usableBounds.y += insets.top; | |
| 261 | + usableBounds.width -= (insets.left + insets.right); | |
| 262 | + usableBounds.height -= (insets.top + insets.bottom); | |
| 263 | + | |
| 264 | + return usableBounds; | |
| 265 | + } | |
| 266 | + | |
| 267 | + /** | |
| 268 | + * From the DisplayChangedListener interface; called | |
| 269 | + * when the display mode has been changed. | |
| 270 | + */ | |
| 271 | + public void displayChanged() { | |
| 272 | + // notify screens in device array to do display update stuff | |
| 273 | + for (GraphicsDevice gd : getScreenDevices()) { | |
| 274 | + if (gd instanceof DisplayChangedListener) { | |
| 275 | + ((DisplayChangedListener) gd).displayChanged(); | |
| 276 | + } | |
| 277 | + } | |
| 278 | + | |
| 279 | + // notify SunDisplayChanger list (e.g. VolatileSurfaceManagers and | |
| 280 | + // SurfaceDataProxies) about the display change event | |
| 281 | + displayChanger.notifyListeners(); | |
| 282 | + } | |
| 283 | + | |
| 284 | + /** | |
| 285 | + * Part of the DisplayChangedListener interface: | |
| 286 | + * propagate this event to listeners | |
| 287 | + */ | |
| 288 | + public void paletteChanged() { | |
| 289 | + displayChanger.notifyPaletteChanged(); | |
| 290 | + } | |
| 291 | + | |
| 292 | + /** | |
| 293 | + * Returns true when the display is local, false for remote displays. | |
| 294 | + * | |
| 295 | + * @return true when the display is local, false for remote displays | |
| 296 | + */ | |
| 297 | + public abstract boolean isDisplayLocal(); | |
| 298 | + | |
| 299 | + /* | |
| 300 | + * ----DISPLAY CHANGE SUPPORT---- | |
| 301 | + */ | |
| 302 | + | |
| 303 | + protected SunDisplayChanger displayChanger = new SunDisplayChanger(); | |
| 304 | + | |
| 305 | + /** | |
| 306 | + * Add a DisplayChangeListener to be notified when the display settings | |
| 307 | + * are changed. | |
| 308 | + */ | |
| 309 | + public void addDisplayChangedListener(DisplayChangedListener client) { | |
| 310 | + displayChanger.add(client); | |
| 311 | + } | |
| 312 | + | |
| 313 | + /** | |
| 314 | + * Remove a DisplayChangeListener from Win32GraphicsEnvironment | |
| 315 | + */ | |
| 316 | + public void removeDisplayChangedListener(DisplayChangedListener client) { | |
| 317 | + displayChanger.remove(client); | |
| 318 | + } | |
| 319 | + | |
| 320 | + /* | |
| 321 | + * ----END DISPLAY CHANGE SUPPORT---- | |
| 322 | + */ | |
| 323 | + | |
| 324 | + /** | |
| 325 | + * Returns true if FlipBufferStrategy with COPIED buffer contents | |
| 326 | + * is preferred for this peer's GraphicsConfiguration over | |
| 327 | + * BlitBufferStrategy, false otherwise. | |
| 328 | + * | |
| 329 | + * The reason FlipBS could be preferred is that in some configurations | |
| 330 | + * an accelerated copy to the screen is supported (like Direct3D 9) | |
| 331 | + * | |
| 332 | + * @return true if flip strategy should be used, false otherwise | |
| 333 | + */ | |
| 334 | + public boolean isFlipStrategyPreferred(ComponentPeer peer) { | |
| 335 | + return false; | |
| 336 | + } | |
| 337 | +} | |
Binary file not shown.
| @@ -0,0 +1,34 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This is a tag interface for a surface. | |
| 30 | + * @see sun.java2d.SurfaceData | |
| 31 | + * @see sun.java2d.pipe.hw.AccelSurface | |
| 32 | + */ | |
| 33 | +public interface Surface { | |
| 34 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,1060 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d; | |
| 27 | + | |
| 28 | +import java.awt.Color; | |
| 29 | +import java.awt.Rectangle; | |
| 30 | +import java.awt.Transparency; | |
| 31 | +import java.awt.GraphicsConfiguration; | |
| 32 | +import java.awt.Image; | |
| 33 | +import java.awt.image.ColorModel; | |
| 34 | +import java.awt.image.IndexColorModel; | |
| 35 | +import java.awt.image.Raster; | |
| 36 | + | |
| 37 | +import sun.java2d.loops.RenderCache; | |
| 38 | +import sun.java2d.loops.RenderLoops; | |
| 39 | +import sun.java2d.loops.CompositeType; | |
| 40 | +import sun.java2d.loops.SurfaceType; | |
| 41 | +import sun.java2d.loops.MaskFill; | |
| 42 | +import sun.java2d.loops.DrawLine; | |
| 43 | +import sun.java2d.loops.FillRect; | |
| 44 | +import sun.java2d.loops.DrawRect; | |
| 45 | +import sun.java2d.loops.DrawPolygons; | |
| 46 | +import sun.java2d.loops.DrawPath; | |
| 47 | +import sun.java2d.loops.FillPath; | |
| 48 | +import sun.java2d.loops.FillSpans; | |
| 49 | +import sun.java2d.loops.FillParallelogram; | |
| 50 | +import sun.java2d.loops.DrawParallelogram; | |
| 51 | +import sun.java2d.loops.FontInfo; | |
| 52 | +import sun.java2d.loops.DrawGlyphList; | |
| 53 | +import sun.java2d.loops.DrawGlyphListAA; | |
| 54 | +import sun.java2d.loops.DrawGlyphListLCD; | |
| 55 | +import sun.java2d.pipe.LoopPipe; | |
| 56 | +import sun.java2d.pipe.ShapeDrawPipe; | |
| 57 | +import sun.java2d.pipe.ParallelogramPipe; | |
| 58 | +import sun.java2d.pipe.CompositePipe; | |
| 59 | +import sun.java2d.pipe.GeneralCompositePipe; | |
| 60 | +import sun.java2d.pipe.SpanClipRenderer; | |
| 61 | +import sun.java2d.pipe.SpanShapeRenderer; | |
| 62 | +import sun.java2d.pipe.AAShapePipe; | |
| 63 | +import sun.java2d.pipe.AlphaPaintPipe; | |
| 64 | +import sun.java2d.pipe.AlphaColorPipe; | |
| 65 | +import sun.java2d.pipe.PixelToShapeConverter; | |
| 66 | +import sun.java2d.pipe.PixelToParallelogramConverter; | |
| 67 | +import sun.java2d.pipe.TextPipe; | |
| 68 | +import sun.java2d.pipe.TextRenderer; | |
| 69 | +import sun.java2d.pipe.AATextRenderer; | |
| 70 | +import sun.java2d.pipe.LCDTextRenderer; | |
| 71 | +import sun.java2d.pipe.SolidTextRenderer; | |
| 72 | +import sun.java2d.pipe.OutlineTextRenderer; | |
| 73 | +import sun.java2d.pipe.DrawImagePipe; | |
| 74 | +import sun.java2d.pipe.DrawImage; | |
| 75 | +import sun.awt.SunHints; | |
| 76 | +import sun.awt.image.SurfaceManager; | |
| 77 | +import sun.java2d.pipe.LoopBasedPipe; | |
| 78 | + | |
| 79 | +/** | |
| 80 | + * This class provides various pieces of information relevant to a | |
| 81 | + * particular drawing surface. The information obtained from this | |
| 82 | + * object describes the pixels of a particular instance of a drawing | |
| 83 | + * surface and can only be shared among the various graphics objects | |
| 84 | + * that target the same BufferedImage or the same screen Component. | |
| 85 | + * <p> | |
| 86 | + * Each SurfaceData object holds a StateTrackableDelegate object | |
| 87 | + * which tracks both changes to the content of the pixels of this | |
| 88 | + * surface and changes to the overall state of the pixels - such | |
| 89 | + * as becoming invalid or losing the surface. The delegate is | |
| 90 | + * marked "dirty" whenever the setSurfaceLost() or invalidate() | |
| 91 | + * methods are called and should also be marked "dirty" by the | |
| 92 | + * rendering pipelines whenever they modify the pixels of this | |
| 93 | + * SurfaceData. | |
| 94 | + * <p> | |
| 95 | + * If you get a StateTracker from a SurfaceData and it reports | |
| 96 | + * that it is still "current", then you can trust that the pixels | |
| 97 | + * have not changed and that the SurfaceData is still valid and | |
| 98 | + * has not lost its underlying storage (surfaceLost) since you | |
| 99 | + * retrieved the tracker. | |
| 100 | + */ | |
| 101 | +public abstract class SurfaceData | |
| 102 | + implements Transparency, DisposerTarget, StateTrackable, Surface | |
| 103 | +{ | |
| 104 | + private long pData; | |
| 105 | + private boolean valid; | |
| 106 | + private boolean surfaceLost; // = false; | |
| 107 | + private SurfaceType surfaceType; | |
| 108 | + private ColorModel colorModel; | |
| 109 | + | |
| 110 | + private Object disposerReferent = new Object(); | |
| 111 | + | |
| 112 | + private static native void initIDs(); | |
| 113 | + | |
| 114 | + private Object blitProxyKey; | |
| 115 | + private StateTrackableDelegate stateDelegate; | |
| 116 | + | |
| 117 | + static { | |
| 118 | + initIDs(); | |
| 119 | + } | |
| 120 | + | |
| 121 | + protected SurfaceData(SurfaceType surfaceType, ColorModel cm) { | |
| 122 | + this(State.STABLE, surfaceType, cm); | |
| 123 | + } | |
| 124 | + | |
| 125 | + protected SurfaceData(State state, SurfaceType surfaceType, ColorModel cm) { | |
| 126 | + this(StateTrackableDelegate.createInstance(state), surfaceType, cm); | |
| 127 | + } | |
| 128 | + | |
| 129 | + protected SurfaceData(StateTrackableDelegate trackable, | |
| 130 | + SurfaceType surfaceType, ColorModel cm) | |
| 131 | + { | |
| 132 | + this.stateDelegate = trackable; | |
| 133 | + this.colorModel = cm; | |
| 134 | + this.surfaceType = surfaceType; | |
| 135 | + valid = true; | |
| 136 | + } | |
| 137 | + | |
| 138 | + protected SurfaceData(State state) { | |
| 139 | + this.stateDelegate = StateTrackableDelegate.createInstance(state); | |
| 140 | + valid = true; | |
| 141 | + } | |
| 142 | + | |
| 143 | + /** | |
| 144 | + * Subclasses can set a "blit proxy key" which will be used | |
| 145 | + * along with the SurfaceManager.getCacheData() mechanism to | |
| 146 | + * store acceleration-compatible cached copies of source images. | |
| 147 | + * This key is a "tag" used to identify which cached copies | |
| 148 | + * are compatible with this destination SurfaceData. | |
| 149 | + * The getSourceSurfaceData() method uses this key to manage | |
| 150 | + * cached copies of a source image as described below. | |
| 151 | + * <p> | |
| 152 | + * The Object used as this key should be as unique as it needs | |
| 153 | + * to be to ensure that multiple acceleratible destinations can | |
| 154 | + * each store their cached copies separately under different keys | |
| 155 | + * without interfering with each other or getting back the wrong | |
| 156 | + * cached copy. | |
| 157 | + * <p> | |
| 158 | + * Many acceleratable SurfaceData objects can use their own | |
| 159 | + * GraphicsConfiguration as their proxy key as the GC object will | |
| 160 | + * typically be unique to a given screen and pixel format, but | |
| 161 | + * other rendering destinations may have more or less stringent | |
| 162 | + * sharing requirements. For instance, X11 pixmaps can be | |
| 163 | + * shared on a given screen by any GraphicsConfiguration that | |
| 164 | + * has the same depth and SurfaceType. Multiple such GCs with | |
| 165 | + * the same depth and SurfaceType can exist per screen so storing | |
| 166 | + * a different cached proxy for each would be a waste. One can | |
| 167 | + * imagine platforms where a single cached copy can be created | |
| 168 | + * and shared across all screens and pixel formats - such | |
| 169 | + * implementations could use a single heavily shared key Object. | |
| 170 | + */ | |
| 171 | + protected void setBlitProxyKey(Object key) { | |
| 172 | + // Caching is effectively disabled if we never have a proxy key | |
| 173 | + // since the getSourceSurfaceData() method only does caching | |
| 174 | + // if the key is not null. | |
| 175 | + if (SurfaceDataProxy.isCachingAllowed()) { | |
| 176 | + this.blitProxyKey = key; | |
| 177 | + } | |
| 178 | + } | |
| 179 | + | |
| 180 | + /** | |
| 181 | + * This method is called on a destination SurfaceData to choose | |
| 182 | + * the best SurfaceData from a source Image for an imaging | |
| 183 | + * operation, with help from its SurfaceManager. | |
| 184 | + * The method may determine that the default SurfaceData was | |
| 185 | + * really the best choice in the first place, or it may decide | |
| 186 | + * to use a cached surface. Some general decisions about whether | |
| 187 | + * acceleration is enabled are made by this method, but any | |
| 188 | + * decision based on the type of the source image is made in | |
| 189 | + * the makeProxyFor method below when it comes up with the | |
| 190 | + * appropriate SurfaceDataProxy instance. | |
| 191 | + * The parameters describe the type of imaging operation being performed. | |
| 192 | + * <p> | |
| 193 | + * If a blitProxyKey was supplied by the subclass then it is | |
| 194 | + * used to potentially override the choice of source SurfaceData. | |
| 195 | + * The outline of this process is: | |
| 196 | + * <ol> | |
| 197 | + * <li> Image pipeline asks destSD to find an appropriate | |
| 198 | + * srcSD for a given source Image object. | |
| 199 | + * <li> destSD gets the SurfaceManager of the source Image | |
| 200 | + * and first retrieves the default SD from it using | |
| 201 | + * getPrimarySurfaceData() | |
| 202 | + * <li> destSD uses its "blit proxy key" (if set) to look for | |
| 203 | + * some cached data stored in the source SurfaceManager | |
| 204 | + * <li> If the cached data is null then makeProxyFor() is used | |
| 205 | + * to create some cached data which is stored back in the | |
| 206 | + * source SurfaceManager under the same key for future uses. | |
| 207 | + * <li> The cached data will be a SurfaceDataProxy object. | |
| 208 | + * <li> The SurfaceDataProxy object is then consulted to | |
| 209 | + * return a replacement SurfaceData object (typically | |
| 210 | + * a cached copy if appropriate, or the original if not). | |
| 211 | + * </ol> | |
| 212 | + */ | |
| 213 | + public SurfaceData getSourceSurfaceData(Image img, | |
| 214 | + int txtype, | |
| 215 | + CompositeType comp, | |
| 216 | + Color bgColor) | |
| 217 | + { | |
| 218 | + SurfaceManager srcMgr = SurfaceManager.getManager(img); | |
| 219 | + SurfaceData srcData = srcMgr.getPrimarySurfaceData(); | |
| 220 | + if (img.getAccelerationPriority() > 0.0f && | |
| 221 | + blitProxyKey != null) | |
| 222 | + { | |
| 223 | + SurfaceDataProxy sdp = | |
| 224 | + (SurfaceDataProxy) srcMgr.getCacheData(blitProxyKey); | |
| 225 | + if (sdp == null || !sdp.isValid()) { | |
| 226 | + if (srcData.getState() == State.UNTRACKABLE) { | |
| 227 | + sdp = SurfaceDataProxy.UNCACHED; | |
| 228 | + } else { | |
| 229 | + sdp = makeProxyFor(srcData); | |
| 230 | + } | |
| 231 | + srcMgr.setCacheData(blitProxyKey, sdp); | |
| 232 | + } | |
| 233 | + srcData = sdp.replaceData(srcData, txtype, comp, bgColor); | |
| 234 | + } | |
| 235 | + return srcData; | |
| 236 | + } | |
| 237 | + | |
| 238 | + /** | |
| 239 | + * This method is called on a destination SurfaceData to choose | |
| 240 | + * a proper SurfaceDataProxy subclass for a source SurfaceData | |
| 241 | + * to use to control when and with what surface to override a | |
| 242 | + * given image operation. The argument is the default SurfaceData | |
| 243 | + * for the source Image. | |
| 244 | + * <p> | |
| 245 | + * The type of the return object is chosen based on the | |
| 246 | + * acceleration capabilities of this SurfaceData and the | |
| 247 | + * type of the given source SurfaceData object. | |
| 248 | + * <p> | |
| 249 | + * In some cases the original SurfaceData will always be the | |
| 250 | + * best choice to use to blit to this SurfaceData. This can | |
| 251 | + * happen if the source image is a hardware surface of the | |
| 252 | + * same type as this one and so acceleration will happen without | |
| 253 | + * any caching. It may also be the case that the source image | |
| 254 | + * can never be accelerated on this SurfaceData - for example | |
| 255 | + * because it is translucent and there are no accelerated | |
| 256 | + * translucent image ops for this surface. | |
| 257 | + * <p> | |
| 258 | + * In those cases there is a special SurfaceDataProxy.UNCACHED | |
| 259 | + * instance that represents a NOP for caching purposes - it | |
| 260 | + * always returns the original sourceSD object as the replacement | |
| 261 | + * copy so no caching is ever performed. | |
| 262 | + */ | |
| 263 | + public SurfaceDataProxy makeProxyFor(SurfaceData srcData) { | |
| 264 | + return SurfaceDataProxy.UNCACHED; | |
| 265 | + } | |
| 266 | + | |
| 267 | + /** | |
| 268 | + * Extracts the SurfaceManager from the given Image, and then | |
| 269 | + * returns the SurfaceData object that would best be suited as the | |
| 270 | + * destination surface in some rendering operation. | |
| 271 | + */ | |
| 272 | + public static SurfaceData getPrimarySurfaceData(Image img) { | |
| 273 | + SurfaceManager sMgr = SurfaceManager.getManager(img); | |
| 274 | + return sMgr.getPrimarySurfaceData(); | |
| 275 | + } | |
| 276 | + | |
| 277 | + /** | |
| 278 | + * Restores the contents of the given Image and then returns the new | |
| 279 | + * SurfaceData object in use by the Image's SurfaceManager. | |
| 280 | + */ | |
| 281 | + public static SurfaceData restoreContents(Image img) { | |
| 282 | + SurfaceManager sMgr = SurfaceManager.getManager(img); | |
| 283 | + return sMgr.restoreContents(); | |
| 284 | + } | |
| 285 | + | |
| 286 | + public State getState() { | |
| 287 | + return stateDelegate.getState(); | |
| 288 | + } | |
| 289 | + | |
| 290 | + public StateTracker getStateTracker() { | |
| 291 | + return stateDelegate.getStateTracker(); | |
| 292 | + } | |
| 293 | + | |
| 294 | + /** | |
| 295 | + * Marks this surface as dirty. | |
| 296 | + */ | |
| 297 | + public final void markDirty() { | |
| 298 | + stateDelegate.markDirty(); | |
| 299 | + } | |
| 300 | + | |
| 301 | + /** | |
| 302 | + * Sets the value of the surfaceLost variable, which indicates whether | |
| 303 | + * something has happened to the rendering surface such that it needs | |
| 304 | + * to be restored and re-rendered. | |
| 305 | + */ | |
| 306 | + public void setSurfaceLost(boolean lost) { | |
| 307 | + surfaceLost = lost; | |
| 308 | + stateDelegate.markDirty(); | |
| 309 | + } | |
| 310 | + | |
| 311 | + public boolean isSurfaceLost() { | |
| 312 | + return surfaceLost; | |
| 313 | + } | |
| 314 | + | |
| 315 | + /** | |
| 316 | + * Returns a boolean indicating whether or not this SurfaceData is valid. | |
| 317 | + */ | |
| 318 | + public final boolean isValid() { | |
| 319 | + return valid; | |
| 320 | + } | |
| 321 | + | |
| 322 | + public Object getDisposerReferent() { | |
| 323 | + return disposerReferent; | |
| 324 | + } | |
| 325 | + | |
| 326 | + public long getNativeOps() { | |
| 327 | + return pData; | |
| 328 | + } | |
| 329 | + | |
| 330 | + /** | |
| 331 | + * Sets this SurfaceData object to the invalid state. All Graphics | |
| 332 | + * objects must get a new SurfaceData object via the refresh method | |
| 333 | + * and revalidate their pipelines before continuing. | |
| 334 | + */ | |
| 335 | + public void invalidate() { | |
| 336 | + valid = false; | |
| 337 | + stateDelegate.markDirty(); | |
| 338 | + } | |
| 339 | + | |
| 340 | + /** | |
| 341 | + * Certain changes in the configuration of a surface require the | |
| 342 | + * invalidation of existing associated SurfaceData objects and | |
| 343 | + * the creation of brand new ones. These changes include size, | |
| 344 | + * ColorModel, or SurfaceType. Existing Graphics objects | |
| 345 | + * which are directed at such surfaces, however, must continue | |
| 346 | + * to render to them even after the change occurs underneath | |
| 347 | + * the covers. The getReplacement() method is called from | |
| 348 | + * SunGraphics2D.revalidateAll() when the associated SurfaceData | |
| 349 | + * is found to be invalid so that a Graphics object can continue | |
| 350 | + * to render to the surface in its new configuration. | |
| 351 | + * | |
| 352 | + * Such changes only tend to happen to window based surfaces since | |
| 353 | + * most image based surfaces never change size or pixel format. | |
| 354 | + * Even VolatileImage objects never change size and they only | |
| 355 | + * change their pixel format when manually validated against a | |
| 356 | + * new GraphicsConfiguration, at which point old Graphics objects | |
| 357 | + * are no longer expected to render to them after the validation | |
| 358 | + * step. Thus, only window based surfaces really need to deal | |
| 359 | + * with this form of replacement. | |
| 360 | + */ | |
| 361 | + public abstract SurfaceData getReplacement(); | |
| 362 | + | |
| 363 | + protected static final LoopPipe colorPrimitives; | |
| 364 | + | |
| 365 | + public static final TextPipe outlineTextRenderer; | |
| 366 | + public static final TextPipe solidTextRenderer; | |
| 367 | + public static final TextPipe aaTextRenderer; | |
| 368 | + public static final TextPipe lcdTextRenderer; | |
| 369 | + | |
| 370 | + protected static final AlphaColorPipe colorPipe; | |
| 371 | + protected static final PixelToShapeConverter colorViaShape; | |
| 372 | + protected static final PixelToParallelogramConverter colorViaPgram; | |
| 373 | + protected static final TextPipe colorText; | |
| 374 | + protected static final CompositePipe clipColorPipe; | |
| 375 | + protected static final TextPipe clipColorText; | |
| 376 | + protected static final AAShapePipe AAColorShape; | |
| 377 | + protected static final PixelToParallelogramConverter AAColorViaShape; | |
| 378 | + protected static final PixelToParallelogramConverter AAColorViaPgram; | |
| 379 | + protected static final AAShapePipe AAClipColorShape; | |
| 380 | + protected static final PixelToParallelogramConverter AAClipColorViaShape; | |
| 381 | + | |
| 382 | + protected static final CompositePipe paintPipe; | |
| 383 | + protected static final SpanShapeRenderer paintShape; | |
| 384 | + protected static final PixelToShapeConverter paintViaShape; | |
| 385 | + protected static final TextPipe paintText; | |
| 386 | + protected static final CompositePipe clipPaintPipe; | |
| 387 | + protected static final TextPipe clipPaintText; | |
| 388 | + protected static final AAShapePipe AAPaintShape; | |
| 389 | + protected static final PixelToParallelogramConverter AAPaintViaShape; | |
| 390 | + protected static final AAShapePipe AAClipPaintShape; | |
| 391 | + protected static final PixelToParallelogramConverter AAClipPaintViaShape; | |
| 392 | + | |
| 393 | + protected static final CompositePipe compPipe; | |
| 394 | + protected static final SpanShapeRenderer compShape; | |
| 395 | + protected static final PixelToShapeConverter compViaShape; | |
| 396 | + protected static final TextPipe compText; | |
| 397 | + protected static final CompositePipe clipCompPipe; | |
| 398 | + protected static final TextPipe clipCompText; | |
| 399 | + protected static final AAShapePipe AACompShape; | |
| 400 | + protected static final PixelToParallelogramConverter AACompViaShape; | |
| 401 | + protected static final AAShapePipe AAClipCompShape; | |
| 402 | + protected static final PixelToParallelogramConverter AAClipCompViaShape; | |
| 403 | + | |
| 404 | + protected static final DrawImagePipe imagepipe; | |
| 405 | + | |
| 406 | + // Utility subclass to add the LoopBasedPipe tagging interface | |
| 407 | + static class PixelToShapeLoopConverter | |
| 408 | + extends PixelToShapeConverter | |
| 409 | + implements LoopBasedPipe | |
| 410 | + { | |
| 411 | + public PixelToShapeLoopConverter(ShapeDrawPipe pipe) { | |
| 412 | + super(pipe); | |
| 413 | + } | |
| 414 | + } | |
| 415 | + | |
| 416 | + // Utility subclass to add the LoopBasedPipe tagging interface | |
| 417 | + static class PixelToPgramLoopConverter | |
| 418 | + extends PixelToParallelogramConverter | |
| 419 | + implements LoopBasedPipe | |
| 420 | + { | |
| 421 | + public PixelToPgramLoopConverter(ShapeDrawPipe shapepipe, | |
| 422 | + ParallelogramPipe pgrampipe, | |
| 423 | + double minPenSize, | |
| 424 | + double normPosition, | |
| 425 | + boolean adjustfill) | |
| 426 | + { | |
| 427 | + super(shapepipe, pgrampipe, minPenSize, normPosition, adjustfill); | |
| 428 | + } | |
| 429 | + } | |
| 430 | + | |
| 431 | + private static PixelToParallelogramConverter | |
| 432 | + makeConverter(AAShapePipe renderer, | |
| 433 | + ParallelogramPipe pgrampipe) | |
| 434 | + { | |
| 435 | + return new PixelToParallelogramConverter(renderer, | |
| 436 | + pgrampipe, | |
| 437 | + 1.0/8.0, 0.499, | |
| 438 | + false); | |
| 439 | + } | |
| 440 | + | |
| 441 | + private static PixelToParallelogramConverter | |
| 442 | + makeConverter(AAShapePipe renderer) | |
| 443 | + { | |
| 444 | + return makeConverter(renderer, renderer); | |
| 445 | + } | |
| 446 | + | |
| 447 | + static { | |
| 448 | + colorPrimitives = new LoopPipe(); | |
| 449 | + | |
| 450 | + outlineTextRenderer = new OutlineTextRenderer(); | |
| 451 | + solidTextRenderer = new SolidTextRenderer(); | |
| 452 | + aaTextRenderer = new AATextRenderer(); | |
| 453 | + lcdTextRenderer = new LCDTextRenderer(); | |
| 454 | + | |
| 455 | + colorPipe = new AlphaColorPipe(); | |
| 456 | + // colorShape = colorPrimitives; | |
| 457 | + colorViaShape = new PixelToShapeLoopConverter(colorPrimitives); | |
| 458 | + colorViaPgram = new PixelToPgramLoopConverter(colorPrimitives, | |
| 459 | + colorPrimitives, | |
| 460 | + 1.0, 0.25, true); | |
| 461 | + colorText = new TextRenderer(colorPipe); | |
| 462 | + clipColorPipe = new SpanClipRenderer(colorPipe); | |
| 463 | + clipColorText = new TextRenderer(clipColorPipe); | |
| 464 | + AAColorShape = new AAShapePipe(colorPipe); | |
| 465 | + AAColorViaShape = makeConverter(AAColorShape); | |
| 466 | + AAColorViaPgram = makeConverter(AAColorShape, colorPipe); | |
| 467 | + AAClipColorShape = new AAShapePipe(clipColorPipe); | |
| 468 | + AAClipColorViaShape = makeConverter(AAClipColorShape); | |
| 469 | + | |
| 470 | + paintPipe = new AlphaPaintPipe(); | |
| 471 | + paintShape = new SpanShapeRenderer.Composite(paintPipe); | |
| 472 | + paintViaShape = new PixelToShapeConverter(paintShape); | |
| 473 | + paintText = new TextRenderer(paintPipe); | |
| 474 | + clipPaintPipe = new SpanClipRenderer(paintPipe); | |
| 475 | + clipPaintText = new TextRenderer(clipPaintPipe); | |
| 476 | + AAPaintShape = new AAShapePipe(paintPipe); | |
| 477 | + AAPaintViaShape = makeConverter(AAPaintShape); | |
| 478 | + AAClipPaintShape = new AAShapePipe(clipPaintPipe); | |
| 479 | + AAClipPaintViaShape = makeConverter(AAClipPaintShape); | |
| 480 | + | |
| 481 | + compPipe = new GeneralCompositePipe(); | |
| 482 | + compShape = new SpanShapeRenderer.Composite(compPipe); | |
| 483 | + compViaShape = new PixelToShapeConverter(compShape); | |
| 484 | + compText = new TextRenderer(compPipe); | |
| 485 | + clipCompPipe = new SpanClipRenderer(compPipe); | |
| 486 | + clipCompText = new TextRenderer(clipCompPipe); | |
| 487 | + AACompShape = new AAShapePipe(compPipe); | |
| 488 | + AACompViaShape = makeConverter(AACompShape); | |
| 489 | + AAClipCompShape = new AAShapePipe(clipCompPipe); | |
| 490 | + AAClipCompViaShape = makeConverter(AAClipCompShape); | |
| 491 | + | |
| 492 | + imagepipe = new DrawImage(); | |
| 493 | + } | |
| 494 | + | |
| 495 | + /* Not all surfaces and rendering mode combinations support LCD text. */ | |
| 496 | + static final int LOOP_UNKNOWN = 0; | |
| 497 | + static final int LOOP_FOUND = 1; | |
| 498 | + static final int LOOP_NOTFOUND = 2; | |
| 499 | + int haveLCDLoop; | |
| 500 | + int havePgramXORLoop; | |
| 501 | + int havePgramSolidLoop; | |
| 502 | + | |
| 503 | + public boolean canRenderLCDText(SunGraphics2D sg2d) { | |
| 504 | + // For now the answer can only be true in the following cases: | |
| 505 | + if (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY && | |
| 506 | + sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR && | |
| 507 | + sg2d.clipState <= SunGraphics2D.CLIP_RECTANGULAR && | |
| 508 | + sg2d.surfaceData.getTransparency() == Transparency.OPAQUE) | |
| 509 | + { | |
| 510 | + if (haveLCDLoop == LOOP_UNKNOWN) { | |
| 511 | + DrawGlyphListLCD loop = | |
| 512 | + DrawGlyphListLCD.locate(SurfaceType.AnyColor, | |
| 513 | + CompositeType.SrcNoEa, | |
| 514 | + getSurfaceType()); | |
| 515 | + haveLCDLoop = (loop != null) ? LOOP_FOUND : LOOP_NOTFOUND; | |
| 516 | + } | |
| 517 | + return haveLCDLoop == LOOP_FOUND; | |
| 518 | + } | |
| 519 | + return false; /* for now - in the future we may want to search */ | |
| 520 | + } | |
| 521 | + | |
| 522 | + public boolean canRenderParallelograms(SunGraphics2D sg2d) { | |
| 523 | + if (sg2d.paintState <= sg2d.PAINT_ALPHACOLOR) { | |
| 524 | + if (sg2d.compositeState == sg2d.COMP_XOR) { | |
| 525 | + if (havePgramXORLoop == LOOP_UNKNOWN) { | |
| 526 | + FillParallelogram loop = | |
| 527 | + FillParallelogram.locate(SurfaceType.AnyColor, | |
| 528 | + CompositeType.Xor, | |
| 529 | + getSurfaceType()); | |
| 530 | + havePgramXORLoop = | |
| 531 | + (loop != null) ? LOOP_FOUND : LOOP_NOTFOUND; | |
| 532 | + } | |
| 533 | + return havePgramXORLoop == LOOP_FOUND; | |
| 534 | + } else if (sg2d.compositeState <= sg2d.COMP_ISCOPY && | |
| 535 | + sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON && | |
| 536 | + sg2d.clipState != sg2d.CLIP_SHAPE) | |
| 537 | + { | |
| 538 | + if (havePgramSolidLoop == LOOP_UNKNOWN) { | |
| 539 | + FillParallelogram loop = | |
| 540 | + FillParallelogram.locate(SurfaceType.AnyColor, | |
| 541 | + CompositeType.SrcNoEa, | |
| 542 | + getSurfaceType()); | |
| 543 | + havePgramSolidLoop = | |
| 544 | + (loop != null) ? LOOP_FOUND : LOOP_NOTFOUND; | |
| 545 | + } | |
| 546 | + return havePgramSolidLoop == LOOP_FOUND; | |
| 547 | + } | |
| 548 | + } | |
| 549 | + return false; | |
| 550 | + } | |
| 551 | + | |
| 552 | + public void validatePipe(SunGraphics2D sg2d) { | |
| 553 | + sg2d.imagepipe = imagepipe; | |
| 554 | + if (sg2d.compositeState == sg2d.COMP_XOR) { | |
| 555 | + if (sg2d.paintState > sg2d.PAINT_ALPHACOLOR) { | |
| 556 | + sg2d.drawpipe = paintViaShape; | |
| 557 | + sg2d.fillpipe = paintViaShape; | |
| 558 | + sg2d.shapepipe = paintShape; | |
| 559 | + // REMIND: Ideally custom paint mode would use glyph | |
| 560 | + // rendering as opposed to outline rendering but the | |
| 561 | + // glyph paint rendering pipeline uses MaskBlit which | |
| 562 | + // is not defined for XOR. This means that text drawn | |
| 563 | + // in XOR mode with a Color object is different than | |
| 564 | + // text drawn in XOR mode with a Paint object. | |
| 565 | + sg2d.textpipe = outlineTextRenderer; | |
| 566 | + } else { | |
| 567 | + PixelToShapeConverter converter; | |
| 568 | + if (canRenderParallelograms(sg2d)) { | |
| 569 | + converter = colorViaPgram; | |
| 570 | + // Note that we use the transforming pipe here because it | |
| 571 | + // will examine the shape and possibly perform an optimized | |
| 572 | + // operation if it can be simplified. The simplifications | |
| 573 | + // will be valid for all STROKE and TRANSFORM types. | |
| 574 | + sg2d.shapepipe = colorViaPgram; | |
| 575 | + } else { | |
| 576 | + converter = colorViaShape; | |
| 577 | + sg2d.shapepipe = colorPrimitives; | |
| 578 | + } | |
| 579 | + if (sg2d.clipState == sg2d.CLIP_SHAPE) { | |
| 580 | + sg2d.drawpipe = converter; | |
| 581 | + sg2d.fillpipe = converter; | |
| 582 | + // REMIND: We should not be changing text strategies | |
| 583 | + // between outline and glyph rendering based upon the | |
| 584 | + // presence of a complex clip as that could cause a | |
| 585 | + // mismatch when drawing the same text both clipped | |
| 586 | + // and unclipped on two separate rendering passes. | |
| 587 | + // Unfortunately, all of the clipped glyph rendering | |
| 588 | + // pipelines rely on the use of the MaskBlit operation | |
| 589 | + // which is not defined for XOR. | |
| 590 | + sg2d.textpipe = outlineTextRenderer; | |
| 591 | + } else { | |
| 592 | + if (sg2d.transformState >= sg2d.TRANSFORM_TRANSLATESCALE) { | |
| 593 | + sg2d.drawpipe = converter; | |
| 594 | + sg2d.fillpipe = converter; | |
| 595 | + } else { | |
| 596 | + if (sg2d.strokeState != sg2d.STROKE_THIN) { | |
| 597 | + sg2d.drawpipe = converter; | |
| 598 | + } else { | |
| 599 | + sg2d.drawpipe = colorPrimitives; | |
| 600 | + } | |
| 601 | + sg2d.fillpipe = colorPrimitives; | |
| 602 | + } | |
| 603 | + sg2d.textpipe = solidTextRenderer; | |
| 604 | + } | |
| 605 | + // assert(sg2d.surfaceData == this); | |
| 606 | + } | |
| 607 | + } else if (sg2d.compositeState == sg2d.COMP_CUSTOM) { | |
| 608 | + if (sg2d.antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) { | |
| 609 | + if (sg2d.clipState == sg2d.CLIP_SHAPE) { | |
| 610 | + sg2d.drawpipe = AAClipCompViaShape; | |
| 611 | + sg2d.fillpipe = AAClipCompViaShape; | |
| 612 | + sg2d.shapepipe = AAClipCompViaShape; | |
| 613 | + sg2d.textpipe = clipCompText; | |
| 614 | + } else { | |
| 615 | + sg2d.drawpipe = AACompViaShape; | |
| 616 | + sg2d.fillpipe = AACompViaShape; | |
| 617 | + sg2d.shapepipe = AACompViaShape; | |
| 618 | + sg2d.textpipe = compText; | |
| 619 | + } | |
| 620 | + } else { | |
| 621 | + sg2d.drawpipe = compViaShape; | |
| 622 | + sg2d.fillpipe = compViaShape; | |
| 623 | + sg2d.shapepipe = compShape; | |
| 624 | + if (sg2d.clipState == sg2d.CLIP_SHAPE) { | |
| 625 | + sg2d.textpipe = clipCompText; | |
| 626 | + } else { | |
| 627 | + sg2d.textpipe = compText; | |
| 628 | + } | |
| 629 | + } | |
| 630 | + } else if (sg2d.antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) { | |
| 631 | + sg2d.alphafill = getMaskFill(sg2d); | |
| 632 | + // assert(sg2d.surfaceData == this); | |
| 633 | + if (sg2d.alphafill != null) { | |
| 634 | + if (sg2d.clipState == sg2d.CLIP_SHAPE) { | |
| 635 | + sg2d.drawpipe = AAClipColorViaShape; | |
| 636 | + sg2d.fillpipe = AAClipColorViaShape; | |
| 637 | + sg2d.shapepipe = AAClipColorViaShape; | |
| 638 | + sg2d.textpipe = clipColorText; | |
| 639 | + } else { | |
| 640 | + PixelToParallelogramConverter converter = | |
| 641 | + (sg2d.alphafill.canDoParallelograms() | |
| 642 | + ? AAColorViaPgram | |
| 643 | + : AAColorViaShape); | |
| 644 | + sg2d.drawpipe = converter; | |
| 645 | + sg2d.fillpipe = converter; | |
| 646 | + sg2d.shapepipe = converter; | |
| 647 | + if (sg2d.paintState > sg2d.PAINT_ALPHACOLOR || | |
| 648 | + sg2d.compositeState > sg2d.COMP_ISCOPY) | |
| 649 | + { | |
| 650 | + sg2d.textpipe = colorText; | |
| 651 | + } else { | |
| 652 | + sg2d.textpipe = getTextPipe(sg2d, true /* AA==ON */); | |
| 653 | + } | |
| 654 | + } | |
| 655 | + } else { | |
| 656 | + if (sg2d.clipState == sg2d.CLIP_SHAPE) { | |
| 657 | + sg2d.drawpipe = AAClipPaintViaShape; | |
| 658 | + sg2d.fillpipe = AAClipPaintViaShape; | |
| 659 | + sg2d.shapepipe = AAClipPaintViaShape; | |
| 660 | + sg2d.textpipe = clipPaintText; | |
| 661 | + } else { | |
| 662 | + sg2d.drawpipe = AAPaintViaShape; | |
| 663 | + sg2d.fillpipe = AAPaintViaShape; | |
| 664 | + sg2d.shapepipe = AAPaintViaShape; | |
| 665 | + sg2d.textpipe = paintText; | |
| 666 | + } | |
| 667 | + } | |
| 668 | + } else if (sg2d.paintState > sg2d.PAINT_ALPHACOLOR || | |
| 669 | + sg2d.compositeState > sg2d.COMP_ISCOPY || | |
| 670 | + sg2d.clipState == sg2d.CLIP_SHAPE) | |
| 671 | + { | |
| 672 | + sg2d.drawpipe = paintViaShape; | |
| 673 | + sg2d.fillpipe = paintViaShape; | |
| 674 | + sg2d.shapepipe = paintShape; | |
| 675 | + sg2d.alphafill = getMaskFill(sg2d); | |
| 676 | + // assert(sg2d.surfaceData == this); | |
| 677 | + if (sg2d.alphafill != null) { | |
| 678 | + if (sg2d.clipState == sg2d.CLIP_SHAPE) { | |
| 679 | + sg2d.textpipe = clipColorText; | |
| 680 | + } else { | |
| 681 | + sg2d.textpipe = colorText; | |
| 682 | + } | |
| 683 | + } else { | |
| 684 | + if (sg2d.clipState == sg2d.CLIP_SHAPE) { | |
| 685 | + sg2d.textpipe = clipPaintText; | |
| 686 | + } else { | |
| 687 | + sg2d.textpipe = paintText; | |
| 688 | + } | |
| 689 | + } | |
| 690 | + } else { | |
| 691 | + PixelToShapeConverter converter; | |
| 692 | + if (canRenderParallelograms(sg2d)) { | |
| 693 | + converter = colorViaPgram; | |
| 694 | + // Note that we use the transforming pipe here because it | |
| 695 | + // will examine the shape and possibly perform an optimized | |
| 696 | + // operation if it can be simplified. The simplifications | |
| 697 | + // will be valid for all STROKE and TRANSFORM types. | |
| 698 | + sg2d.shapepipe = colorViaPgram; | |
| 699 | + } else { | |
| 700 | + converter = colorViaShape; | |
| 701 | + sg2d.shapepipe = colorPrimitives; | |
| 702 | + } | |
| 703 | + if (sg2d.transformState >= sg2d.TRANSFORM_TRANSLATESCALE) { | |
| 704 | + sg2d.drawpipe = converter; | |
| 705 | + sg2d.fillpipe = converter; | |
| 706 | + } else { | |
| 707 | + if (sg2d.strokeState != sg2d.STROKE_THIN) { | |
| 708 | + sg2d.drawpipe = converter; | |
| 709 | + } else { | |
| 710 | + sg2d.drawpipe = colorPrimitives; | |
| 711 | + } | |
| 712 | + sg2d.fillpipe = colorPrimitives; | |
| 713 | + } | |
| 714 | + | |
| 715 | + sg2d.textpipe = getTextPipe(sg2d, false /* AA==OFF */); | |
| 716 | + // assert(sg2d.surfaceData == this); | |
| 717 | + } | |
| 718 | + | |
| 719 | + // check for loops | |
| 720 | + if (sg2d.textpipe instanceof LoopBasedPipe || | |
| 721 | + sg2d.shapepipe instanceof LoopBasedPipe || | |
| 722 | + sg2d.fillpipe instanceof LoopBasedPipe || | |
| 723 | + sg2d.drawpipe instanceof LoopBasedPipe || | |
| 724 | + sg2d.imagepipe instanceof LoopBasedPipe) | |
| 725 | + { | |
| 726 | + sg2d.loops = getRenderLoops(sg2d); | |
| 727 | + } | |
| 728 | + } | |
| 729 | + | |
| 730 | + /* Return the text pipe to be used based on the graphics AA hint setting, | |
| 731 | + * and the rest of the graphics state is compatible with these loops. | |
| 732 | + * If the text AA hint is "DEFAULT", then the AA graphics hint requests | |
| 733 | + * the AA text renderer, else it requests the B&W text renderer. | |
| 734 | + */ | |
| 735 | + private TextPipe getTextPipe(SunGraphics2D sg2d, boolean aaHintIsOn) { | |
| 736 | + | |
| 737 | + /* Try to avoid calling getFontInfo() unless its needed to | |
| 738 | + * resolve one of the new AA types. | |
| 739 | + */ | |
| 740 | + switch (sg2d.textAntialiasHint) { | |
| 741 | + case SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT: | |
| 742 | + if (aaHintIsOn) { | |
| 743 | + return aaTextRenderer; | |
| 744 | + } else { | |
| 745 | + return solidTextRenderer; | |
| 746 | + } | |
| 747 | + case SunHints.INTVAL_TEXT_ANTIALIAS_OFF: | |
| 748 | + return solidTextRenderer; | |
| 749 | + | |
| 750 | + case SunHints.INTVAL_TEXT_ANTIALIAS_ON: | |
| 751 | + return aaTextRenderer; | |
| 752 | + | |
| 753 | + default: | |
| 754 | + switch (sg2d.getFontInfo().aaHint) { | |
| 755 | + | |
| 756 | + case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB: | |
| 757 | + case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB: | |
| 758 | + return lcdTextRenderer; | |
| 759 | + | |
| 760 | + case SunHints.INTVAL_TEXT_ANTIALIAS_ON: | |
| 761 | + return aaTextRenderer; | |
| 762 | + | |
| 763 | + case SunHints.INTVAL_TEXT_ANTIALIAS_OFF: | |
| 764 | + return solidTextRenderer; | |
| 765 | + | |
| 766 | + /* This should not be reached as the FontInfo will | |
| 767 | + * always explicitly set its hint value. So whilst | |
| 768 | + * this could be collapsed to returning say just | |
| 769 | + * solidTextRenderer, or even removed, its left | |
| 770 | + * here in case DEFAULT is ever passed in. | |
| 771 | + */ | |
| 772 | + default: | |
| 773 | + if (aaHintIsOn) { | |
| 774 | + return aaTextRenderer; | |
| 775 | + } else { | |
| 776 | + return solidTextRenderer; | |
| 777 | + } | |
| 778 | + } | |
| 779 | + } | |
| 780 | + } | |
| 781 | + | |
| 782 | + private static SurfaceType getPaintSurfaceType(SunGraphics2D sg2d) { | |
| 783 | + switch (sg2d.paintState) { | |
| 784 | + case SunGraphics2D.PAINT_OPAQUECOLOR: | |
| 785 | + return SurfaceType.OpaqueColor; | |
| 786 | + case SunGraphics2D.PAINT_ALPHACOLOR: | |
| 787 | + return SurfaceType.AnyColor; | |
| 788 | + case SunGraphics2D.PAINT_GRADIENT: | |
| 789 | + if (sg2d.paint.getTransparency() == OPAQUE) { | |
| 790 | + return SurfaceType.OpaqueGradientPaint; | |
| 791 | + } else { | |
| 792 | + return SurfaceType.GradientPaint; | |
| 793 | + } | |
| 794 | + case SunGraphics2D.PAINT_LIN_GRADIENT: | |
| 795 | + if (sg2d.paint.getTransparency() == OPAQUE) { | |
| 796 | + return SurfaceType.OpaqueLinearGradientPaint; | |
| 797 | + } else { | |
| 798 | + return SurfaceType.LinearGradientPaint; | |
| 799 | + } | |
| 800 | + case SunGraphics2D.PAINT_RAD_GRADIENT: | |
| 801 | + if (sg2d.paint.getTransparency() == OPAQUE) { | |
| 802 | + return SurfaceType.OpaqueRadialGradientPaint; | |
| 803 | + } else { | |
| 804 | + return SurfaceType.RadialGradientPaint; | |
| 805 | + } | |
| 806 | + case SunGraphics2D.PAINT_TEXTURE: | |
| 807 | + if (sg2d.paint.getTransparency() == OPAQUE) { | |
| 808 | + return SurfaceType.OpaqueTexturePaint; | |
| 809 | + } else { | |
| 810 | + return SurfaceType.TexturePaint; | |
| 811 | + } | |
| 812 | + default: | |
| 813 | + case SunGraphics2D.PAINT_CUSTOM: | |
| 814 | + return SurfaceType.AnyPaint; | |
| 815 | + } | |
| 816 | + } | |
| 817 | + | |
| 818 | + private static CompositeType getFillCompositeType(SunGraphics2D sg2d) { | |
| 819 | + CompositeType compType = sg2d.imageComp; | |
| 820 | + if (sg2d.compositeState == sg2d.COMP_ISCOPY) { | |
| 821 | + if (compType == CompositeType.SrcOverNoEa) { | |
| 822 | + compType = CompositeType.OpaqueSrcOverNoEa; | |
| 823 | + } else { | |
| 824 | + compType = CompositeType.SrcNoEa; | |
| 825 | + } | |
| 826 | + } | |
| 827 | + return compType; | |
| 828 | + } | |
| 829 | + | |
| 830 | + /** | |
| 831 | + * Returns a MaskFill object that can be used on this destination | |
| 832 | + * with the source (paint) and composite types determined by the given | |
| 833 | + * SunGraphics2D, or null if no such MaskFill object can be located. | |
| 834 | + * Subclasses can override this method if they wish to filter other | |
| 835 | + * attributes (such as the hardware capabilities of the destination | |
| 836 | + * surface) before returning a specific MaskFill object. | |
| 837 | + */ | |
| 838 | + protected MaskFill getMaskFill(SunGraphics2D sg2d) { | |
| 839 | + SurfaceType src = getPaintSurfaceType(sg2d); | |
| 840 | + CompositeType comp = getFillCompositeType(sg2d); | |
| 841 | + SurfaceType dst = getSurfaceType(); | |
| 842 | + return MaskFill.getFromCache(src, comp, dst); | |
| 843 | + } | |
| 844 | + | |
| 845 | + private static RenderCache loopcache = new RenderCache(30); | |
| 846 | + | |
| 847 | + /** | |
| 848 | + * Return a RenderLoops object containing all of the basic | |
| 849 | + * GraphicsPrimitive objects for rendering to the destination | |
| 850 | + * surface with the current attributes of the given SunGraphics2D. | |
| 851 | + */ | |
| 852 | + public RenderLoops getRenderLoops(SunGraphics2D sg2d) { | |
| 853 | + SurfaceType src = getPaintSurfaceType(sg2d); | |
| 854 | + CompositeType comp = getFillCompositeType(sg2d); | |
| 855 | + SurfaceType dst = sg2d.getSurfaceData().getSurfaceType(); | |
| 856 | + | |
| 857 | + Object o = loopcache.get(src, comp, dst); | |
| 858 | + if (o != null) { | |
| 859 | + return (RenderLoops) o; | |
| 860 | + } | |
| 861 | + | |
| 862 | + RenderLoops loops = makeRenderLoops(src, comp, dst); | |
| 863 | + loopcache.put(src, comp, dst, loops); | |
| 864 | + return loops; | |
| 865 | + } | |
| 866 | + | |
| 867 | + /** | |
| 868 | + * Construct and return a RenderLoops object containing all of | |
| 869 | + * the basic GraphicsPrimitive objects for rendering to the | |
| 870 | + * destination surface with the given source, destination, and | |
| 871 | + * composite types. | |
| 872 | + */ | |
| 873 | + public static RenderLoops makeRenderLoops(SurfaceType src, | |
| 874 | + CompositeType comp, | |
| 875 | + SurfaceType dst) | |
| 876 | + { | |
| 877 | + RenderLoops loops = new RenderLoops(); | |
| 878 | + loops.drawLineLoop = DrawLine.locate(src, comp, dst); | |
| 879 | + loops.fillRectLoop = FillRect.locate(src, comp, dst); | |
| 880 | + loops.drawRectLoop = DrawRect.locate(src, comp, dst); | |
| 881 | + loops.drawPolygonsLoop = DrawPolygons.locate(src, comp, dst); | |
| 882 | + loops.drawPathLoop = DrawPath.locate(src, comp, dst); | |
| 883 | + loops.fillPathLoop = FillPath.locate(src, comp, dst); | |
| 884 | + loops.fillSpansLoop = FillSpans.locate(src, comp, dst); | |
| 885 | + loops.fillParallelogramLoop = FillParallelogram.locate(src, comp, dst); | |
| 886 | + loops.drawParallelogramLoop = DrawParallelogram.locate(src, comp, dst); | |
| 887 | + loops.drawGlyphListLoop = DrawGlyphList.locate(src, comp, dst); | |
| 888 | + loops.drawGlyphListAALoop = DrawGlyphListAA.locate(src, comp, dst); | |
| 889 | + loops.drawGlyphListLCDLoop = DrawGlyphListLCD.locate(src, comp, dst); | |
| 890 | + /* | |
| 891 | + System.out.println("drawLine: "+loops.drawLineLoop); | |
| 892 | + System.out.println("fillRect: "+loops.fillRectLoop); | |
| 893 | + System.out.println("drawRect: "+loops.drawRectLoop); | |
| 894 | + System.out.println("drawPolygons: "+loops.drawPolygonsLoop); | |
| 895 | + System.out.println("fillSpans: "+loops.fillSpansLoop); | |
| 896 | + System.out.println("drawGlyphList: "+loops.drawGlyphListLoop); | |
| 897 | + System.out.println("drawGlyphListAA: "+loops.drawGlyphListAALoop); | |
| 898 | + System.out.println("drawGlyphListLCD: "+loops.drawGlyphListLCDLoop); | |
| 899 | + */ | |
| 900 | + return loops; | |
| 901 | + } | |
| 902 | + | |
| 903 | + /** | |
| 904 | + * Return the GraphicsConfiguration object that describes this | |
| 905 | + * destination surface. | |
| 906 | + */ | |
| 907 | + public abstract GraphicsConfiguration getDeviceConfiguration(); | |
| 908 | + | |
| 909 | + /** | |
| 910 | + * Return the SurfaceType object that describes the destination | |
| 911 | + * surface. | |
| 912 | + */ | |
| 913 | + public final SurfaceType getSurfaceType() { | |
| 914 | + return surfaceType; | |
| 915 | + } | |
| 916 | + | |
| 917 | + /** | |
| 918 | + * Return the ColorModel for the destination surface. | |
| 919 | + */ | |
| 920 | + public final ColorModel getColorModel() { | |
| 921 | + return colorModel; | |
| 922 | + } | |
| 923 | + | |
| 924 | + /** | |
| 925 | + * Returns the type of this <code>Transparency</code>. | |
| 926 | + * @return the field type of this <code>Transparency</code>, which is | |
| 927 | + * either OPAQUE, BITMASK or TRANSLUCENT. | |
| 928 | + */ | |
| 929 | + public int getTransparency() { | |
| 930 | + return getColorModel().getTransparency(); | |
| 931 | + } | |
| 932 | + | |
| 933 | + /** | |
| 934 | + * Return a readable Raster which contains the pixels for the | |
| 935 | + * specified rectangular region of the destination surface. | |
| 936 | + * The coordinate origin of the returned Raster is the same as | |
| 937 | + * the device space origin of the destination surface. | |
| 938 | + * In some cases the returned Raster might also be writeable. | |
| 939 | + * In most cases, the returned Raster might contain more pixels | |
| 940 | + * than requested. | |
| 941 | + * | |
| 942 | + * @see useTightBBoxes | |
| 943 | + */ | |
| 944 | + public abstract Raster getRaster(int x, int y, int w, int h); | |
| 945 | + | |
| 946 | + /** | |
| 947 | + * Does the pixel accessibility of the destination surface | |
| 948 | + * suggest that rendering algorithms might want to take | |
| 949 | + * extra time to calculate a more accurate bounding box for | |
| 950 | + * the operation being performed? | |
| 951 | + * The typical case when this will be true is when a copy of | |
| 952 | + * the pixels has to be made when doing a getRaster. The | |
| 953 | + * fewer pixels copied, the faster the operation will go. | |
| 954 | + * | |
| 955 | + * @see getRaster | |
| 956 | + */ | |
| 957 | + public boolean useTightBBoxes() { | |
| 958 | + // Note: The native equivalent would trigger on VISIBLE_TO_NATIVE | |
| 959 | + // REMIND: This is not used - should be obsoleted maybe | |
| 960 | + return true; | |
| 961 | + } | |
| 962 | + | |
| 963 | + /** | |
| 964 | + * Returns the pixel data for the specified Argb value packed | |
| 965 | + * into an integer for easy storage and conveyance. | |
| 966 | + */ | |
| 967 | + public int pixelFor(int rgb) { | |
| 968 | + return surfaceType.pixelFor(rgb, colorModel); | |
| 969 | + } | |
| 970 | + | |
| 971 | + /** | |
| 972 | + * Returns the pixel data for the specified color packed into an | |
| 973 | + * integer for easy storage and conveyance. | |
| 974 | + * | |
| 975 | + * This method will use the getRGB() method of the Color object | |
| 976 | + * and defer to the pixelFor(int rgb) method if not overridden. | |
| 977 | + * | |
| 978 | + * For now this is a convenience function, but for cases where | |
| 979 | + * the highest quality color conversion is requested, this method | |
| 980 | + * should be overridden in those cases so that a more direct | |
| 981 | + * conversion of the color to the destination color space | |
| 982 | + * can be done using the additional information in the Color | |
| 983 | + * object. | |
| 984 | + */ | |
| 985 | + public int pixelFor(Color c) { | |
| 986 | + return pixelFor(c.getRGB()); | |
| 987 | + } | |
| 988 | + | |
| 989 | + /** | |
| 990 | + * Returns the Argb representation for the specified integer value | |
| 991 | + * which is packed in the format of the associated ColorModel. | |
| 992 | + */ | |
| 993 | + public int rgbFor(int pixel) { | |
| 994 | + return surfaceType.rgbFor(pixel, colorModel); | |
| 995 | + } | |
| 996 | + | |
| 997 | + /** | |
| 998 | + * Returns the bounds of the destination surface. | |
| 999 | + */ | |
| 1000 | + public abstract Rectangle getBounds(); | |
| 1001 | + | |
| 1002 | + static java.security.Permission compPermission; | |
| 1003 | + | |
| 1004 | + /** | |
| 1005 | + * Performs Security Permissions checks to see if a Custom | |
| 1006 | + * Composite object should be allowed access to the pixels | |
| 1007 | + * of this surface. | |
| 1008 | + */ | |
| 1009 | + protected void checkCustomComposite() { | |
| 1010 | + SecurityManager sm = System.getSecurityManager(); | |
| 1011 | + if (sm != null) { | |
| 1012 | + if (compPermission == null) { | |
| 1013 | + compPermission = | |
| 1014 | + new java.awt.AWTPermission("readDisplayPixels"); | |
| 1015 | + } | |
| 1016 | + sm.checkPermission(compPermission); | |
| 1017 | + } | |
| 1018 | + } | |
| 1019 | + | |
| 1020 | + /** | |
| 1021 | + * Fetches private field IndexColorModel.allgrayopaque | |
| 1022 | + * which is true when all palette entries in the color | |
| 1023 | + * model are gray and opaque. | |
| 1024 | + */ | |
| 1025 | + protected static native boolean isOpaqueGray(IndexColorModel icm); | |
| 1026 | + | |
| 1027 | + /** | |
| 1028 | + * For our purposes null and NullSurfaceData are the same as | |
| 1029 | + * they represent a disposed surface. | |
| 1030 | + */ | |
| 1031 | + public static boolean isNull(SurfaceData sd) { | |
| 1032 | + if (sd == null || sd == NullSurfaceData.theInstance) { | |
| 1033 | + return true; | |
| 1034 | + } | |
| 1035 | + return false; | |
| 1036 | + } | |
| 1037 | + | |
| 1038 | + /** | |
| 1039 | + * Performs a copyarea within this surface. Returns | |
| 1040 | + * false if there is no algorithm to perform the copyarea | |
| 1041 | + * given the current settings of the SunGraphics2D. | |
| 1042 | + */ | |
| 1043 | + public boolean copyArea(SunGraphics2D sg2d, | |
| 1044 | + int x, int y, int w, int h, int dx, int dy) | |
| 1045 | + { | |
| 1046 | + return false; | |
| 1047 | + } | |
| 1048 | + | |
| 1049 | + /** | |
| 1050 | + * Synchronously releases resources associated with this surface. | |
| 1051 | + */ | |
| 1052 | + public void flush() {} | |
| 1053 | + | |
| 1054 | + /** | |
| 1055 | + * Returns destination associated with this SurfaceData. This could be | |
| 1056 | + * either an Image or a Component; subclasses of SurfaceData are | |
| 1057 | + * responsible for returning the appropriate object. | |
| 1058 | + */ | |
| 1059 | + public abstract Object getDestination(); | |
| 1060 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,528 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d; | |
| 27 | + | |
| 28 | +import java.awt.Color; | |
| 29 | +import java.awt.Rectangle; | |
| 30 | +import java.awt.AlphaComposite; | |
| 31 | +import java.awt.GraphicsEnvironment; | |
| 32 | + | |
| 33 | +import sun.awt.DisplayChangedListener; | |
| 34 | +import sun.java2d.StateTrackable.State; | |
| 35 | +import sun.java2d.loops.CompositeType; | |
| 36 | +import sun.java2d.loops.SurfaceType; | |
| 37 | +import sun.java2d.loops.Blit; | |
| 38 | +import sun.java2d.loops.BlitBg; | |
| 39 | +import sun.awt.image.SurfaceManager; | |
| 40 | +import sun.awt.image.SurfaceManager.FlushableCacheData; | |
| 41 | + | |
| 42 | +import java.security.AccessController; | |
| 43 | +import sun.security.action.GetPropertyAction; | |
| 44 | + | |
| 45 | +/** | |
| 46 | + * The proxy class encapsulates the logic for managing alternate | |
| 47 | + * SurfaceData representations of a primary SurfaceData. | |
| 48 | + * The main class will handle tracking the state changes of the | |
| 49 | + * primary SurfaceData and updating the associated SurfaceData | |
| 50 | + * proxy variants. | |
| 51 | + * <p> | |
| 52 | + * Subclasses have 2 main responsibilities: | |
| 53 | + * <ul> | |
| 54 | + * <li> Override the isSupportedOperation() method to determine if | |
| 55 | + * a given operation can be accelerated with a given source | |
| 56 | + * SurfaceData | |
| 57 | + * <li> Override the validateSurfaceData() method to create or update | |
| 58 | + * a given accelerated surface to hold the pixels for the indicated | |
| 59 | + * source SurfaceData | |
| 60 | + * </ul> | |
| 61 | + * If necessary, a subclass may also override the updateSurfaceData | |
| 62 | + * method to transfer the pixels to the accelerated surface. | |
| 63 | + * By default the parent class will transfer the pixels using a | |
| 64 | + * standard Blit operation between the two SurfaceData objects. | |
| 65 | + */ | |
| 66 | +public abstract class SurfaceDataProxy | |
| 67 | + implements DisplayChangedListener, SurfaceManager.FlushableCacheData | |
| 68 | +{ | |
| 69 | + private static boolean cachingAllowed; | |
| 70 | + private static int defaultThreshold; | |
| 71 | + | |
| 72 | + static { | |
| 73 | + cachingAllowed = true; | |
| 74 | + String manimg = (String)AccessController.doPrivileged( | |
| 75 | + new GetPropertyAction("sun.java2d.managedimages")); | |
| 76 | + if (manimg != null && manimg.equals("false")) { | |
| 77 | + cachingAllowed = false; | |
| 78 | + System.out.println("Disabling managed images"); | |
| 79 | + } | |
| 80 | + | |
| 81 | + defaultThreshold = 1; | |
| 82 | + String num = (String)AccessController.doPrivileged( | |
| 83 | + new GetPropertyAction("sun.java2d.accthreshold")); | |
| 84 | + if (num != null) { | |
| 85 | + try { | |
| 86 | + int parsed = Integer.parseInt(num); | |
| 87 | + if (parsed >= 0) { | |
| 88 | + defaultThreshold = parsed; | |
| 89 | + System.out.println("New Default Acceleration Threshold: " + | |
| 90 | + defaultThreshold); | |
| 91 | + } | |
| 92 | + } catch (NumberFormatException e) { | |
| 93 | + System.err.println("Error setting new threshold:" + e); | |
| 94 | + } | |
| 95 | + } | |
| 96 | + } | |
| 97 | + | |
| 98 | + public static boolean isCachingAllowed() { | |
| 99 | + return cachingAllowed; | |
| 100 | + } | |
| 101 | + | |
| 102 | + /** | |
| 103 | + * Determine if an alternate form for the srcData is needed | |
| 104 | + * and appropriate from the given operational parameters. | |
| 105 | + */ | |
| 106 | + public abstract boolean isSupportedOperation(SurfaceData srcData, | |
| 107 | + int txtype, | |
| 108 | + CompositeType comp, | |
| 109 | + Color bgColor); | |
| 110 | + | |
| 111 | + /** | |
| 112 | + * Construct an alternate form of the given SurfaceData. | |
| 113 | + * The contents of the returned SurfaceData may be undefined | |
| 114 | + * since the calling code will take care of updating the | |
| 115 | + * contents with a subsequent call to updateSurfaceData. | |
| 116 | + * <p> | |
| 117 | + * If the method returns null then there was a problem with | |
| 118 | + * allocating the accelerated surface. The getRetryTracker() | |
| 119 | + * method will be called to track when to attempt another | |
| 120 | + * revalidation. | |
| 121 | + */ | |
| 122 | + public abstract SurfaceData validateSurfaceData(SurfaceData srcData, | |
| 123 | + SurfaceData cachedData, | |
| 124 | + int w, int h); | |
| 125 | + | |
| 126 | + /** | |
| 127 | + * If the subclass is unable to validate or create a cached | |
| 128 | + * SurfaceData then this method will be used to get a | |
| 129 | + * StateTracker object that will indicate when to attempt | |
| 130 | + * to validate the surface again. Subclasses may return | |
| 131 | + * trackers which count down an ever increasing threshold | |
| 132 | + * to provide hysteresis on creating surfaces during low | |
| 133 | + * memory conditions. The default implementation just waits | |
| 134 | + * another "threshold" number of accesses before trying again. | |
| 135 | + */ | |
| 136 | + public StateTracker getRetryTracker(SurfaceData srcData) { | |
| 137 | + return new CountdownTracker(threshold); | |
| 138 | + } | |
| 139 | + | |
| 140 | + public static class CountdownTracker implements StateTracker { | |
| 141 | + private int countdown; | |
| 142 | + | |
| 143 | + public CountdownTracker(int threshold) { | |
| 144 | + this.countdown = threshold; | |
| 145 | + } | |
| 146 | + | |
| 147 | + public synchronized boolean isCurrent() { | |
| 148 | + return (--countdown >= 0); | |
| 149 | + } | |
| 150 | + } | |
| 151 | + | |
| 152 | + /** | |
| 153 | + * This instance is for cases where a caching implementation | |
| 154 | + * determines that a particular source image will never need | |
| 155 | + * to be cached - either the source SurfaceData was of an | |
| 156 | + * incompatible type, or it was in an UNTRACKABLE state or | |
| 157 | + * some other factor is discovered that permanently prevents | |
| 158 | + * acceleration or caching. | |
| 159 | + * This class optimally implements NOP variants of all necessary | |
| 160 | + * methods to avoid caching with a minimum of fuss. | |
| 161 | + */ | |
| 162 | + public static SurfaceDataProxy UNCACHED = new SurfaceDataProxy(0) { | |
| 163 | + @Override | |
| 164 | + public boolean isAccelerated() { | |
| 165 | + return false; | |
| 166 | + } | |
| 167 | + | |
| 168 | + @Override | |
| 169 | + public boolean isSupportedOperation(SurfaceData srcData, | |
| 170 | + int txtype, | |
| 171 | + CompositeType comp, | |
| 172 | + Color bgColor) | |
| 173 | + { | |
| 174 | + return false; | |
| 175 | + } | |
| 176 | + | |
| 177 | + @Override | |
| 178 | + public SurfaceData validateSurfaceData(SurfaceData srcData, | |
| 179 | + SurfaceData cachedData, | |
| 180 | + int w, int h) | |
| 181 | + { | |
| 182 | + throw new InternalError("UNCACHED should never validate SDs"); | |
| 183 | + } | |
| 184 | + | |
| 185 | + @Override | |
| 186 | + public SurfaceData replaceData(SurfaceData srcData, | |
| 187 | + int txtype, | |
| 188 | + CompositeType comp, | |
| 189 | + Color bgColor) | |
| 190 | + { | |
| 191 | + // Not necessary to override this, but doing so is faster | |
| 192 | + return srcData; | |
| 193 | + } | |
| 194 | + }; | |
| 195 | + | |
| 196 | + // The number of attempts to copy from a STABLE source before | |
| 197 | + // a cached copy is created or updated. | |
| 198 | + private int threshold; | |
| 199 | + | |
| 200 | + /* | |
| 201 | + * Source tracking data | |
| 202 | + * | |
| 203 | + * Every time that srcTracker is out of date we will reset numtries | |
| 204 | + * to threshold and set the cacheTracker to one that is non-current. | |
| 205 | + * numtries will then count down to 0 at which point the cacheTracker | |
| 206 | + * will remind us that we need to update the cachedSD before we can | |
| 207 | + * use it. | |
| 208 | + * | |
| 209 | + * Note that since these fields interrelate we should synchronize | |
| 210 | + * whenever we update them, but it should be OK to read them | |
| 211 | + * without synchronization. | |
| 212 | + */ | |
| 213 | + private StateTracker srcTracker; | |
| 214 | + private int numtries; | |
| 215 | + | |
| 216 | + /* | |
| 217 | + * Cached data | |
| 218 | + * | |
| 219 | + * We cache a SurfaceData created by the subclass in cachedSD and | |
| 220 | + * track its state (isValid and !surfaceLost) in cacheTracker. | |
| 221 | + * | |
| 222 | + * Also, when we want to note that cachedSD needs to be updated | |
| 223 | + * we replace the cacheTracker with a NEVER_CURRENT tracker which | |
| 224 | + * will cause us to try to revalidate and update the surface on | |
| 225 | + * next use. | |
| 226 | + */ | |
| 227 | + private SurfaceData cachedSD; | |
| 228 | + private StateTracker cacheTracker; | |
| 229 | + | |
| 230 | + /* | |
| 231 | + * Are we still the best object to control caching of data | |
| 232 | + * for the source image? | |
| 233 | + */ | |
| 234 | + private boolean valid; | |
| 235 | + | |
| 236 | + /** | |
| 237 | + * Create a SurfaceData proxy manager that attempts to create | |
| 238 | + * and cache a variant copy of the source SurfaceData after | |
| 239 | + * the default threshold number of attempts to copy from the | |
| 240 | + * STABLE source. | |
| 241 | + */ | |
| 242 | + public SurfaceDataProxy() { | |
| 243 | + this(defaultThreshold); | |
| 244 | + } | |
| 245 | + | |
| 246 | + /** | |
| 247 | + * Create a SurfaceData proxy manager that attempts to create | |
| 248 | + * and cache a variant copy of the source SurfaceData after | |
| 249 | + * the specified threshold number of attempts to copy from | |
| 250 | + * the STABLE source. | |
| 251 | + */ | |
| 252 | + public SurfaceDataProxy(int threshold) { | |
| 253 | + this.threshold = threshold; | |
| 254 | + | |
| 255 | + this.srcTracker = StateTracker.NEVER_CURRENT; | |
| 256 | + // numtries will be reset on first use | |
| 257 | + this.cacheTracker = StateTracker.NEVER_CURRENT; | |
| 258 | + | |
| 259 | + this.valid = true; | |
| 260 | + } | |
| 261 | + | |
| 262 | + /** | |
| 263 | + * Returns true iff this SurfaceData proxy is still the best | |
| 264 | + * way to control caching of the given source on the given | |
| 265 | + * destination. | |
| 266 | + */ | |
| 267 | + public boolean isValid() { | |
| 268 | + return valid; | |
| 269 | + } | |
| 270 | + | |
| 271 | + /** | |
| 272 | + * Sets the valid state to false so that the next time this | |
| 273 | + * proxy is fetched to generate a replacement SurfaceData, | |
| 274 | + * the code in SurfaceData knows to replace the proxy first. | |
| 275 | + */ | |
| 276 | + public void invalidate() { | |
| 277 | + this.valid = false; | |
| 278 | + } | |
| 279 | + | |
| 280 | + /** | |
| 281 | + * Flush all cached resources as per the FlushableCacheData interface. | |
| 282 | + * The deaccelerated parameter indicates if the flush is | |
| 283 | + * happening because the associated surface is no longer | |
| 284 | + * being accelerated (for instance the acceleration priority | |
| 285 | + * is set below the threshold needed for acceleration). | |
| 286 | + * Returns a boolean that indicates if the cached object is | |
| 287 | + * no longer needed and should be removed from the cache. | |
| 288 | + */ | |
| 289 | + public boolean flush(boolean deaccelerated) { | |
| 290 | + if (deaccelerated) { | |
| 291 | + invalidate(); | |
| 292 | + } | |
| 293 | + flush(); | |
| 294 | + return !isValid(); | |
| 295 | + } | |
| 296 | + | |
| 297 | + /** | |
| 298 | + * Actively flushes (drops and invalidates) the cached surface | |
| 299 | + * so that it can be reclaimed quickly. | |
| 300 | + */ | |
| 301 | + public synchronized void flush() { | |
| 302 | + SurfaceData csd = this.cachedSD; | |
| 303 | + this.cachedSD = null; | |
| 304 | + this.cacheTracker = StateTracker.NEVER_CURRENT; | |
| 305 | + if (csd != null) { | |
| 306 | + csd.flush(); | |
| 307 | + } | |
| 308 | + } | |
| 309 | + | |
| 310 | + /** | |
| 311 | + * Returns true iff this SurfaceData proxy is still valid | |
| 312 | + * and if it has a currently cached replacement that is also | |
| 313 | + * valid and current. | |
| 314 | + */ | |
| 315 | + public boolean isAccelerated() { | |
| 316 | + return (isValid() && | |
| 317 | + srcTracker.isCurrent() && | |
| 318 | + cacheTracker.isCurrent()); | |
| 319 | + } | |
| 320 | + | |
| 321 | + /** | |
| 322 | + * This method should be called from subclasses which create | |
| 323 | + * cached SurfaceData objects that depend on the current | |
| 324 | + * properties of the display. | |
| 325 | + */ | |
| 326 | + protected void activateDisplayListener() { | |
| 327 | + GraphicsEnvironment ge = | |
| 328 | + GraphicsEnvironment.getLocalGraphicsEnvironment(); | |
| 329 | + // We could have a HeadlessGE at this point, so double-check before | |
| 330 | + // assuming anything. | |
| 331 | + // Also, no point in listening to display change events if | |
| 332 | + // the image is never going to be accelerated. | |
| 333 | + if (ge instanceof SunGraphicsEnvironment) { | |
| 334 | + ((SunGraphicsEnvironment)ge).addDisplayChangedListener(this); | |
| 335 | + } | |
| 336 | + } | |
| 337 | + | |
| 338 | + /** | |
| 339 | + * Invoked when the display mode has changed. | |
| 340 | + * This method will invalidate and drop the internal cachedSD object. | |
| 341 | + */ | |
| 342 | + public void displayChanged() { | |
| 343 | + flush(); | |
| 344 | + } | |
| 345 | + | |
| 346 | + /** | |
| 347 | + * Invoked when the palette has changed. | |
| 348 | + */ | |
| 349 | + public void paletteChanged() { | |
| 350 | + // We could potentially get away with just resetting cacheTracker | |
| 351 | + // here but there is a small window of vulnerability in the | |
| 352 | + // replaceData method where we could be just finished with | |
| 353 | + // updating the cachedSD when this method is called and even | |
| 354 | + // though we set a non-current cacheTracker here it will then | |
| 355 | + // immediately get set to a current one by the thread that is | |
| 356 | + // updating the cachedSD. It is safer to just replace the | |
| 357 | + // srcTracker with a non-current version that will trigger a | |
| 358 | + // full update cycle the next time this proxy is used. | |
| 359 | + // The downside is having to go through a full threshold count | |
| 360 | + // before we can update and use our cache again, but palette | |
| 361 | + // changes should be relatively rare... | |
| 362 | + this.srcTracker = StateTracker.NEVER_CURRENT; | |
| 363 | + } | |
| 364 | + | |
| 365 | + /** | |
| 366 | + * This method attempts to replace the srcData with a cached version. | |
| 367 | + * It relies on the subclass to determine if the cached version will | |
| 368 | + * be useful given the operational parameters. | |
| 369 | + * This method checks any preexisting cached copy for being "up to date" | |
| 370 | + * and tries to update it if it is stale or non-existant and the | |
| 371 | + * appropriate number of accesses have occured since it last was stale. | |
| 372 | + * <p> | |
| 373 | + * An outline of the process is as follows: | |
| 374 | + * <ol> | |
| 375 | + * <li> Check the operational parameters (txtype, comp, bgColor) | |
| 376 | + * to make sure that the operation is supported. Return the | |
| 377 | + * original SurfaceData if the operation cannot be accelerated. | |
| 378 | + * <li> Check the tracker for the source surface to see if it has | |
| 379 | + * remained stable since it was last cached. Update the state | |
| 380 | + * variables to cause both a threshold countdown and an update | |
| 381 | + * of the cached copy if it is not. (Setting cacheTracker to | |
| 382 | + * NEVER_CURRENT effectively marks it as "needing to be updated".) | |
| 383 | + * <li> Check the tracker for the cached copy to see if is still | |
| 384 | + * valid and up to date. Note that the cacheTracker may be | |
| 385 | + * non-current if either something happened to the cached copy | |
| 386 | + * (eg. surfaceLost) or if the source was out of date and the | |
| 387 | + * cacheTracker was set to NEVER_CURRENT to force an update. | |
| 388 | + * Decrement the countdown and copy the source to the cache | |
| 389 | + * as necessary and then update the variables to show that | |
| 390 | + * the cached copy is stable. | |
| 391 | + * </ol> | |
| 392 | + */ | |
| 393 | + public SurfaceData replaceData(SurfaceData srcData, | |
| 394 | + int txtype, | |
| 395 | + CompositeType comp, | |
| 396 | + Color bgColor) | |
| 397 | + { | |
| 398 | + if (isSupportedOperation(srcData, txtype, comp, bgColor)) { | |
| 399 | + // First deal with tracking the source. | |
| 400 | + if (!srcTracker.isCurrent()) { | |
| 401 | + synchronized (this) { | |
| 402 | + this.numtries = threshold; | |
| 403 | + this.srcTracker = srcData.getStateTracker(); | |
| 404 | + this.cacheTracker = StateTracker.NEVER_CURRENT; | |
| 405 | + } | |
| 406 | + | |
| 407 | + if (!srcTracker.isCurrent()) { | |
| 408 | + // Dynamic or Untrackable (or a very recent modification) | |
| 409 | + if (srcData.getState() == State.UNTRACKABLE) { | |
| 410 | + // UNTRACKABLE means we can never cache again. | |
| 411 | + | |
| 412 | + // Invalidate so we get replaced next time we are used | |
| 413 | + // (presumably with an UNCACHED proxy). | |
| 414 | + invalidate(); | |
| 415 | + | |
| 416 | + // Aggressively drop our reference to the cachedSD | |
| 417 | + // in case this proxy is not consulted again (and | |
| 418 | + // thus replaced) for a long time. | |
| 419 | + flush(); | |
| 420 | + } | |
| 421 | + return srcData; | |
| 422 | + } | |
| 423 | + } | |
| 424 | + | |
| 425 | + // Then deal with checking the validity of the cached SurfaceData | |
| 426 | + SurfaceData csd = this.cachedSD; | |
| 427 | + if (!cacheTracker.isCurrent()) { | |
| 428 | + // Next make sure the dust has settled | |
| 429 | + synchronized (this) { | |
| 430 | + if (numtries > 0) { | |
| 431 | + --numtries; | |
| 432 | + return srcData; | |
| 433 | + } | |
| 434 | + } | |
| 435 | + | |
| 436 | + Rectangle r = srcData.getBounds(); | |
| 437 | + int w = r.width; | |
| 438 | + int h = r.height; | |
| 439 | + | |
| 440 | + // Snapshot the tracker in case it changes while | |
| 441 | + // we are updating the cached SD... | |
| 442 | + StateTracker curTracker = srcTracker; | |
| 443 | + | |
| 444 | + csd = validateSurfaceData(srcData, csd, w, h); | |
| 445 | + if (csd == null) { | |
| 446 | + synchronized (this) { | |
| 447 | + if (curTracker == srcTracker) { | |
| 448 | + this.cacheTracker = getRetryTracker(srcData); | |
| 449 | + this.cachedSD = null; | |
| 450 | + } | |
| 451 | + } | |
| 452 | + return srcData; | |
| 453 | + } | |
| 454 | + | |
| 455 | + updateSurfaceData(srcData, csd, w, h); | |
| 456 | + if (!csd.isValid()) { | |
| 457 | + return srcData; | |
| 458 | + } | |
| 459 | + | |
| 460 | + synchronized (this) { | |
| 461 | + // We only reset these variables if the tracker from | |
| 462 | + // before the surface update is still in use and current | |
| 463 | + // Note that we must use a srcTracker that was fetched | |
| 464 | + // from before the update process to make sure that we | |
| 465 | + // do not lose some pixel changes in the shuffle. | |
| 466 | + if (curTracker == srcTracker && curTracker.isCurrent()) { | |
| 467 | + this.cacheTracker = csd.getStateTracker(); | |
| 468 | + this.cachedSD = csd; | |
| 469 | + } | |
| 470 | + } | |
| 471 | + } | |
| 472 | + | |
| 473 | + if (csd != null) { | |
| 474 | + return csd; | |
| 475 | + } | |
| 476 | + } | |
| 477 | + | |
| 478 | + return srcData; | |
| 479 | + } | |
| 480 | + | |
| 481 | + /** | |
| 482 | + * This is the default implementation for updating the cached | |
| 483 | + * SurfaceData from the source (primary) SurfaceData. | |
| 484 | + * A simple Blit is used to copy the pixels from the source to | |
| 485 | + * the destination SurfaceData. | |
| 486 | + * A subclass can override this implementation if a more complex | |
| 487 | + * operation is required to update its cached copies. | |
| 488 | + */ | |
| 489 | + public void updateSurfaceData(SurfaceData srcData, | |
| 490 | + SurfaceData dstData, | |
| 491 | + int w, int h) | |
| 492 | + { | |
| 493 | + SurfaceType srcType = srcData.getSurfaceType(); | |
| 494 | + SurfaceType dstType = dstData.getSurfaceType(); | |
| 495 | + Blit blit = Blit.getFromCache(srcType, | |
| 496 | + CompositeType.SrcNoEa, | |
| 497 | + dstType); | |
| 498 | + blit.Blit(srcData, dstData, | |
| 499 | + AlphaComposite.Src, null, | |
| 500 | + 0, 0, 0, 0, w, h); | |
| 501 | + dstData.markDirty(); | |
| 502 | + } | |
| 503 | + | |
| 504 | + /** | |
| 505 | + * This is an alternate implementation for updating the cached | |
| 506 | + * SurfaceData from the source (primary) SurfaceData using a | |
| 507 | + * background color for transparent pixels. | |
| 508 | + * A simple BlitBg is used to copy the pixels from the source to | |
| 509 | + * the destination SurfaceData with the specified bgColor. | |
| 510 | + * A subclass can override the normal updateSurfaceData method | |
| 511 | + * and call this implementation instead if it wants to use color | |
| 512 | + * keying for bitmask images. | |
| 513 | + */ | |
| 514 | + public void updateSurfaceDataBg(SurfaceData srcData, | |
| 515 | + SurfaceData dstData, | |
| 516 | + int w, int h, Color bgColor) | |
| 517 | + { | |
| 518 | + SurfaceType srcType = srcData.getSurfaceType(); | |
| 519 | + SurfaceType dstType = dstData.getSurfaceType(); | |
| 520 | + BlitBg blitbg = BlitBg.getFromCache(srcType, | |
| 521 | + CompositeType.SrcNoEa, | |
| 522 | + dstType); | |
| 523 | + blitbg.BlitBg(srcData, dstData, | |
| 524 | + AlphaComposite.Src, null, bgColor.getRGB(), | |
| 525 | + 0, 0, 0, 0, w, h); | |
| 526 | + dstData.markDirty(); | |
| 527 | + } | |
| 528 | +} | |
Binary file not shown.
| @@ -0,0 +1,91 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d; | |
| 27 | + | |
| 28 | +import sun.awt.image.SunVolatileImage; | |
| 29 | +import sun.awt.image.VolatileSurfaceManager; | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * This factory creates platform specific VolatileSurfaceManager | |
| 33 | + * implementations. | |
| 34 | + * | |
| 35 | + * There are two platform specific SurfaceManagerFactories in OpenJDK, | |
| 36 | + * UnixSurfaceManagerFactory and WindowsSurfaceManagerFactory. | |
| 37 | + * The actually used SurfaceManagerFactory is set by the respective platform | |
| 38 | + * GraphicsEnvironment implementations in the static initializer. | |
| 39 | + */ | |
| 40 | +public abstract class SurfaceManagerFactory { | |
| 41 | + | |
| 42 | + /** | |
| 43 | + * The single shared instance. | |
| 44 | + */ | |
| 45 | + private static SurfaceManagerFactory instance; | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * Returns the surface manager factory instance. This returns a factory | |
| 49 | + * that has been set by {@link #setInstance(SurfaceManagerFactory)}. | |
| 50 | + * | |
| 51 | + * @return the surface manager factory | |
| 52 | + */ | |
| 53 | + public synchronized static SurfaceManagerFactory getInstance() { | |
| 54 | + | |
| 55 | + if (instance == null) { | |
| 56 | + throw new IllegalStateException("No SurfaceManagerFactory set."); | |
| 57 | + } | |
| 58 | + return instance; | |
| 59 | + } | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * Sets the surface manager factory. This may only be called once, and it | |
| 63 | + * may not be set back to {@code null} when the factory is already | |
| 64 | + * instantiated. | |
| 65 | + * | |
| 66 | + * @param factory the factory to set | |
| 67 | + */ | |
| 68 | + public synchronized static void setInstance(SurfaceManagerFactory factory) { | |
| 69 | + | |
| 70 | + if (factory == null) { | |
| 71 | + // We don't want to allow setting this to null at any time. | |
| 72 | + throw new IllegalArgumentException("factory must be non-null"); | |
| 73 | + } | |
| 74 | + | |
| 75 | + if (instance != null) { | |
| 76 | + // We don't want to re-set the instance at any time. | |
| 77 | + throw new IllegalStateException("The surface manager factory is already initialized"); | |
| 78 | + } | |
| 79 | + | |
| 80 | + instance = factory; | |
| 81 | + } | |
| 82 | + | |
| 83 | + /** | |
| 84 | + * Creates a new instance of a VolatileSurfaceManager given any | |
| 85 | + * arbitrary SunVolatileImage. An optional context Object can be supplied | |
| 86 | + * as a way for the caller to pass pipeline-specific context data to | |
| 87 | + * the VolatileSurfaceManager (such as a backbuffer handle, for example). | |
| 88 | + */ | |
| 89 | + public abstract VolatileSurfaceManager | |
| 90 | + createVolatileManager(SunVolatileImage image, Object context); | |
| 91 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,170 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.cmm; | |
| 27 | + | |
| 28 | +import java.awt.color.ColorSpace; | |
| 29 | +import java.awt.color.ICC_Profile; | |
| 30 | +import java.awt.color.CMMException; | |
| 31 | +import java.awt.image.BufferedImage; | |
| 32 | +import java.awt.image.Raster; | |
| 33 | +import java.awt.image.WritableRaster; | |
| 34 | +import java.security.AccessController; | |
| 35 | +import java.security.PrivilegedAction; | |
| 36 | +import sun.security.action.GetPropertyAction; | |
| 37 | +import java.util.ServiceLoader; | |
| 38 | + | |
| 39 | +public class CMSManager { | |
| 40 | + public static ColorSpace GRAYspace; // These two fields allow access | |
| 41 | + public static ColorSpace LINEAR_RGBspace; // to java.awt.color.ColorSpace | |
| 42 | + // private fields from other | |
| 43 | + // packages. The fields are set | |
| 44 | + // by java.awt.color.ColorSpace | |
| 45 | + // and read by | |
| 46 | + // java.awt.image.ColorModel. | |
| 47 | + | |
| 48 | + private static PCMM cmmImpl = null; | |
| 49 | + | |
| 50 | + public static synchronized PCMM getModule() { | |
| 51 | + if (cmmImpl != null) { | |
| 52 | + return cmmImpl; | |
| 53 | + } | |
| 54 | + | |
| 55 | + cmmImpl = (PCMM)AccessController.doPrivileged(new PrivilegedAction() { | |
| 56 | + public Object run() { | |
| 57 | + String cmmClass = System.getProperty( | |
| 58 | + "sun.java2d.cmm", "sun.java2d.cmm.kcms.CMM"); | |
| 59 | + | |
| 60 | + ServiceLoader<PCMM> cmmLoader | |
| 61 | + = ServiceLoader.loadInstalled(PCMM.class); | |
| 62 | + | |
| 63 | + PCMM service = null; | |
| 64 | + | |
| 65 | + for (PCMM cmm : cmmLoader) { | |
| 66 | + service = cmm; | |
| 67 | + if (cmm.getClass().getName().equals(cmmClass)) { | |
| 68 | + break; | |
| 69 | + } | |
| 70 | + } | |
| 71 | + return service; | |
| 72 | + } | |
| 73 | + }); | |
| 74 | + | |
| 75 | + if (cmmImpl == null) { | |
| 76 | + throw new CMMException("Cannot initialize Color Management System."+ | |
| 77 | + "No CM module found"); | |
| 78 | + } | |
| 79 | + | |
| 80 | + GetPropertyAction gpa = new GetPropertyAction("sun.java2d.cmm.trace"); | |
| 81 | + String cmmTrace = (String)AccessController.doPrivileged(gpa); | |
| 82 | + if (cmmTrace != null) { | |
| 83 | + cmmImpl = new CMMTracer(cmmImpl); | |
| 84 | + } | |
| 85 | + | |
| 86 | + return cmmImpl; | |
| 87 | + } | |
| 88 | + | |
| 89 | + /* CMM trace routines */ | |
| 90 | + | |
| 91 | + public static class CMMTracer implements PCMM { | |
| 92 | + PCMM tcmm; | |
| 93 | + String cName ; | |
| 94 | + | |
| 95 | + public CMMTracer(PCMM tcmm) { | |
| 96 | + this.tcmm = tcmm; | |
| 97 | + cName = tcmm.getClass().getName(); | |
| 98 | + } | |
| 99 | + | |
| 100 | + public long loadProfile(byte[] data) { | |
| 101 | + System.err.print(cName + ".loadProfile"); | |
| 102 | + long profileID = tcmm.loadProfile(data); | |
| 103 | + System.err.printf("(ID=%x)\n", profileID); | |
| 104 | + return profileID; | |
| 105 | + } | |
| 106 | + | |
| 107 | + public void freeProfile(long profileID) { | |
| 108 | + System.err.printf(cName + ".freeProfile(ID=%x)\n", profileID); | |
| 109 | + tcmm.freeProfile(profileID); | |
| 110 | + } | |
| 111 | + | |
| 112 | + public int getProfileSize(long profileID) { | |
| 113 | + System.err.print(cName + ".getProfileSize(ID=" + profileID + ")"); | |
| 114 | + int size = tcmm.getProfileSize(profileID); | |
| 115 | + System.err.println("=" + size); | |
| 116 | + return size; | |
| 117 | + } | |
| 118 | + | |
| 119 | + public void getProfileData(long profileID, byte[] data) { | |
| 120 | + System.err.print(cName + ".getProfileData(ID=" + profileID + ") "); | |
| 121 | + System.err.println("requested " + data.length + " byte(s)"); | |
| 122 | + tcmm.getProfileData(profileID, data); | |
| 123 | + } | |
| 124 | + | |
| 125 | + public int getTagSize(long profileID, int tagSignature) { | |
| 126 | + System.err.printf(cName + ".getTagSize(ID=%x, TagSig=%s)", | |
| 127 | + profileID, signatureToString(tagSignature)); | |
| 128 | + int size = tcmm.getTagSize(profileID, tagSignature); | |
| 129 | + System.err.println("=" + size); | |
| 130 | + return size; | |
| 131 | + } | |
| 132 | + | |
| 133 | + public void getTagData(long profileID, int tagSignature, | |
| 134 | + byte[] data) { | |
| 135 | + System.err.printf(cName + ".getTagData(ID=%x, TagSig=%s)", | |
| 136 | + profileID, signatureToString(tagSignature)); | |
| 137 | + System.err.println(" requested " + data.length + " byte(s)"); | |
| 138 | + tcmm.getTagData(profileID, tagSignature, data); | |
| 139 | + } | |
| 140 | + | |
| 141 | + public void setTagData(long profileID, int tagSignature, | |
| 142 | + byte[] data) { | |
| 143 | + System.err.print(cName + ".setTagData(ID=" + profileID + | |
| 144 | + ", TagSig=" + tagSignature + ")"); | |
| 145 | + System.err.println(" sending " + data.length + " byte(s)"); | |
| 146 | + tcmm.setTagData(profileID, tagSignature, data); | |
| 147 | + } | |
| 148 | + | |
| 149 | + /* methods for creating ColorTransforms */ | |
| 150 | + public ColorTransform createTransform(ICC_Profile profile, | |
| 151 | + int renderType, | |
| 152 | + int transformType) { | |
| 153 | + System.err.println(cName + ".createTransform(ICC_Profile,int,int)"); | |
| 154 | + return tcmm.createTransform(profile, renderType, transformType); | |
| 155 | + } | |
| 156 | + | |
| 157 | + public ColorTransform createTransform(ColorTransform[] transforms) { | |
| 158 | + System.err.println(cName + ".createTransform(ColorTransform[])"); | |
| 159 | + return tcmm.createTransform(transforms); | |
| 160 | + } | |
| 161 | + | |
| 162 | + private static String signatureToString(int sig) { | |
| 163 | + return String.format("%c%c%c%c", | |
| 164 | + (char)(0xff & (sig >> 24)), | |
| 165 | + (char)(0xff & (sig >> 16)), | |
| 166 | + (char)(0xff & (sig >> 8)), | |
| 167 | + (char)(0xff & (sig ))); | |
| 168 | + } | |
| 169 | + } | |
| 170 | +} | |
Binary file not shown.
| @@ -0,0 +1,53 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.cmm; | |
| 27 | + | |
| 28 | +import java.awt.image.BufferedImage; | |
| 29 | +import java.awt.image.Raster; | |
| 30 | +import java.awt.image.WritableRaster; | |
| 31 | + | |
| 32 | +public interface ColorTransform { | |
| 33 | + public int Any = -1;/* any rendering type, whichever is | |
| 34 | + available */ | |
| 35 | + /* search order is icPerceptual, | |
| 36 | + icRelativeColorimetric, icSaturation */ | |
| 37 | + | |
| 38 | + /* Transform types */ | |
| 39 | + public int In = 1; | |
| 40 | + public int Out = 2; | |
| 41 | + public int Gamut = 3; | |
| 42 | + public int Simulation = 4; | |
| 43 | + | |
| 44 | + public int getNumInComponents(); | |
| 45 | + public int getNumOutComponents(); | |
| 46 | + public void colorConvert(BufferedImage src, BufferedImage dst); | |
| 47 | + public void colorConvert(Raster src, WritableRaster dst, | |
| 48 | + float[] srcMinVal, float[]srcMaxVal, | |
| 49 | + float[] dstMinVal, float[]dstMaxVal); | |
| 50 | + public void colorConvert(Raster src, WritableRaster dst); | |
| 51 | + public short[] colorConvert(short[] src, short[] dest); | |
| 52 | + public byte[] colorConvert (byte[] src, byte[] dest); | |
| 53 | +} | |
Binary file not shown.
| @@ -0,0 +1,48 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.cmm; | |
| 27 | + | |
| 28 | +import java.awt.color.ICC_Profile; | |
| 29 | + | |
| 30 | +/* Pluggable CMM interface */ | |
| 31 | + | |
| 32 | +public interface PCMM { | |
| 33 | + | |
| 34 | + /* methods invoked from ICC_Profile */ | |
| 35 | + public long loadProfile(byte[] data); | |
| 36 | + public void freeProfile(long profileID); | |
| 37 | + public int getProfileSize(long profileID); | |
| 38 | + public void getProfileData(long profileID, byte[] data); | |
| 39 | + public void getTagData(long profileID, int tagSignature, byte[] data); | |
| 40 | + public int getTagSize(long profileID, int tagSignature); | |
| 41 | + public void setTagData(long profileID, int tagSignature, byte[] data); | |
| 42 | + | |
| 43 | + /* methods for creating ColorTransforms */ | |
| 44 | + public ColorTransform createTransform(ICC_Profile profile, int renderType, | |
| 45 | + int transformType); | |
| 46 | + | |
| 47 | + public ColorTransform createTransform(ColorTransform[] transforms); | |
| 48 | +} | |
Binary file not shown.
| @@ -0,0 +1,41 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.cmm; | |
| 27 | + | |
| 28 | +import java.awt.color.ProfileDataException; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * An interface to allow the ProfileDeferralMgr to activate a | |
| 32 | + * deferred profile. | |
| 33 | + */ | |
| 34 | +public interface ProfileActivator { | |
| 35 | + | |
| 36 | + /** | |
| 37 | + * Activate a previously deferred ICC_Profile object. | |
| 38 | + */ | |
| 39 | + public void activate() throws ProfileDataException; | |
| 40 | + | |
| 41 | +} | |
Binary file not shown.
| @@ -0,0 +1,61 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.cmm; | |
| 27 | + | |
| 28 | +import java.io.InputStream; | |
| 29 | +import java.io.IOException; | |
| 30 | + | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * A class to pass information about a profile to be loaded from | |
| 34 | + * a file to the static getInstance(InputStream) method of | |
| 35 | + * ICC_Profile. Loading of the profile data and initialization | |
| 36 | + * of the CMM is to be deferred as long as possible. | |
| 37 | + */ | |
| 38 | +public class ProfileDeferralInfo extends InputStream { | |
| 39 | + | |
| 40 | + public int colorSpaceType, numComponents, profileClass; | |
| 41 | + public String filename; | |
| 42 | + | |
| 43 | + public ProfileDeferralInfo(String fn, int type, int ncomp, int pclass) { | |
| 44 | + | |
| 45 | + super(); | |
| 46 | + filename = fn; | |
| 47 | + colorSpaceType = type; | |
| 48 | + numComponents = ncomp; | |
| 49 | + profileClass = pclass; | |
| 50 | + } | |
| 51 | + | |
| 52 | + | |
| 53 | + /** | |
| 54 | + * Implements the abstract read() method of InputStream. | |
| 55 | + */ | |
| 56 | + public int read() throws IOException { | |
| 57 | + | |
| 58 | + return 0; | |
| 59 | + } | |
| 60 | + | |
| 61 | +} | |
Binary file not shown.
| @@ -0,0 +1,119 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.cmm; | |
| 27 | + | |
| 28 | +import java.awt.color.ProfileDataException; | |
| 29 | +import java.util.Vector; | |
| 30 | + | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * A class to manage the deferral of CMM initialization of profile | |
| 34 | + * data for internal ICC_Profile objects - i.e. when we "trust" that | |
| 35 | + * the profile data is valid and we think it may not be needed. An | |
| 36 | + * example is the sRGB profile which gets loaded by any program doing | |
| 37 | + * graphics, but which may not be needed if the program does not need | |
| 38 | + * high quality color conversion. | |
| 39 | + */ | |
| 40 | +public class ProfileDeferralMgr { | |
| 41 | + | |
| 42 | + public static boolean deferring = true; | |
| 43 | + private static Vector<ProfileActivator> aVector; | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * Records a ProfileActivator object whose activate method will | |
| 47 | + * be called if the CMM needs to be activated. | |
| 48 | + */ | |
| 49 | + public static void registerDeferral(ProfileActivator pa) { | |
| 50 | + | |
| 51 | + if (!deferring) { | |
| 52 | + return; | |
| 53 | + } | |
| 54 | + if (aVector == null) { | |
| 55 | + aVector = new Vector<ProfileActivator>(3, 3); | |
| 56 | + } | |
| 57 | + aVector.addElement(pa); | |
| 58 | + return; | |
| 59 | + } | |
| 60 | + | |
| 61 | + | |
| 62 | + /** | |
| 63 | + * Removes a ProfileActivator object from the vector of ProfileActivator | |
| 64 | + * objects whose activate method will be called if the CMM needs to be | |
| 65 | + * activated. | |
| 66 | + */ | |
| 67 | + public static void unregisterDeferral(ProfileActivator pa) { | |
| 68 | + | |
| 69 | + if (!deferring) { | |
| 70 | + return; | |
| 71 | + } | |
| 72 | + if (aVector == null) { | |
| 73 | + return; | |
| 74 | + } | |
| 75 | + aVector.removeElement(pa); | |
| 76 | + return; | |
| 77 | + } | |
| 78 | + | |
| 79 | + /** | |
| 80 | + * Removes a ProfileActivator object from the vector of ProfileActivator | |
| 81 | + * objects whose activate method will be called if the CMM needs to be | |
| 82 | + * activated. | |
| 83 | + */ | |
| 84 | + public static void activateProfiles() { | |
| 85 | + | |
| 86 | + int i, n; | |
| 87 | + | |
| 88 | + deferring = false; | |
| 89 | + if (aVector == null) { | |
| 90 | + return; | |
| 91 | + } | |
| 92 | + n = aVector.size(); | |
| 93 | + for (ProfileActivator pa : aVector) { | |
| 94 | + try { | |
| 95 | + pa.activate(); | |
| 96 | + } catch (ProfileDataException e) { | |
| 97 | + /* | |
| 98 | + * Ignore profile activation error for now: | |
| 99 | + * such exception is pssible due to absence | |
| 100 | + * or corruption of standard color profile. | |
| 101 | + * As for now we expect all profiles should | |
| 102 | + * be shiped with jre and presence of this | |
| 103 | + * exception is indication of some configuration | |
| 104 | + * problem in jre installation. | |
| 105 | + * | |
| 106 | + * NB: we still are greedy loading deferred profiles | |
| 107 | + * and load them all if any of them is needed. | |
| 108 | + * Therefore broken profile (if any) might be never used. | |
| 109 | + * If there will be attempt to use broken profile then | |
| 110 | + * it will result in CMMException. | |
| 111 | + */ | |
| 112 | + } | |
| 113 | + } | |
| 114 | + aVector.removeAllElements(); | |
| 115 | + aVector = null; | |
| 116 | + return; | |
| 117 | + } | |
| 118 | + | |
| 119 | +} | |
| @@ -0,0 +1,104 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.cmm.lcms; | |
| 27 | + | |
| 28 | +import java.awt.color.ColorSpace; | |
| 29 | +import java.awt.color.ICC_Profile; | |
| 30 | +import java.awt.color.CMMException; | |
| 31 | +import sun.java2d.cmm.ColorTransform; | |
| 32 | +import sun.java2d.cmm.PCMM; | |
| 33 | +import sun.java2d.cmm.lcms.LCMS; | |
| 34 | +import sun.java2d.cmm.lcms.LCMSTransform; | |
| 35 | + | |
| 36 | +public class LCMS implements PCMM { | |
| 37 | + | |
| 38 | + /* methods invoked from ICC_Profile */ | |
| 39 | + public native long loadProfile(byte[] data); | |
| 40 | + | |
| 41 | + public native void freeProfile(long profileID); | |
| 42 | + | |
| 43 | + public native synchronized int getProfileSize(long profileID); | |
| 44 | + | |
| 45 | + public native synchronized void getProfileData(long profileID, byte[] data); | |
| 46 | + | |
| 47 | + public native synchronized int getTagSize(long profileID, int tagSignature); | |
| 48 | + public native synchronized void getTagData(long profileID, int tagSignature, | |
| 49 | + byte[] data); | |
| 50 | + public native synchronized void setTagData(long profileID, int tagSignature, | |
| 51 | + byte[] data); | |
| 52 | + | |
| 53 | + public static native long getProfileID(ICC_Profile profile); | |
| 54 | + | |
| 55 | + public static native long createNativeTransform( | |
| 56 | + long[] profileIDs, int renderType, int inFormatter, int outFormatter, | |
| 57 | + Object disposerRef); | |
| 58 | + | |
| 59 | + /** | |
| 60 | + * Constructs ColorTransform object corresponding to an ICC_profile | |
| 61 | + */ | |
| 62 | + public ColorTransform createTransform(ICC_Profile profile, | |
| 63 | + int renderType, | |
| 64 | + int transformType) | |
| 65 | + { | |
| 66 | + return new LCMSTransform(profile, renderType, renderType); | |
| 67 | + } | |
| 68 | + | |
| 69 | + /** | |
| 70 | + * Constructs an ColorTransform object from a list of ColorTransform | |
| 71 | + * objects | |
| 72 | + */ | |
| 73 | + public synchronized ColorTransform createTransform( | |
| 74 | + ColorTransform[] transforms) | |
| 75 | + { | |
| 76 | + return new LCMSTransform(transforms); | |
| 77 | + } | |
| 78 | + | |
| 79 | + /* methods invoked from LCMSTransform */ | |
| 80 | + public static native void colorConvert(LCMSTransform trans, | |
| 81 | + LCMSImageLayout src, | |
| 82 | + LCMSImageLayout dest); | |
| 83 | + public static native void freeTransform(long ID); | |
| 84 | + | |
| 85 | + public static native void initLCMS(Class Trans, Class IL, Class Pf); | |
| 86 | + | |
| 87 | + /* the class initializer which loads the CMM */ | |
| 88 | + static { | |
| 89 | + java.security.AccessController.doPrivileged( | |
| 90 | + new java.security.PrivilegedAction() { | |
| 91 | + public Object run() { | |
| 92 | + /* We need to load awt here because of usage trace and | |
| 93 | + * disposer frameworks | |
| 94 | + */ | |
| 95 | + System.loadLibrary("awt"); | |
| 96 | + System.loadLibrary("lcms"); | |
| 97 | + return null; | |
| 98 | + } | |
| 99 | + } | |
| 100 | + ); | |
| 101 | + | |
| 102 | + initLCMS(LCMSTransform.class, LCMSImageLayout.class, ICC_Profile.class); | |
| 103 | + } | |
| 104 | +} | |
| @@ -0,0 +1,235 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.cmm.lcms; | |
| 27 | + | |
| 28 | +import java.awt.Graphics2D; | |
| 29 | +import java.awt.image.BufferedImage; | |
| 30 | +import java.awt.image.ComponentColorModel; | |
| 31 | +import java.awt.image.Raster; | |
| 32 | +import java.awt.image.WritableRaster; | |
| 33 | +import java.awt.image.SinglePixelPackedSampleModel; | |
| 34 | +import java.awt.image.ComponentSampleModel; | |
| 35 | +import java.awt.image.DataBuffer; | |
| 36 | +import java.awt.image.DataBufferByte; | |
| 37 | +import java.awt.image.DataBufferUShort; | |
| 38 | +import java.awt.image.DataBufferInt; | |
| 39 | +import java.awt.image.ColorModel; | |
| 40 | +import sun.awt.image.ByteComponentRaster; | |
| 41 | +import sun.awt.image.ShortComponentRaster; | |
| 42 | +import sun.awt.image.IntegerComponentRaster; | |
| 43 | + | |
| 44 | + | |
| 45 | +class LCMSImageLayout { | |
| 46 | + | |
| 47 | + public static int BYTES_SH(int x) { | |
| 48 | + return x; | |
| 49 | + } | |
| 50 | + | |
| 51 | + public static int EXTRA_SH(int x) { | |
| 52 | + return x<<7; | |
| 53 | + } | |
| 54 | + | |
| 55 | + public static int CHANNELS_SH(int x) { | |
| 56 | + return x<<3; | |
| 57 | + } | |
| 58 | + | |
| 59 | + public static final int SWAPFIRST = 1<<14; | |
| 60 | + | |
| 61 | + public static final int DOSWAP = 1<<10; | |
| 62 | + | |
| 63 | + public static final int PT_RGB_8 = | |
| 64 | + CHANNELS_SH(3) | BYTES_SH(1); | |
| 65 | + | |
| 66 | + public static final int PT_GRAY_8 = | |
| 67 | + CHANNELS_SH(1) | BYTES_SH(1); | |
| 68 | + | |
| 69 | + public static final int PT_GRAY_16 = | |
| 70 | + CHANNELS_SH(1) | BYTES_SH(2); | |
| 71 | + | |
| 72 | + public static final int PT_RGBA_8 = | |
| 73 | + EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1); | |
| 74 | + | |
| 75 | + public static final int PT_ARGB_8 = | |
| 76 | + EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1) | SWAPFIRST; | |
| 77 | + | |
| 78 | + public static final int PT_BGR_8 = | |
| 79 | + DOSWAP | CHANNELS_SH(3) | BYTES_SH(1); | |
| 80 | + | |
| 81 | + public static final int PT_ABGR_8 = | |
| 82 | + DOSWAP | EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1); | |
| 83 | + | |
| 84 | + public static final int PT_BGRA_8 = EXTRA_SH(1) | CHANNELS_SH(3) | | |
| 85 | + BYTES_SH(1) | DOSWAP | SWAPFIRST; | |
| 86 | + | |
| 87 | + public static final int DT_BYTE = 0; | |
| 88 | + public static final int DT_SHORT = 1; | |
| 89 | + public static final int DT_INT = 2; | |
| 90 | + public static final int DT_DOUBLE = 3; | |
| 91 | + | |
| 92 | + | |
| 93 | + boolean isIntPacked = false; | |
| 94 | + int pixelType; | |
| 95 | + int dataType; | |
| 96 | + int width; | |
| 97 | + int height; | |
| 98 | + int nextRowOffset; | |
| 99 | + int offset; | |
| 100 | + | |
| 101 | + Object dataArray; | |
| 102 | + private LCMSImageLayout(int np, int pixelType, int pixelSize) { | |
| 103 | + this.pixelType = pixelType; | |
| 104 | + width = np; | |
| 105 | + height = 1; | |
| 106 | + nextRowOffset = np*pixelSize; | |
| 107 | + offset = 0; | |
| 108 | + } | |
| 109 | + | |
| 110 | + private LCMSImageLayout(int width, int height, int pixelType, | |
| 111 | + int pixelSize) { | |
| 112 | + this.pixelType = pixelType; | |
| 113 | + this.width = width; | |
| 114 | + this.height = height; | |
| 115 | + nextRowOffset = width*pixelSize; | |
| 116 | + offset = 0; | |
| 117 | + } | |
| 118 | + | |
| 119 | + | |
| 120 | + public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize) { | |
| 121 | + this(np, pixelType, pixelSize); | |
| 122 | + dataType = DT_BYTE; | |
| 123 | + dataArray = data; | |
| 124 | + } | |
| 125 | + | |
| 126 | + public LCMSImageLayout(short[] data, int np, int pixelType, int pixelSize) { | |
| 127 | + this(np, pixelType, pixelSize); | |
| 128 | + dataType = DT_SHORT; | |
| 129 | + dataArray = data; | |
| 130 | + } | |
| 131 | + | |
| 132 | + public LCMSImageLayout(int[] data, int np, int pixelType, int pixelSize) { | |
| 133 | + this(np, pixelType, pixelSize); | |
| 134 | + dataType = DT_INT; | |
| 135 | + dataArray = data; | |
| 136 | + } | |
| 137 | + | |
| 138 | + public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize) | |
| 139 | + { | |
| 140 | + this(np, pixelType, pixelSize); | |
| 141 | + dataType = DT_DOUBLE; | |
| 142 | + dataArray = data; | |
| 143 | + } | |
| 144 | + | |
| 145 | + public LCMSImageLayout(BufferedImage image) { | |
| 146 | + ShortComponentRaster shortRaster; | |
| 147 | + IntegerComponentRaster intRaster; | |
| 148 | + ByteComponentRaster byteRaster; | |
| 149 | + switch (image.getType()) { | |
| 150 | + case BufferedImage.TYPE_INT_RGB: | |
| 151 | + pixelType = PT_ARGB_8; | |
| 152 | + isIntPacked = true; | |
| 153 | + break; | |
| 154 | + case BufferedImage.TYPE_INT_ARGB: | |
| 155 | + pixelType = PT_ARGB_8; | |
| 156 | + isIntPacked = true; | |
| 157 | + break; | |
| 158 | + case BufferedImage.TYPE_INT_BGR: | |
| 159 | + pixelType = PT_ABGR_8; | |
| 160 | + isIntPacked = true; | |
| 161 | + break; | |
| 162 | + case BufferedImage.TYPE_3BYTE_BGR: | |
| 163 | + pixelType = PT_BGR_8; | |
| 164 | + break; | |
| 165 | + case BufferedImage.TYPE_4BYTE_ABGR: | |
| 166 | + pixelType = PT_ABGR_8; | |
| 167 | + break; | |
| 168 | + case BufferedImage.TYPE_BYTE_GRAY: | |
| 169 | + pixelType = PT_GRAY_8; | |
| 170 | + break; | |
| 171 | + case BufferedImage.TYPE_USHORT_GRAY: | |
| 172 | + pixelType = PT_GRAY_16; | |
| 173 | + break; | |
| 174 | + default: | |
| 175 | + // TODO: Add support for some images having | |
| 176 | + // SinglePixelPackedModel and ComponentSampleModel | |
| 177 | + throw new IllegalArgumentException( | |
| 178 | + "CMMImageLayout - bad image type passed to constructor"); | |
| 179 | + } | |
| 180 | + | |
| 181 | + width = image.getWidth(); | |
| 182 | + height = image.getHeight(); | |
| 183 | + | |
| 184 | + switch (image.getType()) { | |
| 185 | + case BufferedImage.TYPE_INT_RGB: | |
| 186 | + case BufferedImage.TYPE_INT_ARGB: | |
| 187 | + case BufferedImage.TYPE_INT_BGR: | |
| 188 | + intRaster = (IntegerComponentRaster)image.getRaster(); | |
| 189 | + nextRowOffset = intRaster.getScanlineStride()*4; | |
| 190 | + offset = intRaster.getDataOffset(0)*4; | |
| 191 | + dataArray = intRaster.getDataStorage(); | |
| 192 | + dataType = DT_INT; | |
| 193 | + break; | |
| 194 | + | |
| 195 | + case BufferedImage.TYPE_3BYTE_BGR: | |
| 196 | + case BufferedImage.TYPE_4BYTE_ABGR: | |
| 197 | + byteRaster = (ByteComponentRaster)image.getRaster(); | |
| 198 | + nextRowOffset = byteRaster.getScanlineStride(); | |
| 199 | + offset = byteRaster.getDataOffset(0); | |
| 200 | + dataArray = byteRaster.getDataStorage(); | |
| 201 | + dataType = DT_BYTE; | |
| 202 | + break; | |
| 203 | + | |
| 204 | + case BufferedImage.TYPE_BYTE_GRAY: | |
| 205 | + byteRaster = (ByteComponentRaster)image.getRaster(); | |
| 206 | + nextRowOffset = byteRaster.getScanlineStride(); | |
| 207 | + offset = byteRaster.getDataOffset(0); | |
| 208 | + dataArray = byteRaster.getDataStorage(); | |
| 209 | + dataType = DT_BYTE; | |
| 210 | + break; | |
| 211 | + | |
| 212 | + case BufferedImage.TYPE_USHORT_GRAY: | |
| 213 | + shortRaster = (ShortComponentRaster)image.getRaster(); | |
| 214 | + nextRowOffset = shortRaster.getScanlineStride()*2; | |
| 215 | + offset = shortRaster.getDataOffset(0) * 2; | |
| 216 | + dataArray = shortRaster.getDataStorage(); | |
| 217 | + dataType = DT_SHORT; | |
| 218 | + break; | |
| 219 | + } | |
| 220 | + } | |
| 221 | + | |
| 222 | + public static boolean isSupported(BufferedImage image) { | |
| 223 | + switch (image.getType()) { | |
| 224 | + case BufferedImage.TYPE_INT_RGB: | |
| 225 | + case BufferedImage.TYPE_INT_ARGB: | |
| 226 | + case BufferedImage.TYPE_INT_BGR: | |
| 227 | + case BufferedImage.TYPE_3BYTE_BGR: | |
| 228 | + case BufferedImage.TYPE_4BYTE_ABGR: | |
| 229 | + case BufferedImage.TYPE_BYTE_GRAY: | |
| 230 | + case BufferedImage.TYPE_USHORT_GRAY: | |
| 231 | + return true; | |
| 232 | + } | |
| 233 | + return false; | |
| 234 | + } | |
| 235 | +} | |
| @@ -0,0 +1,609 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +/********************************************************************** | |
| 27 | + ********************************************************************** | |
| 28 | + ********************************************************************** | |
| 29 | + *** COPYRIGHT (c) Eastman Kodak Company, 1997 *** | |
| 30 | + *** As an unpublished work pursuant to Title 17 of the United *** | |
| 31 | + *** States Code. All rights reserved. *** | |
| 32 | + ********************************************************************** | |
| 33 | + ********************************************************************** | |
| 34 | + **********************************************************************/ | |
| 35 | + | |
| 36 | +package sun.java2d.cmm.lcms; | |
| 37 | + | |
| 38 | +import java.awt.color.ICC_Profile; | |
| 39 | +import java.awt.color.ProfileDataException; | |
| 40 | +import java.awt.color.CMMException; | |
| 41 | +import java.awt.color.ColorSpace; | |
| 42 | +import java.awt.image.BufferedImage; | |
| 43 | +import java.awt.image.Raster; | |
| 44 | +import java.awt.image.WritableRaster; | |
| 45 | +import java.awt.image.ColorModel; | |
| 46 | +import java.awt.image.DirectColorModel; | |
| 47 | +import java.awt.image.ComponentColorModel; | |
| 48 | +import java.awt.image.SampleModel; | |
| 49 | +import java.awt.image.DataBuffer; | |
| 50 | +import java.awt.image.SinglePixelPackedSampleModel; | |
| 51 | +import java.awt.image.ComponentSampleModel; | |
| 52 | +import sun.java2d.cmm.*; | |
| 53 | +import sun.java2d.cmm.lcms.*; | |
| 54 | + | |
| 55 | + | |
| 56 | +public class LCMSTransform implements ColorTransform { | |
| 57 | + long ID; | |
| 58 | + private int inFormatter; | |
| 59 | + private int outFormatter; | |
| 60 | + | |
| 61 | + ICC_Profile[] profiles; | |
| 62 | + long [] profileIDs; | |
| 63 | + int renderType; | |
| 64 | + int transformType; | |
| 65 | + | |
| 66 | + private int numInComponents = -1; | |
| 67 | + private int numOutComponents = -1; | |
| 68 | + | |
| 69 | + private Object disposerReferent = new Object(); | |
| 70 | + | |
| 71 | + /* the class initializer */ | |
| 72 | + static { | |
| 73 | + if (ProfileDeferralMgr.deferring) { | |
| 74 | + ProfileDeferralMgr.activateProfiles(); | |
| 75 | + } | |
| 76 | + } | |
| 77 | + | |
| 78 | + public LCMSTransform(ICC_Profile profile, int renderType, | |
| 79 | + int transformType) | |
| 80 | + { | |
| 81 | + /* Actually, it is not a complete transform but just part of it */ | |
| 82 | + profiles = new ICC_Profile[1]; | |
| 83 | + profiles[0] = profile; | |
| 84 | + profileIDs = new long[1]; | |
| 85 | + profileIDs[0] = LCMS.getProfileID(profile); | |
| 86 | + this.renderType = (renderType == ColorTransform.Any)? | |
| 87 | + ICC_Profile.icPerceptual : renderType; | |
| 88 | + this.transformType = transformType; | |
| 89 | + | |
| 90 | + /* Note that ICC_Profile.getNumComponents() is quite expensive | |
| 91 | + * (it may results in a reading of the profile header). | |
| 92 | + * So, here we cache the number of components of input and | |
| 93 | + * output profiles for further usage. | |
| 94 | + */ | |
| 95 | + numInComponents = profiles[0].getNumComponents(); | |
| 96 | + numOutComponents = profiles[profiles.length - 1].getNumComponents(); | |
| 97 | + } | |
| 98 | + | |
| 99 | + public LCMSTransform (ColorTransform[] transforms) { | |
| 100 | + int size = 0; | |
| 101 | + for (int i=0; i < transforms.length; i++) { | |
| 102 | + size+=((LCMSTransform)transforms[i]).profiles.length; | |
| 103 | + } | |
| 104 | + profiles = new ICC_Profile[size]; | |
| 105 | + profileIDs = new long[size]; | |
| 106 | + int j = 0; | |
| 107 | + for (int i=0; i < transforms.length; i++) { | |
| 108 | + LCMSTransform curTrans = (LCMSTransform)transforms[i]; | |
| 109 | + System.arraycopy(curTrans.profiles, 0, profiles, j, | |
| 110 | + curTrans.profiles.length); | |
| 111 | + System.arraycopy(curTrans.profileIDs, 0, profileIDs, j, | |
| 112 | + curTrans.profileIDs.length); | |
| 113 | + j += curTrans.profiles.length; | |
| 114 | + } | |
| 115 | + renderType = ((LCMSTransform)transforms[0]).renderType; | |
| 116 | + | |
| 117 | + /* Note that ICC_Profile.getNumComponents() is quite expensive | |
| 118 | + * (it may results in a reading of the profile header). | |
| 119 | + * So, here we cache the number of components of input and | |
| 120 | + * output profiles for further usage. | |
| 121 | + */ | |
| 122 | + numInComponents = profiles[0].getNumComponents(); | |
| 123 | + numOutComponents = profiles[profiles.length - 1].getNumComponents(); | |
| 124 | + } | |
| 125 | + | |
| 126 | + public int getNumInComponents() { | |
| 127 | + return numInComponents; | |
| 128 | + } | |
| 129 | + | |
| 130 | + public int getNumOutComponents() { | |
| 131 | + return numOutComponents; | |
| 132 | + } | |
| 133 | + | |
| 134 | + private synchronized void doTransform(LCMSImageLayout in, | |
| 135 | + LCMSImageLayout out) { | |
| 136 | + // update native transfrom if needed | |
| 137 | + if (ID == 0L || | |
| 138 | + inFormatter != in.pixelType || | |
| 139 | + outFormatter != out.pixelType) { | |
| 140 | + | |
| 141 | + if (ID != 0L) { | |
| 142 | + // Disposer will destroy forgotten transform | |
| 143 | + disposerReferent = new Object(); | |
| 144 | + } | |
| 145 | + inFormatter = in.pixelType; | |
| 146 | + outFormatter = out.pixelType; | |
| 147 | + | |
| 148 | + ID = LCMS.createNativeTransform(profileIDs, renderType, | |
| 149 | + inFormatter, outFormatter, | |
| 150 | + disposerReferent); | |
| 151 | + } | |
| 152 | + | |
| 153 | + LCMS.colorConvert(this, in, out); | |
| 154 | + } | |
| 155 | + | |
| 156 | + public void colorConvert(BufferedImage src, BufferedImage dst) { | |
| 157 | + if (LCMSImageLayout.isSupported(src) && | |
| 158 | + LCMSImageLayout.isSupported(dst)) | |
| 159 | + { | |
| 160 | + doTransform(new LCMSImageLayout(src), new LCMSImageLayout(dst)); | |
| 161 | + return; | |
| 162 | + } | |
| 163 | + LCMSImageLayout srcIL, dstIL; | |
| 164 | + Raster srcRas = src.getRaster(); | |
| 165 | + WritableRaster dstRas = dst.getRaster(); | |
| 166 | + ColorModel srcCM = src.getColorModel(); | |
| 167 | + ColorModel dstCM = dst.getColorModel(); | |
| 168 | + int w = src.getWidth(); | |
| 169 | + int h = src.getHeight(); | |
| 170 | + int srcNumComp = srcCM.getNumColorComponents(); | |
| 171 | + int dstNumComp = dstCM.getNumColorComponents(); | |
| 172 | + int precision = 8; | |
| 173 | + float maxNum = 255.0f; | |
| 174 | + for (int i = 0; i < srcNumComp; i++) { | |
| 175 | + if (srcCM.getComponentSize(i) > 8) { | |
| 176 | + precision = 16; | |
| 177 | + maxNum = 65535.0f; | |
| 178 | + } | |
| 179 | + } | |
| 180 | + for (int i = 0; i < dstNumComp; i++) { | |
| 181 | + if (dstCM.getComponentSize(i) > 8) { | |
| 182 | + precision = 16; | |
| 183 | + maxNum = 65535.0f; | |
| 184 | + } | |
| 185 | + } | |
| 186 | + float[] srcMinVal = new float[srcNumComp]; | |
| 187 | + float[] srcInvDiffMinMax = new float[srcNumComp]; | |
| 188 | + ColorSpace cs = srcCM.getColorSpace(); | |
| 189 | + for (int i = 0; i < srcNumComp; i++) { | |
| 190 | + srcMinVal[i] = cs.getMinValue(i); | |
| 191 | + srcInvDiffMinMax[i] = maxNum / (cs.getMaxValue(i) - srcMinVal[i]); | |
| 192 | + } | |
| 193 | + cs = dstCM.getColorSpace(); | |
| 194 | + float[] dstMinVal = new float[dstNumComp]; | |
| 195 | + float[] dstDiffMinMax = new float[dstNumComp]; | |
| 196 | + for (int i = 0; i < dstNumComp; i++) { | |
| 197 | + dstMinVal[i] = cs.getMinValue(i); | |
| 198 | + dstDiffMinMax[i] = (cs.getMaxValue(i) - dstMinVal[i]) / maxNum; | |
| 199 | + } | |
| 200 | + boolean dstHasAlpha = dstCM.hasAlpha(); | |
| 201 | + boolean needSrcAlpha = srcCM.hasAlpha() && dstHasAlpha; | |
| 202 | + float[] dstColor; | |
| 203 | + if (dstHasAlpha) { | |
| 204 | + dstColor = new float[dstNumComp + 1]; | |
| 205 | + } else { | |
| 206 | + dstColor = new float[dstNumComp]; | |
| 207 | + } | |
| 208 | + if (precision == 8) { | |
| 209 | + byte[] srcLine = new byte[w * srcNumComp]; | |
| 210 | + byte[] dstLine = new byte[w * dstNumComp]; | |
| 211 | + Object pixel; | |
| 212 | + float[] color; | |
| 213 | + float[] alpha = null; | |
| 214 | + if (needSrcAlpha) { | |
| 215 | + alpha = new float[w]; | |
| 216 | + } | |
| 217 | + int idx; | |
| 218 | + // TODO check for src npixels = dst npixels | |
| 219 | + srcIL = new LCMSImageLayout( | |
| 220 | + srcLine, srcLine.length/getNumInComponents(), | |
| 221 | + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | | |
| 222 | + LCMSImageLayout.BYTES_SH(1), getNumInComponents()); | |
| 223 | + dstIL = new LCMSImageLayout( | |
| 224 | + dstLine, dstLine.length/getNumOutComponents(), | |
| 225 | + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | | |
| 226 | + LCMSImageLayout.BYTES_SH(1), getNumOutComponents()); | |
| 227 | + // process each scanline | |
| 228 | + for (int y = 0; y < h; y++) { | |
| 229 | + // convert src scanline | |
| 230 | + pixel = null; | |
| 231 | + color = null; | |
| 232 | + idx = 0; | |
| 233 | + for (int x = 0; x < w; x++) { | |
| 234 | + pixel = srcRas.getDataElements(x, y, pixel); | |
| 235 | + color = srcCM.getNormalizedComponents(pixel, color, 0); | |
| 236 | + for (int i = 0; i < srcNumComp; i++) { | |
| 237 | + srcLine[idx++] = (byte) | |
| 238 | + ((color[i] - srcMinVal[i]) * srcInvDiffMinMax[i] + | |
| 239 | + 0.5f); | |
| 240 | + } | |
| 241 | + if (needSrcAlpha) { | |
| 242 | + alpha[x] = color[srcNumComp]; | |
| 243 | + } | |
| 244 | + } | |
| 245 | + // color convert srcLine to dstLine | |
| 246 | + doTransform(srcIL, dstIL); | |
| 247 | + | |
| 248 | + // convert dst scanline | |
| 249 | + pixel = null; | |
| 250 | + idx = 0; | |
| 251 | + for (int x = 0; x < w; x++) { | |
| 252 | + for (int i = 0; i < dstNumComp; i++) { | |
| 253 | + dstColor[i] = ((float) (dstLine[idx++] & 0xff)) * | |
| 254 | + dstDiffMinMax[i] + dstMinVal[i]; | |
| 255 | + } | |
| 256 | + if (needSrcAlpha) { | |
| 257 | + dstColor[dstNumComp] = alpha[x]; | |
| 258 | + } else if (dstHasAlpha) { | |
| 259 | + dstColor[dstNumComp] = 1.0f; | |
| 260 | + } | |
| 261 | + pixel = dstCM.getDataElements(dstColor, 0, pixel); | |
| 262 | + dstRas.setDataElements(x, y, pixel); | |
| 263 | + } | |
| 264 | + } | |
| 265 | + } else { | |
| 266 | + short[] srcLine = new short[w * srcNumComp]; | |
| 267 | + short[] dstLine = new short[w * dstNumComp]; | |
| 268 | + Object pixel; | |
| 269 | + float[] color; | |
| 270 | + float[] alpha = null; | |
| 271 | + if (needSrcAlpha) { | |
| 272 | + alpha = new float[w]; | |
| 273 | + } | |
| 274 | + int idx; | |
| 275 | + srcIL = new LCMSImageLayout( | |
| 276 | + srcLine, srcLine.length/getNumInComponents(), | |
| 277 | + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | | |
| 278 | + LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); | |
| 279 | + | |
| 280 | + dstIL = new LCMSImageLayout( | |
| 281 | + dstLine, dstLine.length/getNumOutComponents(), | |
| 282 | + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | | |
| 283 | + LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); | |
| 284 | + | |
| 285 | + // process each scanline | |
| 286 | + for (int y = 0; y < h; y++) { | |
| 287 | + // convert src scanline | |
| 288 | + pixel = null; | |
| 289 | + color = null; | |
| 290 | + idx = 0; | |
| 291 | + for (int x = 0; x < w; x++) { | |
| 292 | + pixel = srcRas.getDataElements(x, y, pixel); | |
| 293 | + color = srcCM.getNormalizedComponents(pixel, color, 0); | |
| 294 | + for (int i = 0; i < srcNumComp; i++) { | |
| 295 | + srcLine[idx++] = (short) | |
| 296 | + ((color[i] - srcMinVal[i]) * srcInvDiffMinMax[i] + | |
| 297 | + 0.5f); | |
| 298 | + } | |
| 299 | + if (needSrcAlpha) { | |
| 300 | + alpha[x] = color[srcNumComp]; | |
| 301 | + } | |
| 302 | + } | |
| 303 | + // color convert srcLine to dstLine | |
| 304 | + doTransform(srcIL, dstIL); | |
| 305 | + | |
| 306 | + // convert dst scanline | |
| 307 | + pixel = null; | |
| 308 | + idx = 0; | |
| 309 | + for (int x = 0; x < w; x++) { | |
| 310 | + for (int i = 0; i < dstNumComp; i++) { | |
| 311 | + dstColor[i] = ((float) (dstLine[idx++] & 0xffff)) * | |
| 312 | + dstDiffMinMax[i] + dstMinVal[i]; | |
| 313 | + } | |
| 314 | + if (needSrcAlpha) { | |
| 315 | + dstColor[dstNumComp] = alpha[x]; | |
| 316 | + } else if (dstHasAlpha) { | |
| 317 | + dstColor[dstNumComp] = 1.0f; | |
| 318 | + } | |
| 319 | + pixel = dstCM.getDataElements(dstColor, 0, pixel); | |
| 320 | + dstRas.setDataElements(x, y, pixel); | |
| 321 | + } | |
| 322 | + } | |
| 323 | + } | |
| 324 | + } | |
| 325 | + | |
| 326 | + public void colorConvert(Raster src, WritableRaster dst, | |
| 327 | + float[] srcMinVal, float[]srcMaxVal, | |
| 328 | + float[] dstMinVal, float[]dstMaxVal) { | |
| 329 | + LCMSImageLayout srcIL, dstIL; | |
| 330 | + | |
| 331 | + // Can't pass src and dst directly to CMM, so process per scanline | |
| 332 | + SampleModel srcSM = src.getSampleModel(); | |
| 333 | + SampleModel dstSM = dst.getSampleModel(); | |
| 334 | + int srcTransferType = src.getTransferType(); | |
| 335 | + int dstTransferType = dst.getTransferType(); | |
| 336 | + boolean srcIsFloat, dstIsFloat; | |
| 337 | + if ((srcTransferType == DataBuffer.TYPE_FLOAT) || | |
| 338 | + (srcTransferType == DataBuffer.TYPE_DOUBLE)) { | |
| 339 | + srcIsFloat = true; | |
| 340 | + } else { | |
| 341 | + srcIsFloat = false; | |
| 342 | + } | |
| 343 | + if ((dstTransferType == DataBuffer.TYPE_FLOAT) || | |
| 344 | + (dstTransferType == DataBuffer.TYPE_DOUBLE)) { | |
| 345 | + dstIsFloat = true; | |
| 346 | + } else { | |
| 347 | + dstIsFloat = false; | |
| 348 | + } | |
| 349 | + int w = src.getWidth(); | |
| 350 | + int h = src.getHeight(); | |
| 351 | + int srcNumBands = src.getNumBands(); | |
| 352 | + int dstNumBands = dst.getNumBands(); | |
| 353 | + float[] srcScaleFactor = new float[srcNumBands]; | |
| 354 | + float[] dstScaleFactor = new float[dstNumBands]; | |
| 355 | + float[] srcUseMinVal = new float[srcNumBands]; | |
| 356 | + float[] dstUseMinVal = new float[dstNumBands]; | |
| 357 | + for (int i = 0; i < srcNumBands; i++) { | |
| 358 | + if (srcIsFloat) { | |
| 359 | + srcScaleFactor[i] = 65535.0f / (srcMaxVal[i] - srcMinVal[i]); | |
| 360 | + srcUseMinVal[i] = srcMinVal[i]; | |
| 361 | + } else { | |
| 362 | + if (srcTransferType == DataBuffer.TYPE_SHORT) { | |
| 363 | + srcScaleFactor[i] = 65535.0f / 32767.0f; | |
| 364 | + } else { | |
| 365 | + srcScaleFactor[i] = 65535.0f / | |
| 366 | + ((float) ((1 << srcSM.getSampleSize(i)) - 1)); | |
| 367 | + } | |
| 368 | + srcUseMinVal[i] = 0.0f; | |
| 369 | + } | |
| 370 | + } | |
| 371 | + for (int i = 0; i < dstNumBands; i++) { | |
| 372 | + if (dstIsFloat) { | |
| 373 | + dstScaleFactor[i] = (dstMaxVal[i] - dstMinVal[i]) / 65535.0f; | |
| 374 | + dstUseMinVal[i] = dstMinVal[i]; | |
| 375 | + } else { | |
| 376 | + if (dstTransferType == DataBuffer.TYPE_SHORT) { | |
| 377 | + dstScaleFactor[i] = 32767.0f / 65535.0f; | |
| 378 | + } else { | |
| 379 | + dstScaleFactor[i] = | |
| 380 | + ((float) ((1 << dstSM.getSampleSize(i)) - 1)) / | |
| 381 | + 65535.0f; | |
| 382 | + } | |
| 383 | + dstUseMinVal[i] = 0.0f; | |
| 384 | + } | |
| 385 | + } | |
| 386 | + int ys = src.getMinY(); | |
| 387 | + int yd = dst.getMinY(); | |
| 388 | + int xs, xd; | |
| 389 | + float sample; | |
| 390 | + short[] srcLine = new short[w * srcNumBands]; | |
| 391 | + short[] dstLine = new short[w * dstNumBands]; | |
| 392 | + int idx; | |
| 393 | + srcIL = new LCMSImageLayout( | |
| 394 | + srcLine, srcLine.length/getNumInComponents(), | |
| 395 | + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | | |
| 396 | + LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); | |
| 397 | + | |
| 398 | + dstIL = new LCMSImageLayout( | |
| 399 | + dstLine, dstLine.length/getNumOutComponents(), | |
| 400 | + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | | |
| 401 | + LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); | |
| 402 | + | |
| 403 | + // process each scanline | |
| 404 | + for (int y = 0; y < h; y++, ys++, yd++) { | |
| 405 | + // get src scanline | |
| 406 | + xs = src.getMinX(); | |
| 407 | + idx = 0; | |
| 408 | + for (int x = 0; x < w; x++, xs++) { | |
| 409 | + for (int i = 0; i < srcNumBands; i++) { | |
| 410 | + sample = src.getSampleFloat(xs, ys, i); | |
| 411 | + srcLine[idx++] = (short) | |
| 412 | + ((sample - srcUseMinVal[i]) * srcScaleFactor[i] + 0.5f); | |
| 413 | + } | |
| 414 | + } | |
| 415 | + | |
| 416 | + // color convert srcLine to dstLine | |
| 417 | + doTransform(srcIL, dstIL); | |
| 418 | + | |
| 419 | + // store dst scanline | |
| 420 | + xd = dst.getMinX(); | |
| 421 | + idx = 0; | |
| 422 | + for (int x = 0; x < w; x++, xd++) { | |
| 423 | + for (int i = 0; i < dstNumBands; i++) { | |
| 424 | + sample = ((dstLine[idx++] & 0xffff) * dstScaleFactor[i]) + | |
| 425 | + dstUseMinVal[i]; | |
| 426 | + dst.setSample(xd, yd, i, sample); | |
| 427 | + } | |
| 428 | + } | |
| 429 | + } | |
| 430 | + } | |
| 431 | + | |
| 432 | + public void colorConvert(Raster src, WritableRaster dst) { | |
| 433 | + | |
| 434 | + LCMSImageLayout srcIL, dstIL; | |
| 435 | + // Can't pass src and dst directly to CMM, so process per scanline | |
| 436 | + SampleModel srcSM = src.getSampleModel(); | |
| 437 | + SampleModel dstSM = dst.getSampleModel(); | |
| 438 | + int srcTransferType = src.getTransferType(); | |
| 439 | + int dstTransferType = dst.getTransferType(); | |
| 440 | + int w = src.getWidth(); | |
| 441 | + int h = src.getHeight(); | |
| 442 | + int srcNumBands = src.getNumBands(); | |
| 443 | + int dstNumBands = dst.getNumBands(); | |
| 444 | + int precision = 8; | |
| 445 | + float maxNum = 255.0f; | |
| 446 | + for (int i = 0; i < srcNumBands; i++) { | |
| 447 | + if (srcSM.getSampleSize(i) > 8) { | |
| 448 | + precision = 16; | |
| 449 | + maxNum = 65535.0f; | |
| 450 | + } | |
| 451 | + } | |
| 452 | + for (int i = 0; i < dstNumBands; i++) { | |
| 453 | + if (dstSM.getSampleSize(i) > 8) { | |
| 454 | + precision = 16; | |
| 455 | + maxNum = 65535.0f; | |
| 456 | + } | |
| 457 | + } | |
| 458 | + float[] srcScaleFactor = new float[srcNumBands]; | |
| 459 | + float[] dstScaleFactor = new float[dstNumBands]; | |
| 460 | + for (int i = 0; i < srcNumBands; i++) { | |
| 461 | + if (srcTransferType == DataBuffer.TYPE_SHORT) { | |
| 462 | + srcScaleFactor[i] = maxNum / 32767.0f; | |
| 463 | + } else { | |
| 464 | + srcScaleFactor[i] = maxNum / | |
| 465 | + ((float) ((1 << srcSM.getSampleSize(i)) - 1)); | |
| 466 | + } | |
| 467 | + } | |
| 468 | + for (int i = 0; i < dstNumBands; i++) { | |
| 469 | + if (dstTransferType == DataBuffer.TYPE_SHORT) { | |
| 470 | + dstScaleFactor[i] = 32767.0f / maxNum; | |
| 471 | + } else { | |
| 472 | + dstScaleFactor[i] = | |
| 473 | + ((float) ((1 << dstSM.getSampleSize(i)) - 1)) / maxNum; | |
| 474 | + } | |
| 475 | + } | |
| 476 | + int ys = src.getMinY(); | |
| 477 | + int yd = dst.getMinY(); | |
| 478 | + int xs, xd; | |
| 479 | + int sample; | |
| 480 | + if (precision == 8) { | |
| 481 | + byte[] srcLine = new byte[w * srcNumBands]; | |
| 482 | + byte[] dstLine = new byte[w * dstNumBands]; | |
| 483 | + int idx; | |
| 484 | + // TODO check for src npixels = dst npixels | |
| 485 | + srcIL = new LCMSImageLayout( | |
| 486 | + srcLine, srcLine.length/getNumInComponents(), | |
| 487 | + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | | |
| 488 | + LCMSImageLayout.BYTES_SH(1), getNumInComponents()); | |
| 489 | + dstIL = new LCMSImageLayout( | |
| 490 | + dstLine, dstLine.length/getNumOutComponents(), | |
| 491 | + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | | |
| 492 | + LCMSImageLayout.BYTES_SH(1), getNumOutComponents()); | |
| 493 | + | |
| 494 | + // process each scanline | |
| 495 | + for (int y = 0; y < h; y++, ys++, yd++) { | |
| 496 | + // get src scanline | |
| 497 | + xs = src.getMinX(); | |
| 498 | + idx = 0; | |
| 499 | + for (int x = 0; x < w; x++, xs++) { | |
| 500 | + for (int i = 0; i < srcNumBands; i++) { | |
| 501 | + sample = src.getSample(xs, ys, i); | |
| 502 | + srcLine[idx++] = (byte) | |
| 503 | + ((sample * srcScaleFactor[i]) + 0.5f); | |
| 504 | + } | |
| 505 | + } | |
| 506 | + | |
| 507 | + // color convert srcLine to dstLine | |
| 508 | + doTransform(srcIL, dstIL); | |
| 509 | + | |
| 510 | + // store dst scanline | |
| 511 | + xd = dst.getMinX(); | |
| 512 | + idx = 0; | |
| 513 | + for (int x = 0; x < w; x++, xd++) { | |
| 514 | + for (int i = 0; i < dstNumBands; i++) { | |
| 515 | + sample = (int) (((dstLine[idx++] & 0xff) * | |
| 516 | + dstScaleFactor[i]) + 0.5f); | |
| 517 | + dst.setSample(xd, yd, i, sample); | |
| 518 | + } | |
| 519 | + } | |
| 520 | + } | |
| 521 | + } else { | |
| 522 | + short[] srcLine = new short[w * srcNumBands]; | |
| 523 | + short[] dstLine = new short[w * dstNumBands]; | |
| 524 | + int idx; | |
| 525 | + srcIL = new LCMSImageLayout( | |
| 526 | + srcLine, srcLine.length/getNumInComponents(), | |
| 527 | + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | | |
| 528 | + LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); | |
| 529 | + | |
| 530 | + dstIL = new LCMSImageLayout( | |
| 531 | + dstLine, dstLine.length/getNumOutComponents(), | |
| 532 | + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | | |
| 533 | + LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); | |
| 534 | + | |
| 535 | + // process each scanline | |
| 536 | + for (int y = 0; y < h; y++, ys++, yd++) { | |
| 537 | + // get src scanline | |
| 538 | + xs = src.getMinX(); | |
| 539 | + idx = 0; | |
| 540 | + for (int x = 0; x < w; x++, xs++) { | |
| 541 | + for (int i = 0; i < srcNumBands; i++) { | |
| 542 | + sample = src.getSample(xs, ys, i); | |
| 543 | + srcLine[idx++] = (short) | |
| 544 | + ((sample * srcScaleFactor[i]) + 0.5f); | |
| 545 | + } | |
| 546 | + } | |
| 547 | + | |
| 548 | + // color convert srcLine to dstLine | |
| 549 | + doTransform(srcIL, dstIL); | |
| 550 | + | |
| 551 | + // store dst scanline | |
| 552 | + xd = dst.getMinX(); | |
| 553 | + idx = 0; | |
| 554 | + for (int x = 0; x < w; x++, xd++) { | |
| 555 | + for (int i = 0; i < dstNumBands; i++) { | |
| 556 | + sample = (int) (((dstLine[idx++] & 0xffff) * | |
| 557 | + dstScaleFactor[i]) + 0.5f); | |
| 558 | + dst.setSample(xd, yd, i, sample); | |
| 559 | + } | |
| 560 | + } | |
| 561 | + } | |
| 562 | + } | |
| 563 | + } | |
| 564 | + | |
| 565 | + /* convert an array of colors in short format */ | |
| 566 | + /* each color is a contiguous set of array elements */ | |
| 567 | + /* the number of colors is (size of the array) / (number of input/output | |
| 568 | + components */ | |
| 569 | + public short[] colorConvert(short[] src, short[] dst) { | |
| 570 | + | |
| 571 | + if (dst == null) { | |
| 572 | + dst = new short [(src.length/getNumInComponents())*getNumOutComponents()]; | |
| 573 | + } | |
| 574 | + | |
| 575 | + LCMSImageLayout srcIL = new LCMSImageLayout( | |
| 576 | + src, src.length/getNumInComponents(), | |
| 577 | + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | | |
| 578 | + LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); | |
| 579 | + | |
| 580 | + LCMSImageLayout dstIL = new LCMSImageLayout( | |
| 581 | + dst, dst.length/getNumOutComponents(), | |
| 582 | + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | | |
| 583 | + LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); | |
| 584 | + | |
| 585 | + doTransform(srcIL, dstIL); | |
| 586 | + | |
| 587 | + return dst; | |
| 588 | + } | |
| 589 | + | |
| 590 | + public byte[] colorConvert(byte[] src, byte[] dst) { | |
| 591 | + if (dst == null) { | |
| 592 | + dst = new byte [(src.length/getNumInComponents())*getNumOutComponents()]; | |
| 593 | + } | |
| 594 | + | |
| 595 | + LCMSImageLayout srcIL = new LCMSImageLayout( | |
| 596 | + src, src.length/getNumInComponents(), | |
| 597 | + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | | |
| 598 | + LCMSImageLayout.BYTES_SH(1), getNumInComponents()); | |
| 599 | + | |
| 600 | + LCMSImageLayout dstIL = new LCMSImageLayout( | |
| 601 | + dst, dst.length/getNumOutComponents(), | |
| 602 | + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | | |
| 603 | + LCMSImageLayout.BYTES_SH(1), getNumOutComponents()); | |
| 604 | + | |
| 605 | + doTransform(srcIL, dstIL); | |
| 606 | + | |
| 607 | + return dst; | |
| 608 | + } | |
| 609 | +} | |
| @@ -0,0 +1,6 @@ | ||
| 1 | +<../../../../../../../mkconfig | |
| 2 | + | |
| 3 | +DIRS=\ | |
| 4 | + services\ | |
| 5 | + | |
| 6 | +<$ROOT/mkfiles/mksubdirs | |
| @@ -0,0 +1,2 @@ | ||
| 1 | +<../../../../../../../../mkconfig | |
| 2 | + | |
| @@ -0,0 +1,2 @@ | ||
| 1 | +# Little CMS color management module | |
| 2 | +sun.java2d.cmm.lcms.LCMS | |
| @@ -0,0 +1,14 @@ | ||
| 1 | +<../../../../../../mkconfig | |
| 2 | + | |
| 3 | +DIRS=\ | |
| 4 | + META-INF\ | |
| 5 | + | |
| 6 | +TARG=\ | |
| 7 | + LCMS.dis\ | |
| 8 | + LCMSImageLayout.dis\ | |
| 9 | + LCMSTransform.dis\ | |
| 10 | + | |
| 11 | +DISBIN=$ROOT/java/dis/java/java/sun/java2d/cmm/lcms | |
| 12 | + | |
| 13 | +<$ROOT/mkfiles/mkjava | |
| 14 | +<$ROOT/mkfiles/mksubdirs | |
| @@ -0,0 +1,17 @@ | ||
| 1 | +<../../../../../mkconfig | |
| 2 | + | |
| 3 | +DIRS=\ | |
| 4 | + lcms\ | |
| 5 | + | |
| 6 | +TARG=\ | |
| 7 | + CMSManager.dis\ | |
| 8 | + ColorTransform.dis\ | |
| 9 | + PCMM.dis\ | |
| 10 | + ProfileActivator.dis\ | |
| 11 | + ProfileDeferralInfo.dis\ | |
| 12 | + ProfileDeferralMgr.dis\ | |
| 13 | + | |
| 14 | +DISBIN=$ROOT/java/dis/java/java/sun/java2d/cmm | |
| 15 | + | |
| 16 | +<$ROOT/mkfiles/mkjava | |
| 17 | +<$ROOT/mkfiles/mksubdirs | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,332 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.loops; | |
| 27 | + | |
| 28 | +import java.awt.Composite; | |
| 29 | +import java.awt.CompositeContext; | |
| 30 | +import java.awt.RenderingHints; | |
| 31 | +import java.awt.image.ColorModel; | |
| 32 | +import java.awt.image.Raster; | |
| 33 | +import java.awt.image.WritableRaster; | |
| 34 | +import java.lang.ref.WeakReference; | |
| 35 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 36 | +import sun.java2d.SurfaceData; | |
| 37 | +import sun.java2d.pipe.Region; | |
| 38 | +import sun.java2d.pipe.SpanIterator; | |
| 39 | + | |
| 40 | +/** | |
| 41 | + * Blit | |
| 42 | + * 1) copies rectangle of pixels from one surface to another | |
| 43 | + * 2) performs compositing of colors based upon a Composite | |
| 44 | + * parameter | |
| 45 | + * | |
| 46 | + * precise behavior is undefined if the source surface | |
| 47 | + * and the destination surface are the same surface | |
| 48 | + * with overlapping regions of pixels | |
| 49 | + */ | |
| 50 | + | |
| 51 | +public class Blit extends GraphicsPrimitive | |
| 52 | +{ | |
| 53 | + public static final String methodSignature = "Blit(...)".toString(); | |
| 54 | + | |
| 55 | + public static final int primTypeID = makePrimTypeID(); | |
| 56 | + | |
| 57 | + private static RenderCache blitcache = new RenderCache(20); | |
| 58 | + | |
| 59 | + public static Blit locate(SurfaceType srctype, | |
| 60 | + CompositeType comptype, | |
| 61 | + SurfaceType dsttype) | |
| 62 | + { | |
| 63 | + return (Blit) | |
| 64 | + GraphicsPrimitiveMgr.locate(primTypeID, | |
| 65 | + srctype, comptype, dsttype); | |
| 66 | + } | |
| 67 | + | |
| 68 | + public static Blit getFromCache(SurfaceType src, | |
| 69 | + CompositeType comp, | |
| 70 | + SurfaceType dst) | |
| 71 | + { | |
| 72 | + Object o = blitcache.get(src, comp, dst); | |
| 73 | + if (o != null) { | |
| 74 | + return (Blit) o; | |
| 75 | + } | |
| 76 | + | |
| 77 | + Blit blit = locate(src, comp, dst); | |
| 78 | + if (blit == null) { | |
| 79 | + System.out.println("blit loop not found for:"); | |
| 80 | + System.out.println("src: "+src); | |
| 81 | + System.out.println("comp: "+comp); | |
| 82 | + System.out.println("dst: "+dst); | |
| 83 | + } else { | |
| 84 | + blitcache.put(src, comp, dst, blit); | |
| 85 | + } | |
| 86 | + return blit; | |
| 87 | + } | |
| 88 | + | |
| 89 | + protected Blit(SurfaceType srctype, | |
| 90 | + CompositeType comptype, | |
| 91 | + SurfaceType dsttype) | |
| 92 | + { | |
| 93 | + super(methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 94 | + } | |
| 95 | + | |
| 96 | + public Blit(long pNativePrim, | |
| 97 | + SurfaceType srctype, | |
| 98 | + CompositeType comptype, | |
| 99 | + SurfaceType dsttype) | |
| 100 | + { | |
| 101 | + super(pNativePrim, methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 102 | + } | |
| 103 | + | |
| 104 | + /** | |
| 105 | + * All Blit implementors must have this invoker method | |
| 106 | + */ | |
| 107 | + public native void Blit(SurfaceData src, SurfaceData dst, | |
| 108 | + Composite comp, Region clip, | |
| 109 | + int srcx, int srcy, | |
| 110 | + int dstx, int dsty, | |
| 111 | + int width, int height); | |
| 112 | + | |
| 113 | + static { | |
| 114 | + GraphicsPrimitiveMgr.registerGeneral(new Blit(null, null, null)); | |
| 115 | + } | |
| 116 | + | |
| 117 | + public GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 118 | + CompositeType comptype, | |
| 119 | + SurfaceType dsttype) | |
| 120 | + { | |
| 121 | + /* | |
| 122 | + System.out.println("Constructing general blit for:"); | |
| 123 | + System.out.println("src: "+srctype); | |
| 124 | + System.out.println("comp: "+comptype); | |
| 125 | + System.out.println("dst: "+dsttype); | |
| 126 | + */ | |
| 127 | + | |
| 128 | + if (comptype.isDerivedFrom(CompositeType.Xor)) { | |
| 129 | + GeneralXorBlit gxb = new GeneralXorBlit(srctype, | |
| 130 | + comptype, | |
| 131 | + dsttype); | |
| 132 | + setupGeneralBinaryOp(gxb); | |
| 133 | + return gxb; | |
| 134 | + } else if (comptype.isDerivedFrom(CompositeType.AnyAlpha)) { | |
| 135 | + return new GeneralMaskBlit(srctype, comptype, dsttype); | |
| 136 | + } else { | |
| 137 | + return AnyBlit.instance; | |
| 138 | + } | |
| 139 | + } | |
| 140 | + | |
| 141 | + private static class AnyBlit extends Blit { | |
| 142 | + public static AnyBlit instance = new AnyBlit(); | |
| 143 | + | |
| 144 | + public AnyBlit() { | |
| 145 | + super(SurfaceType.Any, CompositeType.Any, SurfaceType.Any); | |
| 146 | + } | |
| 147 | + | |
| 148 | + public void Blit(SurfaceData srcData, | |
| 149 | + SurfaceData dstData, | |
| 150 | + Composite comp, | |
| 151 | + Region clip, | |
| 152 | + int srcx, int srcy, | |
| 153 | + int dstx, int dsty, | |
| 154 | + int width, int height) | |
| 155 | + { | |
| 156 | + ColorModel srcCM = srcData.getColorModel(); | |
| 157 | + ColorModel dstCM = dstData.getColorModel(); | |
| 158 | + // REMIND: Should get RenderingHints from sg2d | |
| 159 | + CompositeContext ctx = comp.createContext(srcCM, dstCM, | |
| 160 | + new RenderingHints(null)); | |
| 161 | + Raster srcRas = srcData.getRaster(srcx, srcy, width, height); | |
| 162 | + WritableRaster dstRas = | |
| 163 | + (WritableRaster) dstData.getRaster(dstx, dsty, width, height); | |
| 164 | + | |
| 165 | + if (clip == null) { | |
| 166 | + clip = Region.getInstanceXYWH(dstx, dsty, width, height); | |
| 167 | + } | |
| 168 | + int span[] = {dstx, dsty, dstx+width, dsty+height}; | |
| 169 | + SpanIterator si = clip.getSpanIterator(span); | |
| 170 | + srcx -= dstx; | |
| 171 | + srcy -= dsty; | |
| 172 | + while (si.nextSpan(span)) { | |
| 173 | + int w = span[2] - span[0]; | |
| 174 | + int h = span[3] - span[1]; | |
| 175 | + srcRas = srcRas.createChild(srcx + span[0], srcy + span[1], | |
| 176 | + w, h, 0, 0, null); | |
| 177 | + dstRas = dstRas.createWritableChild(span[0], span[1], | |
| 178 | + w, h, 0, 0, null); | |
| 179 | + ctx.compose(srcRas, dstRas, dstRas); | |
| 180 | + } | |
| 181 | + ctx.dispose(); | |
| 182 | + } | |
| 183 | + } | |
| 184 | + | |
| 185 | + private static class GeneralMaskBlit extends Blit { | |
| 186 | + MaskBlit performop; | |
| 187 | + | |
| 188 | + public GeneralMaskBlit(SurfaceType srctype, | |
| 189 | + CompositeType comptype, | |
| 190 | + SurfaceType dsttype) | |
| 191 | + { | |
| 192 | + super(srctype, comptype, dsttype); | |
| 193 | + performop = MaskBlit.locate(srctype, comptype, dsttype); | |
| 194 | + } | |
| 195 | + | |
| 196 | + public void Blit(SurfaceData srcData, | |
| 197 | + SurfaceData dstData, | |
| 198 | + Composite comp, | |
| 199 | + Region clip, | |
| 200 | + int srcx, int srcy, | |
| 201 | + int dstx, int dsty, | |
| 202 | + int width, int height) | |
| 203 | + { | |
| 204 | + performop.MaskBlit(srcData, dstData, comp, clip, | |
| 205 | + srcx, srcy, dstx, dsty, | |
| 206 | + width, height, | |
| 207 | + null, 0, 0); | |
| 208 | + } | |
| 209 | + } | |
| 210 | + | |
| 211 | + private static class GeneralXorBlit | |
| 212 | + extends Blit | |
| 213 | + implements GeneralBinaryOp | |
| 214 | + { | |
| 215 | + Blit convertsrc; | |
| 216 | + Blit convertdst; | |
| 217 | + Blit performop; | |
| 218 | + Blit convertresult; | |
| 219 | + | |
| 220 | + WeakReference srcTmp; | |
| 221 | + WeakReference dstTmp; | |
| 222 | + | |
| 223 | + public GeneralXorBlit(SurfaceType srctype, | |
| 224 | + CompositeType comptype, | |
| 225 | + SurfaceType dsttype) | |
| 226 | + { | |
| 227 | + super(srctype, comptype, dsttype); | |
| 228 | + } | |
| 229 | + | |
| 230 | + public void setPrimitives(Blit srcconverter, | |
| 231 | + Blit dstconverter, | |
| 232 | + GraphicsPrimitive genericop, | |
| 233 | + Blit resconverter) | |
| 234 | + { | |
| 235 | + this.convertsrc = srcconverter; | |
| 236 | + this.convertdst = dstconverter; | |
| 237 | + this.performop = (Blit) genericop; | |
| 238 | + this.convertresult = resconverter; | |
| 239 | + } | |
| 240 | + | |
| 241 | + public synchronized void Blit(SurfaceData srcData, | |
| 242 | + SurfaceData dstData, | |
| 243 | + Composite comp, | |
| 244 | + Region clip, | |
| 245 | + int srcx, int srcy, | |
| 246 | + int dstx, int dsty, | |
| 247 | + int width, int height) | |
| 248 | + { | |
| 249 | + SurfaceData src, dst; | |
| 250 | + Region opclip; | |
| 251 | + int sx, sy, dx, dy; | |
| 252 | + | |
| 253 | + if (convertsrc == null) { | |
| 254 | + src = srcData; | |
| 255 | + sx = srcx; | |
| 256 | + sy = srcy; | |
| 257 | + } else { | |
| 258 | + SurfaceData cachedSrc = null; | |
| 259 | + if (srcTmp != null) { | |
| 260 | + cachedSrc = (SurfaceData) srcTmp.get(); | |
| 261 | + } | |
| 262 | + src = convertFrom(convertsrc, srcData, srcx, srcy, | |
| 263 | + width, height, cachedSrc); | |
| 264 | + sx = 0; | |
| 265 | + sy = 0; | |
| 266 | + if (src != cachedSrc) { | |
| 267 | + srcTmp = new WeakReference(src); | |
| 268 | + } | |
| 269 | + } | |
| 270 | + | |
| 271 | + if (convertdst == null) { | |
| 272 | + dst = dstData; | |
| 273 | + dx = dstx; | |
| 274 | + dy = dsty; | |
| 275 | + opclip = clip; | |
| 276 | + } else { | |
| 277 | + // assert: convertresult != null | |
| 278 | + SurfaceData cachedDst = null; | |
| 279 | + if (dstTmp != null) { | |
| 280 | + cachedDst = (SurfaceData) dstTmp.get(); | |
| 281 | + } | |
| 282 | + dst = convertFrom(convertdst, dstData, dstx, dsty, | |
| 283 | + width, height, cachedDst); | |
| 284 | + dx = 0; | |
| 285 | + dy = 0; | |
| 286 | + opclip = null; | |
| 287 | + if (dst != cachedDst) { | |
| 288 | + dstTmp = new WeakReference(dst); | |
| 289 | + } | |
| 290 | + } | |
| 291 | + | |
| 292 | + performop.Blit(src, dst, comp, opclip, | |
| 293 | + sx, sy, dx, dy, | |
| 294 | + width, height); | |
| 295 | + | |
| 296 | + if (convertresult != null) { | |
| 297 | + // assert: convertdst != null | |
| 298 | + convertTo(convertresult, dst, dstData, clip, | |
| 299 | + dstx, dsty, width, height); | |
| 300 | + } | |
| 301 | + } | |
| 302 | + } | |
| 303 | + | |
| 304 | + public GraphicsPrimitive traceWrap() { | |
| 305 | + return new TraceBlit(this); | |
| 306 | + } | |
| 307 | + | |
| 308 | + private static class TraceBlit extends Blit { | |
| 309 | + Blit target; | |
| 310 | + | |
| 311 | + public TraceBlit(Blit target) { | |
| 312 | + super(target.getSourceType(), | |
| 313 | + target.getCompositeType(), | |
| 314 | + target.getDestType()); | |
| 315 | + this.target = target; | |
| 316 | + } | |
| 317 | + | |
| 318 | + public GraphicsPrimitive traceWrap() { | |
| 319 | + return this; | |
| 320 | + } | |
| 321 | + | |
| 322 | + public void Blit(SurfaceData src, SurfaceData dst, | |
| 323 | + Composite comp, Region clip, | |
| 324 | + int srcx, int srcy, int dstx, int dsty, | |
| 325 | + int width, int height) | |
| 326 | + { | |
| 327 | + tracePrimitive(target); | |
| 328 | + target.Blit(src, dst, comp, clip, | |
| 329 | + srcx, srcy, dstx, dsty, width, height); | |
| 330 | + } | |
| 331 | + } | |
| 332 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,217 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.loops; | |
| 27 | + | |
| 28 | +import java.awt.Font; | |
| 29 | +import java.awt.Color; | |
| 30 | +import java.awt.Composite; | |
| 31 | +import java.awt.AlphaComposite; | |
| 32 | +import java.awt.Transparency; | |
| 33 | +import java.awt.image.ColorModel; | |
| 34 | +import java.awt.image.WritableRaster; | |
| 35 | +import java.awt.image.BufferedImage; | |
| 36 | +import sun.awt.image.BufImgSurfaceData; | |
| 37 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 38 | +import sun.java2d.SurfaceData; | |
| 39 | +import sun.java2d.SunGraphics2D; | |
| 40 | +import sun.java2d.pipe.Region; | |
| 41 | + | |
| 42 | +/** | |
| 43 | + * BlitBg | |
| 44 | + * 1) copies rectangle of pixels from one surface to another | |
| 45 | + * 2) performs compositing of colors based upon a Composite | |
| 46 | + * parameter | |
| 47 | + * 3) assumes that non-opaque pixels are to be blended with | |
| 48 | + * the indicated Bg color before compositing with the | |
| 49 | + * destination | |
| 50 | + * | |
| 51 | + * precise behavior is undefined if the source surface | |
| 52 | + * and the destination surface are the same surface | |
| 53 | + * with overlapping regions of pixels | |
| 54 | + */ | |
| 55 | +public class BlitBg extends GraphicsPrimitive | |
| 56 | +{ | |
| 57 | + public static final String methodSignature = "BlitBg(...)".toString(); | |
| 58 | + | |
| 59 | + public static final int primTypeID = makePrimTypeID(); | |
| 60 | + | |
| 61 | + private static RenderCache blitcache = new RenderCache(20); | |
| 62 | + | |
| 63 | + public static BlitBg locate(SurfaceType srctype, | |
| 64 | + CompositeType comptype, | |
| 65 | + SurfaceType dsttype) | |
| 66 | + { | |
| 67 | + return (BlitBg) | |
| 68 | + GraphicsPrimitiveMgr.locate(primTypeID, | |
| 69 | + srctype, comptype, dsttype); | |
| 70 | + } | |
| 71 | + | |
| 72 | + public static BlitBg getFromCache(SurfaceType src, | |
| 73 | + CompositeType comp, | |
| 74 | + SurfaceType dst) | |
| 75 | + { | |
| 76 | + Object o = blitcache.get(src, comp, dst); | |
| 77 | + if (o != null) { | |
| 78 | + return (BlitBg) o; | |
| 79 | + } | |
| 80 | + BlitBg blit = locate(src, comp, dst); | |
| 81 | + if (blit == null) { | |
| 82 | + System.out.println("blitbg loop not found for:"); | |
| 83 | + System.out.println("src: "+src); | |
| 84 | + System.out.println("comp: "+comp); | |
| 85 | + System.out.println("dst: "+dst); | |
| 86 | + } else { | |
| 87 | + blitcache.put(src, comp, dst, blit); | |
| 88 | + } | |
| 89 | + return blit; | |
| 90 | + } | |
| 91 | + | |
| 92 | + protected BlitBg(SurfaceType srctype, | |
| 93 | + CompositeType comptype, | |
| 94 | + SurfaceType dsttype) | |
| 95 | + { | |
| 96 | + super(methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 97 | + } | |
| 98 | + | |
| 99 | + public BlitBg(long pNativePrim, | |
| 100 | + SurfaceType srctype, | |
| 101 | + CompositeType comptype, | |
| 102 | + SurfaceType dsttype) | |
| 103 | + { | |
| 104 | + super(pNativePrim, methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 105 | + } | |
| 106 | + | |
| 107 | + /** | |
| 108 | + * All BlitBg implementors must have this invoker method | |
| 109 | + */ | |
| 110 | + public native void BlitBg(SurfaceData src, SurfaceData dst, | |
| 111 | + Composite comp, Region clip, | |
| 112 | + int bgColor, | |
| 113 | + int srcx, int srcy, | |
| 114 | + int dstx, int dsty, | |
| 115 | + int width, int height); | |
| 116 | + | |
| 117 | + static { | |
| 118 | + GraphicsPrimitiveMgr.registerGeneral(new BlitBg(null, null, null)); | |
| 119 | + } | |
| 120 | + | |
| 121 | + public GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 122 | + CompositeType comptype, | |
| 123 | + SurfaceType dsttype) | |
| 124 | + { | |
| 125 | + /* | |
| 126 | + System.out.println("Constructing general blitbg for:"); | |
| 127 | + System.out.println("src: "+srctype); | |
| 128 | + System.out.println("comp: "+comptype); | |
| 129 | + System.out.println("dst: "+dsttype); | |
| 130 | + */ | |
| 131 | + return new General(srctype, comptype, dsttype); | |
| 132 | + } | |
| 133 | + | |
| 134 | + private static class General extends BlitBg { | |
| 135 | + CompositeType compositeType; | |
| 136 | + | |
| 137 | + public General(SurfaceType srctype, | |
| 138 | + CompositeType comptype, | |
| 139 | + SurfaceType dsttype) | |
| 140 | + { | |
| 141 | + super(srctype, comptype, dsttype); | |
| 142 | + compositeType = comptype; | |
| 143 | + } | |
| 144 | + | |
| 145 | + @Override | |
| 146 | + public void BlitBg(SurfaceData srcData, | |
| 147 | + SurfaceData dstData, | |
| 148 | + Composite comp, | |
| 149 | + Region clip, | |
| 150 | + int bgArgb, | |
| 151 | + int srcx, int srcy, | |
| 152 | + int dstx, int dsty, | |
| 153 | + int width, int height) | |
| 154 | + { | |
| 155 | + ColorModel dstModel = dstData.getColorModel(); | |
| 156 | + boolean bgHasAlpha = (bgArgb >>> 24) != 0xff; | |
| 157 | + if (!dstModel.hasAlpha() && bgHasAlpha) { | |
| 158 | + dstModel = ColorModel.getRGBdefault(); | |
| 159 | + } | |
| 160 | + WritableRaster wr = | |
| 161 | + dstModel.createCompatibleWritableRaster(width, height); | |
| 162 | + boolean isPremult = dstModel.isAlphaPremultiplied(); | |
| 163 | + BufferedImage bimg = | |
| 164 | + new BufferedImage(dstModel, wr, isPremult, null); | |
| 165 | + SurfaceData tmpData = BufImgSurfaceData.createData(bimg); | |
| 166 | + Color bgColor = new Color(bgArgb, bgHasAlpha); | |
| 167 | + SunGraphics2D sg2d = new SunGraphics2D(tmpData, bgColor, bgColor, | |
| 168 | + defaultFont); | |
| 169 | + FillRect fillop = FillRect.locate(SurfaceType.AnyColor, | |
| 170 | + CompositeType.SrcNoEa, | |
| 171 | + tmpData.getSurfaceType()); | |
| 172 | + Blit combineop = Blit.getFromCache(srcData.getSurfaceType(), | |
| 173 | + CompositeType.SrcOverNoEa, | |
| 174 | + tmpData.getSurfaceType()); | |
| 175 | + Blit blitop = Blit.getFromCache(tmpData.getSurfaceType(), compositeType, | |
| 176 | + dstData.getSurfaceType()); | |
| 177 | + fillop.FillRect(sg2d, tmpData, 0, 0, width, height); | |
| 178 | + combineop.Blit(srcData, tmpData, AlphaComposite.SrcOver, null, | |
| 179 | + srcx, srcy, 0, 0, width, height); | |
| 180 | + blitop.Blit(tmpData, dstData, comp, clip, | |
| 181 | + 0, 0, dstx, dsty, width, height); | |
| 182 | + } | |
| 183 | + | |
| 184 | + private static Font defaultFont = new Font("Dialog", Font.PLAIN, 12); | |
| 185 | + } | |
| 186 | + | |
| 187 | + public GraphicsPrimitive traceWrap() { | |
| 188 | + return new TraceBlitBg(this); | |
| 189 | + } | |
| 190 | + | |
| 191 | + private static class TraceBlitBg extends BlitBg { | |
| 192 | + BlitBg target; | |
| 193 | + | |
| 194 | + public TraceBlitBg(BlitBg target) { | |
| 195 | + super(target.getSourceType(), | |
| 196 | + target.getCompositeType(), | |
| 197 | + target.getDestType()); | |
| 198 | + this.target = target; | |
| 199 | + } | |
| 200 | + | |
| 201 | + public GraphicsPrimitive traceWrap() { | |
| 202 | + return this; | |
| 203 | + } | |
| 204 | + | |
| 205 | + @Override | |
| 206 | + public void BlitBg(SurfaceData src, SurfaceData dst, | |
| 207 | + Composite comp, Region clip, | |
| 208 | + int bgColor, | |
| 209 | + int srcx, int srcy, int dstx, int dsty, | |
| 210 | + int width, int height) | |
| 211 | + { | |
| 212 | + tracePrimitive(target); | |
| 213 | + target.BlitBg(src, dst, comp, clip, bgColor, | |
| 214 | + srcx, srcy, dstx, dsty, width, height); | |
| 215 | + } | |
| 216 | + } | |
| 217 | +} | |
Binary file not shown.
| @@ -0,0 +1,295 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.loops; | |
| 27 | + | |
| 28 | +import java.awt.image.BufferedImage; | |
| 29 | +import java.awt.AlphaComposite; | |
| 30 | +import java.util.HashMap; | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * A CompositeType object provides a chained description of a type of | |
| 34 | + * algorithm for color compositing. The object will provide a single | |
| 35 | + * String constant descriptor which is one way of describing a particular | |
| 36 | + * compositing algorithm as well as a pointer to another CompositeType | |
| 37 | + * which describes a more general algorithm for achieving the same result. | |
| 38 | + * <p> | |
| 39 | + * A description of a more specific algorithm is considered a "subtype" | |
| 40 | + * and a description of a more general algorithm is considered a "supertype". | |
| 41 | + * Thus, the deriveSubType method provides a way to create a new CompositeType | |
| 42 | + * that is related to but more specific than an existing CompositeType and | |
| 43 | + * the getSuperType method provides a way to ask a given CompositeType | |
| 44 | + * for a more general algorithm to achieve the same result. | |
| 45 | + * <p> | |
| 46 | + * Note that you cannot construct a brand new root for a chain since | |
| 47 | + * the constructor is private. Every chain of types must at some point | |
| 48 | + * derive from the Any node provided here using the deriveSubType() | |
| 49 | + * method. The presence of this common Any node on every chain | |
| 50 | + * ensures that all chains end with the DESC_ANY descriptor so that | |
| 51 | + * a suitable General GraphicsPrimitive object can be obtained for | |
| 52 | + * the indicated algorithm if all of the more specific searches fail. | |
| 53 | + */ | |
| 54 | +public final class CompositeType { | |
| 55 | + | |
| 56 | + private static int unusedUID = 1; | |
| 57 | + private static final HashMap<String,Integer> compositeUIDMap = | |
| 58 | + new HashMap<String,Integer>(100); | |
| 59 | + | |
| 60 | + /* | |
| 61 | + * CONSTANTS USED BY ALL PRIMITIVES TO DESCRIBE THE COMPOSITING | |
| 62 | + * ALGORITHMS THEY CAN PERFORM | |
| 63 | + */ | |
| 64 | + | |
| 65 | + /** | |
| 66 | + * algorithm is a general algorithm that uses a CompositeContext | |
| 67 | + * to do the rendering. | |
| 68 | + */ | |
| 69 | + public static final String DESC_ANY = "Any CompositeContext"; | |
| 70 | + | |
| 71 | + /** | |
| 72 | + * constant used to describe the Graphics.setXORMode() algorithm | |
| 73 | + */ | |
| 74 | + public static final String DESC_XOR = "XOR mode"; | |
| 75 | + | |
| 76 | + /** | |
| 77 | + * constants used to describe the various AlphaComposite | |
| 78 | + * algorithms. | |
| 79 | + */ | |
| 80 | + public static final String DESC_CLEAR = "Porter-Duff Clear"; | |
| 81 | + public static final String DESC_SRC = "Porter-Duff Src"; | |
| 82 | + public static final String DESC_DST = "Porter-Duff Dst"; | |
| 83 | + public static final String DESC_SRC_OVER = "Porter-Duff Src Over Dst"; | |
| 84 | + public static final String DESC_DST_OVER = "Porter-Duff Dst Over Src"; | |
| 85 | + public static final String DESC_SRC_IN = "Porter-Duff Src In Dst"; | |
| 86 | + public static final String DESC_DST_IN = "Porter-Duff Dst In Src"; | |
| 87 | + public static final String DESC_SRC_OUT = "Porter-Duff Src HeldOutBy Dst"; | |
| 88 | + public static final String DESC_DST_OUT = "Porter-Duff Dst HeldOutBy Src"; | |
| 89 | + public static final String DESC_SRC_ATOP = "Porter-Duff Src Atop Dst"; | |
| 90 | + public static final String DESC_DST_ATOP = "Porter-Duff Dst Atop Src"; | |
| 91 | + public static final String DESC_ALPHA_XOR = "Porter-Duff Xor"; | |
| 92 | + | |
| 93 | + /** | |
| 94 | + * constants used to describe the two common cases of | |
| 95 | + * AlphaComposite algorithms that are simpler if there | |
| 96 | + * is not extraAlpha. | |
| 97 | + */ | |
| 98 | + public static final String | |
| 99 | + DESC_SRC_NO_EA = "Porter-Duff Src, No Extra Alpha"; | |
| 100 | + public static final String | |
| 101 | + DESC_SRC_OVER_NO_EA = "Porter-Duff SrcOverDst, No Extra Alpha"; | |
| 102 | + | |
| 103 | + /** | |
| 104 | + * constant used to describe an algorithm that implements all 8 of | |
| 105 | + * the Porter-Duff rules in one Primitive. | |
| 106 | + */ | |
| 107 | + public static final String DESC_ANY_ALPHA = "Any AlphaComposite Rule"; | |
| 108 | + | |
| 109 | + /* | |
| 110 | + * END OF COMPOSITE ALGORITHM TYPE CONSTANTS | |
| 111 | + */ | |
| 112 | + | |
| 113 | + /** | |
| 114 | + * The root CompositeType object for all chains of algorithm descriptions. | |
| 115 | + */ | |
| 116 | + public static final CompositeType | |
| 117 | + Any = new CompositeType(null, DESC_ANY); | |
| 118 | + | |
| 119 | + /* | |
| 120 | + * START OF CompositeeType OBJECTS FOR THE VARIOUS CONSTANTS | |
| 121 | + */ | |
| 122 | + | |
| 123 | + public static final CompositeType | |
| 124 | + General = Any; | |
| 125 | + | |
| 126 | + public static final CompositeType | |
| 127 | + AnyAlpha = General.deriveSubType(DESC_ANY_ALPHA); | |
| 128 | + public static final CompositeType | |
| 129 | + Xor = General.deriveSubType(DESC_XOR); | |
| 130 | + | |
| 131 | + public static final CompositeType | |
| 132 | + Clear = AnyAlpha.deriveSubType(DESC_CLEAR); | |
| 133 | + public static final CompositeType | |
| 134 | + Src = AnyAlpha.deriveSubType(DESC_SRC); | |
| 135 | + public static final CompositeType | |
| 136 | + Dst = AnyAlpha.deriveSubType(DESC_DST); | |
| 137 | + public static final CompositeType | |
| 138 | + SrcOver = AnyAlpha.deriveSubType(DESC_SRC_OVER); | |
| 139 | + public static final CompositeType | |
| 140 | + DstOver = AnyAlpha.deriveSubType(DESC_DST_OVER); | |
| 141 | + public static final CompositeType | |
| 142 | + SrcIn = AnyAlpha.deriveSubType(DESC_SRC_IN); | |
| 143 | + public static final CompositeType | |
| 144 | + DstIn = AnyAlpha.deriveSubType(DESC_DST_IN); | |
| 145 | + public static final CompositeType | |
| 146 | + SrcOut = AnyAlpha.deriveSubType(DESC_SRC_OUT); | |
| 147 | + public static final CompositeType | |
| 148 | + DstOut = AnyAlpha.deriveSubType(DESC_DST_OUT); | |
| 149 | + public static final CompositeType | |
| 150 | + SrcAtop = AnyAlpha.deriveSubType(DESC_SRC_ATOP); | |
| 151 | + public static final CompositeType | |
| 152 | + DstAtop = AnyAlpha.deriveSubType(DESC_DST_ATOP); | |
| 153 | + public static final CompositeType | |
| 154 | + AlphaXor = AnyAlpha.deriveSubType(DESC_ALPHA_XOR); | |
| 155 | + | |
| 156 | + public static final CompositeType | |
| 157 | + SrcNoEa = Src.deriveSubType(DESC_SRC_NO_EA); | |
| 158 | + public static final CompositeType | |
| 159 | + SrcOverNoEa = SrcOver.deriveSubType(DESC_SRC_OVER_NO_EA); | |
| 160 | + | |
| 161 | + /* | |
| 162 | + * A special CompositeType for the case where we are filling in | |
| 163 | + * SrcOverNoEa mode with an opaque color. In that case then the | |
| 164 | + * best loop for us to use would be a SrcNoEa loop, but what if | |
| 165 | + * there is no such loop? In that case then we would end up | |
| 166 | + * backing off to a Src loop (which should still be fine) or an | |
| 167 | + * AnyAlpha loop which would be slower than a SrcOver loop in | |
| 168 | + * most cases. | |
| 169 | + * The fix is to use the following chain which looks for loops | |
| 170 | + * in the following order: | |
| 171 | + * SrcNoEa, Src, SrcOverNoEa, SrcOver, AnyAlpha | |
| 172 | + */ | |
| 173 | + public static final CompositeType | |
| 174 | + OpaqueSrcOverNoEa = SrcOverNoEa.deriveSubType(DESC_SRC) | |
| 175 | + .deriveSubType(DESC_SRC_NO_EA); | |
| 176 | + | |
| 177 | + /* | |
| 178 | + * END OF CompositeType OBJECTS FOR THE VARIOUS CONSTANTS | |
| 179 | + */ | |
| 180 | + | |
| 181 | + /** | |
| 182 | + * Return a new CompositeType object which uses this object as its | |
| 183 | + * more general "supertype" descriptor. If no operation can be | |
| 184 | + * found that implements the algorithm described more exactly | |
| 185 | + * by desc, then this object will define the more general | |
| 186 | + * compositing algorithm that can be used instead. | |
| 187 | + */ | |
| 188 | + public CompositeType deriveSubType(String desc) { | |
| 189 | + return new CompositeType(this, desc); | |
| 190 | + } | |
| 191 | + | |
| 192 | + /** | |
| 193 | + * Return a CompositeType object for the specified AlphaComposite | |
| 194 | + * rule. | |
| 195 | + */ | |
| 196 | + public static CompositeType forAlphaComposite(AlphaComposite ac) { | |
| 197 | + switch (ac.getRule()) { | |
| 198 | + case AlphaComposite.CLEAR: | |
| 199 | + return Clear; | |
| 200 | + case AlphaComposite.SRC: | |
| 201 | + if (ac.getAlpha() >= 1.0f) { | |
| 202 | + return SrcNoEa; | |
| 203 | + } else { | |
| 204 | + return Src; | |
| 205 | + } | |
| 206 | + case AlphaComposite.DST: | |
| 207 | + return Dst; | |
| 208 | + case AlphaComposite.SRC_OVER: | |
| 209 | + if (ac.getAlpha() >= 1.0f) { | |
| 210 | + return SrcOverNoEa; | |
| 211 | + } else { | |
| 212 | + return SrcOver; | |
| 213 | + } | |
| 214 | + case AlphaComposite.DST_OVER: | |
| 215 | + return DstOver; | |
| 216 | + case AlphaComposite.SRC_IN: | |
| 217 | + return SrcIn; | |
| 218 | + case AlphaComposite.DST_IN: | |
| 219 | + return DstIn; | |
| 220 | + case AlphaComposite.SRC_OUT: | |
| 221 | + return SrcOut; | |
| 222 | + case AlphaComposite.DST_OUT: | |
| 223 | + return DstOut; | |
| 224 | + case AlphaComposite.SRC_ATOP: | |
| 225 | + return SrcAtop; | |
| 226 | + case AlphaComposite.DST_ATOP: | |
| 227 | + return DstAtop; | |
| 228 | + case AlphaComposite.XOR: | |
| 229 | + return AlphaXor; | |
| 230 | + default: | |
| 231 | + throw new InternalError("Unrecognized alpha rule"); | |
| 232 | + } | |
| 233 | + } | |
| 234 | + | |
| 235 | + private int uniqueID; | |
| 236 | + private String desc; | |
| 237 | + private CompositeType next; | |
| 238 | + | |
| 239 | + private CompositeType(CompositeType parent, String desc) { | |
| 240 | + next = parent; | |
| 241 | + this.desc = desc; | |
| 242 | + this.uniqueID = makeUniqueID(desc); | |
| 243 | + } | |
| 244 | + | |
| 245 | + public synchronized static final int makeUniqueID(String desc) { | |
| 246 | + Integer i = compositeUIDMap.get(desc); | |
| 247 | + | |
| 248 | + if (i == null) { | |
| 249 | + if (unusedUID > 255) { | |
| 250 | + throw new InternalError("composite type id overflow"); | |
| 251 | + } | |
| 252 | + i = unusedUID++; | |
| 253 | + compositeUIDMap.put(desc, i); | |
| 254 | + } | |
| 255 | + return i; | |
| 256 | + } | |
| 257 | + | |
| 258 | + public int getUniqueID() { | |
| 259 | + return uniqueID; | |
| 260 | + } | |
| 261 | + | |
| 262 | + public String getDescriptor() { | |
| 263 | + return desc; | |
| 264 | + } | |
| 265 | + | |
| 266 | + public CompositeType getSuperType() { | |
| 267 | + return next; | |
| 268 | + } | |
| 269 | + | |
| 270 | + public int hashCode() { | |
| 271 | + return desc.hashCode(); | |
| 272 | + } | |
| 273 | + | |
| 274 | + public boolean isDerivedFrom(CompositeType other) { | |
| 275 | + CompositeType comptype = this; | |
| 276 | + do { | |
| 277 | + if (comptype.desc == other.desc) { | |
| 278 | + return true; | |
| 279 | + } | |
| 280 | + comptype = comptype.next; | |
| 281 | + } while (comptype != null); | |
| 282 | + return false; | |
| 283 | + } | |
| 284 | + | |
| 285 | + public boolean equals(Object o) { | |
| 286 | + if (o instanceof CompositeType) { | |
| 287 | + return (((CompositeType) o).uniqueID == this.uniqueID); | |
| 288 | + } | |
| 289 | + return false; | |
| 290 | + } | |
| 291 | + | |
| 292 | + public String toString() { | |
| 293 | + return desc; | |
| 294 | + } | |
| 295 | +} | |
Binary file not shown.
| @@ -0,0 +1,329 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +/* | |
| 27 | + * @author Charlton Innovations, Inc. | |
| 28 | + * @author Jim Graham | |
| 29 | + */ | |
| 30 | + | |
| 31 | +package sun.java2d.loops; | |
| 32 | + | |
| 33 | +import java.awt.Composite; | |
| 34 | +import java.awt.Rectangle; | |
| 35 | +import java.awt.image.ColorModel; | |
| 36 | +import java.awt.image.DataBuffer; | |
| 37 | +import java.awt.image.Raster; | |
| 38 | +import java.awt.image.WritableRaster; | |
| 39 | +import sun.awt.image.IntegerComponentRaster; | |
| 40 | +import sun.java2d.SurfaceData; | |
| 41 | +import sun.java2d.pipe.Region; | |
| 42 | +import sun.java2d.pipe.SpanIterator; | |
| 43 | + | |
| 44 | +/** | |
| 45 | + * CustomComponent, collection of GraphicsPrimitive | |
| 46 | + * Basically, this collection of components performs conversion from | |
| 47 | + * ANY to ANY via opaque copy | |
| 48 | + */ | |
| 49 | +public final class CustomComponent { | |
| 50 | + public static void register() { | |
| 51 | + // REMIND: This does not work for all destinations yet since | |
| 52 | + // the screen SurfaceData objects do not implement getRaster | |
| 53 | + Class owner = CustomComponent.class; | |
| 54 | + GraphicsPrimitive[] primitives = { | |
| 55 | + new GraphicsPrimitiveProxy(owner, "OpaqueCopyAnyToArgb", | |
| 56 | + Blit.methodSignature, | |
| 57 | + Blit.primTypeID, | |
| 58 | + SurfaceType.Any, | |
| 59 | + CompositeType.SrcNoEa, | |
| 60 | + SurfaceType.IntArgb), | |
| 61 | + new GraphicsPrimitiveProxy(owner, "OpaqueCopyArgbToAny", | |
| 62 | + Blit.methodSignature, | |
| 63 | + Blit.primTypeID, | |
| 64 | + SurfaceType.IntArgb, | |
| 65 | + CompositeType.SrcNoEa, | |
| 66 | + SurfaceType.Any), | |
| 67 | + new GraphicsPrimitiveProxy(owner, "XorCopyArgbToAny", | |
| 68 | + Blit.methodSignature, | |
| 69 | + Blit.primTypeID, | |
| 70 | + SurfaceType.IntArgb, | |
| 71 | + CompositeType.Xor, | |
| 72 | + SurfaceType.Any), | |
| 73 | + }; | |
| 74 | + GraphicsPrimitiveMgr.register(primitives); | |
| 75 | + } | |
| 76 | + | |
| 77 | + public static Region getRegionOfInterest(SurfaceData src, SurfaceData dst, | |
| 78 | + Region clip, | |
| 79 | + int srcx, int srcy, | |
| 80 | + int dstx, int dsty, | |
| 81 | + int w, int h) | |
| 82 | + { | |
| 83 | + /* | |
| 84 | + * Intersect all of: | |
| 85 | + * - operation area (dstx, dsty, w, h) | |
| 86 | + * - destination bounds | |
| 87 | + * - (translated) src bounds | |
| 88 | + * - supplied clip (may be non-rectangular) | |
| 89 | + * Intersect the rectangular regions first since those are | |
| 90 | + * simpler operations. | |
| 91 | + */ | |
| 92 | + Region ret = Region.getInstanceXYWH(dstx, dsty, w, h); | |
| 93 | + ret = ret.getIntersection(dst.getBounds()); | |
| 94 | + Rectangle r = src.getBounds(); | |
| 95 | + // srcxy in src space maps to dstxy in dst space | |
| 96 | + r.translate(dstx - srcx, dsty - srcy); | |
| 97 | + ret = ret.getIntersection(r); | |
| 98 | + if (clip != null) { | |
| 99 | + // Intersect with clip last since it may be non-rectangular | |
| 100 | + ret = ret.getIntersection(clip); | |
| 101 | + } | |
| 102 | + return ret; | |
| 103 | + } | |
| 104 | +} | |
| 105 | + | |
| 106 | +/** | |
| 107 | + * ANY format to ARGB format Blit | |
| 108 | + */ | |
| 109 | +class OpaqueCopyAnyToArgb extends Blit { | |
| 110 | + OpaqueCopyAnyToArgb() { | |
| 111 | + super(SurfaceType.Any, | |
| 112 | + CompositeType.SrcNoEa, | |
| 113 | + SurfaceType.IntArgb); | |
| 114 | + } | |
| 115 | + | |
| 116 | + public void Blit(SurfaceData src, SurfaceData dst, | |
| 117 | + Composite comp, Region clip, | |
| 118 | + int srcx, int srcy, int dstx, int dsty, int w, int h) | |
| 119 | + { | |
| 120 | + Raster srcRast = src.getRaster(srcx, srcy, w, h); | |
| 121 | + ColorModel srcCM = src.getColorModel(); | |
| 122 | + | |
| 123 | + Raster dstRast = dst.getRaster(dstx, dsty, w, h); | |
| 124 | + IntegerComponentRaster icr = (IntegerComponentRaster) dstRast; | |
| 125 | + int[] dstPix = icr.getDataStorage(); | |
| 126 | + | |
| 127 | + Region roi = CustomComponent.getRegionOfInterest(src, dst, clip, | |
| 128 | + srcx, srcy, | |
| 129 | + dstx, dsty, w, h); | |
| 130 | + SpanIterator si = roi.getSpanIterator(); | |
| 131 | + | |
| 132 | + Object srcPix = null; | |
| 133 | + | |
| 134 | + int dstScan = icr.getScanlineStride(); | |
| 135 | + // assert(icr.getPixelStride() == 1); | |
| 136 | + srcx -= dstx; | |
| 137 | + srcy -= dsty; | |
| 138 | + int span[] = new int[4]; | |
| 139 | + while (si.nextSpan(span)) { | |
| 140 | + int rowoff = icr.getDataOffset(0) + span[1] * dstScan + span[0]; | |
| 141 | + for (int y = span[1]; y < span[3]; y++) { | |
| 142 | + int off = rowoff; | |
| 143 | + for (int x = span[0]; x < span[2]; x++) { | |
| 144 | + srcPix = srcRast.getDataElements(x+srcx, y+srcy, srcPix); | |
| 145 | + dstPix[off++] = srcCM.getRGB(srcPix); | |
| 146 | + } | |
| 147 | + rowoff += dstScan; | |
| 148 | + } | |
| 149 | + } | |
| 150 | + // Pixels in the dest were modified directly, we must | |
| 151 | + // manually notify the raster that it was modified | |
| 152 | + icr.markDirty(); | |
| 153 | + // REMIND: We need to do something to make sure that dstRast | |
| 154 | + // is put back to the destination (as in the native Release | |
| 155 | + // function) | |
| 156 | + // src.releaseRaster(srcRast); // NOP? | |
| 157 | + // dst.releaseRaster(dstRast); | |
| 158 | + } | |
| 159 | +} | |
| 160 | + | |
| 161 | +/** | |
| 162 | + * ARGB format to ANY format Blit | |
| 163 | + */ | |
| 164 | +class OpaqueCopyArgbToAny extends Blit { | |
| 165 | + OpaqueCopyArgbToAny() { | |
| 166 | + super(SurfaceType.IntArgb, | |
| 167 | + CompositeType.SrcNoEa, | |
| 168 | + SurfaceType.Any); | |
| 169 | + } | |
| 170 | + | |
| 171 | + public void Blit(SurfaceData src, SurfaceData dst, | |
| 172 | + Composite comp, Region clip, | |
| 173 | + int srcx, int srcy, int dstx, int dsty, int w, int h) | |
| 174 | + { | |
| 175 | + Raster srcRast = src.getRaster(srcx, srcy, w, h); | |
| 176 | + IntegerComponentRaster icr = (IntegerComponentRaster) srcRast; | |
| 177 | + int[] srcPix = icr.getDataStorage(); | |
| 178 | + | |
| 179 | + WritableRaster dstRast = | |
| 180 | + (WritableRaster) dst.getRaster(dstx, dsty, w, h); | |
| 181 | + ColorModel dstCM = dst.getColorModel(); | |
| 182 | + | |
| 183 | + Region roi = CustomComponent.getRegionOfInterest(src, dst, clip, | |
| 184 | + srcx, srcy, | |
| 185 | + dstx, dsty, w, h); | |
| 186 | + SpanIterator si = roi.getSpanIterator(); | |
| 187 | + | |
| 188 | + Object dstPix = null; | |
| 189 | + | |
| 190 | + int srcScan = icr.getScanlineStride(); | |
| 191 | + // assert(icr.getPixelStride() == 1); | |
| 192 | + srcx -= dstx; | |
| 193 | + srcy -= dsty; | |
| 194 | + int span[] = new int[4]; | |
| 195 | + while (si.nextSpan(span)) { | |
| 196 | + int rowoff = (icr.getDataOffset(0) + | |
| 197 | + (srcy + span[1]) * srcScan + | |
| 198 | + (srcx + span[0])); | |
| 199 | + for (int y = span[1]; y < span[3]; y++) { | |
| 200 | + int off = rowoff; | |
| 201 | + for (int x = span[0]; x < span[2]; x++) { | |
| 202 | + dstPix = dstCM.getDataElements(srcPix[off++], dstPix); | |
| 203 | + dstRast.setDataElements(x, y, dstPix); | |
| 204 | + } | |
| 205 | + rowoff += srcScan; | |
| 206 | + } | |
| 207 | + } | |
| 208 | + // REMIND: We need to do something to make sure that dstRast | |
| 209 | + // is put back to the destination (as in the native Release | |
| 210 | + // function) | |
| 211 | + // src.releaseRaster(srcRast); // NOP? | |
| 212 | + // dst.releaseRaster(dstRast); | |
| 213 | + } | |
| 214 | +} | |
| 215 | + | |
| 216 | +/** | |
| 217 | + * ARGB format to ANY format Blit (pixels are XORed together with XOR pixel) | |
| 218 | + */ | |
| 219 | +class XorCopyArgbToAny extends Blit { | |
| 220 | + XorCopyArgbToAny() { | |
| 221 | + super(SurfaceType.IntArgb, | |
| 222 | + CompositeType.Xor, | |
| 223 | + SurfaceType.Any); | |
| 224 | + } | |
| 225 | + | |
| 226 | + public void Blit(SurfaceData src, SurfaceData dst, | |
| 227 | + Composite comp, Region clip, | |
| 228 | + int srcx, int srcy, int dstx, int dsty, int w, int h) | |
| 229 | + { | |
| 230 | + Raster srcRast = src.getRaster(srcx, srcy, w, h); | |
| 231 | + IntegerComponentRaster icr = (IntegerComponentRaster) srcRast; | |
| 232 | + int[] srcPix = icr.getDataStorage(); | |
| 233 | + | |
| 234 | + WritableRaster dstRast = | |
| 235 | + (WritableRaster) dst.getRaster(dstx, dsty, w, h); | |
| 236 | + ColorModel dstCM = dst.getColorModel(); | |
| 237 | + | |
| 238 | + Region roi = CustomComponent.getRegionOfInterest(src, dst, clip, | |
| 239 | + srcx, srcy, | |
| 240 | + dstx, dsty, w, h); | |
| 241 | + SpanIterator si = roi.getSpanIterator(); | |
| 242 | + | |
| 243 | + int xorrgb = ((XORComposite)comp).getXorColor().getRGB(); | |
| 244 | + Object xorPixel = dstCM.getDataElements(xorrgb, null); | |
| 245 | + | |
| 246 | + Object srcPixel = null; | |
| 247 | + Object dstPixel = null; | |
| 248 | + | |
| 249 | + int srcScan = icr.getScanlineStride(); | |
| 250 | + // assert(icr.getPixelStride() == 1); | |
| 251 | + srcx -= dstx; | |
| 252 | + srcy -= dsty; | |
| 253 | + int span[] = new int[4]; | |
| 254 | + while (si.nextSpan(span)) { | |
| 255 | + int rowoff = (icr.getDataOffset(0) + | |
| 256 | + (srcy + span[1]) * srcScan + | |
| 257 | + (srcx + span[0])); | |
| 258 | + for (int y = span[1]; y < span[3]; y++) { | |
| 259 | + int off = rowoff; | |
| 260 | + for (int x = span[0]; x < span[2]; x++) { | |
| 261 | + // REMIND: alpha bits of the destination pixel are | |
| 262 | + // currently altered by the XOR operation, but | |
| 263 | + // should be left untouched | |
| 264 | + srcPixel = dstCM.getDataElements(srcPix[off++], srcPixel); | |
| 265 | + dstPixel = dstRast.getDataElements(x, y, dstPixel); | |
| 266 | + | |
| 267 | + switch (dstCM.getTransferType()) { | |
| 268 | + case DataBuffer.TYPE_BYTE: | |
| 269 | + byte[] bytesrcarr = (byte[]) srcPixel; | |
| 270 | + byte[] bytedstarr = (byte[]) dstPixel; | |
| 271 | + byte[] bytexorarr = (byte[]) xorPixel; | |
| 272 | + for (int i = 0; i < bytedstarr.length; i++) { | |
| 273 | + bytedstarr[i] ^= bytesrcarr[i] ^ bytexorarr[i]; | |
| 274 | + } | |
| 275 | + break; | |
| 276 | + case DataBuffer.TYPE_SHORT: | |
| 277 | + case DataBuffer.TYPE_USHORT: | |
| 278 | + short[] shortsrcarr = (short[]) srcPixel; | |
| 279 | + short[] shortdstarr = (short[]) dstPixel; | |
| 280 | + short[] shortxorarr = (short[]) xorPixel; | |
| 281 | + for (int i = 0; i < shortdstarr.length; i++) { | |
| 282 | + shortdstarr[i] ^= shortsrcarr[i] ^ shortxorarr[i]; | |
| 283 | + } | |
| 284 | + break; | |
| 285 | + case DataBuffer.TYPE_INT: | |
| 286 | + int[] intsrcarr = (int[]) srcPixel; | |
| 287 | + int[] intdstarr = (int[]) dstPixel; | |
| 288 | + int[] intxorarr = (int[]) xorPixel; | |
| 289 | + for (int i = 0; i < intdstarr.length; i++) { | |
| 290 | + intdstarr[i] ^= intsrcarr[i] ^ intxorarr[i]; | |
| 291 | + } | |
| 292 | + break; | |
| 293 | + case DataBuffer.TYPE_FLOAT: | |
| 294 | + float[] floatsrcarr = (float[]) srcPixel; | |
| 295 | + float[] floatdstarr = (float[]) dstPixel; | |
| 296 | + float[] floatxorarr = (float[]) xorPixel; | |
| 297 | + for (int i = 0; i < floatdstarr.length; i++) { | |
| 298 | + int v = (Float.floatToIntBits(floatdstarr[i]) ^ | |
| 299 | + Float.floatToIntBits(floatsrcarr[i]) ^ | |
| 300 | + Float.floatToIntBits(floatxorarr[i])); | |
| 301 | + floatdstarr[i] = Float.intBitsToFloat(v); | |
| 302 | + } | |
| 303 | + break; | |
| 304 | + case DataBuffer.TYPE_DOUBLE: | |
| 305 | + double[] doublesrcarr = (double[]) srcPixel; | |
| 306 | + double[] doubledstarr = (double[]) dstPixel; | |
| 307 | + double[] doublexorarr = (double[]) xorPixel; | |
| 308 | + for (int i = 0; i < doubledstarr.length; i++) { | |
| 309 | + long v = (Double.doubleToLongBits(doubledstarr[i]) ^ | |
| 310 | + Double.doubleToLongBits(doublesrcarr[i]) ^ | |
| 311 | + Double.doubleToLongBits(doublexorarr[i])); | |
| 312 | + doubledstarr[i] = Double.longBitsToDouble(v); | |
| 313 | + } | |
| 314 | + break; | |
| 315 | + default: | |
| 316 | + throw new InternalError("Unsupported XOR pixel type"); | |
| 317 | + } | |
| 318 | + dstRast.setDataElements(x, y, dstPixel); | |
| 319 | + } | |
| 320 | + rowoff += srcScan; | |
| 321 | + } | |
| 322 | + } | |
| 323 | + // REMIND: We need to do something to make sure that dstRast | |
| 324 | + // is put back to the destination (as in the native Release | |
| 325 | + // function) | |
| 326 | + // src.releaseRaster(srcRast); // NOP? | |
| 327 | + // dst.releaseRaster(dstRast); | |
| 328 | + } | |
| 329 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,161 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.loops; | |
| 27 | + | |
| 28 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 29 | +import sun.java2d.pipe.Region; | |
| 30 | +import sun.java2d.SunGraphics2D; | |
| 31 | +import sun.java2d.SurfaceData; | |
| 32 | +import sun.font.GlyphList; | |
| 33 | + | |
| 34 | +/** | |
| 35 | + * DrawGlyphList - loops for SolidTextRenderer pipe. | |
| 36 | + * 1) draw solid color text onto destination surface | |
| 37 | + * 2) must accept output area [x, y, dx, dy] | |
| 38 | + * from within the surface description data for clip rect | |
| 39 | + */ | |
| 40 | +public class DrawGlyphList extends GraphicsPrimitive { | |
| 41 | + | |
| 42 | + public final static String methodSignature = "DrawGlyphList(...)".toString(); | |
| 43 | + | |
| 44 | + public final static int primTypeID = makePrimTypeID(); | |
| 45 | + | |
| 46 | + public static DrawGlyphList locate(SurfaceType srctype, | |
| 47 | + CompositeType comptype, | |
| 48 | + SurfaceType dsttype) | |
| 49 | + { | |
| 50 | + return (DrawGlyphList) | |
| 51 | + GraphicsPrimitiveMgr.locate(primTypeID, | |
| 52 | + srctype, comptype, dsttype); | |
| 53 | + } | |
| 54 | + | |
| 55 | + protected DrawGlyphList(SurfaceType srctype, | |
| 56 | + CompositeType comptype, | |
| 57 | + SurfaceType dsttype) | |
| 58 | + { | |
| 59 | + super(methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 60 | + } | |
| 61 | + | |
| 62 | + public DrawGlyphList(long pNativePrim, | |
| 63 | + SurfaceType srctype, | |
| 64 | + CompositeType comptype, | |
| 65 | + SurfaceType dsttype) | |
| 66 | + { | |
| 67 | + super(pNativePrim, methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 68 | + } | |
| 69 | + | |
| 70 | + | |
| 71 | + public native void DrawGlyphList(SunGraphics2D sg2d, SurfaceData dest, | |
| 72 | + GlyphList srcData); | |
| 73 | + | |
| 74 | + // This instance is used only for lookup. | |
| 75 | + static { | |
| 76 | + GraphicsPrimitiveMgr.registerGeneral( | |
| 77 | + new DrawGlyphList(null, null, null)); | |
| 78 | + } | |
| 79 | + | |
| 80 | + public GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 81 | + CompositeType comptype, | |
| 82 | + SurfaceType dsttype) { | |
| 83 | + return new General(srctype, comptype, dsttype); | |
| 84 | + } | |
| 85 | + | |
| 86 | + private static class General extends DrawGlyphList { | |
| 87 | + MaskFill maskop; | |
| 88 | + | |
| 89 | + public General(SurfaceType srctype, | |
| 90 | + CompositeType comptype, | |
| 91 | + SurfaceType dsttype) | |
| 92 | + { | |
| 93 | + super(srctype, comptype, dsttype); | |
| 94 | + maskop = MaskFill.locate(srctype, comptype, dsttype); | |
| 95 | + } | |
| 96 | + | |
| 97 | + public void DrawGlyphList(SunGraphics2D sg2d, SurfaceData dest, | |
| 98 | + GlyphList gl) { | |
| 99 | + | |
| 100 | + int strbounds[] = gl.getBounds(); // Don't delete, bug 4895493 | |
| 101 | + int num = gl.getNumGlyphs(); | |
| 102 | + Region clip = sg2d.getCompClip(); | |
| 103 | + int cx1 = clip.getLoX(); | |
| 104 | + int cy1 = clip.getLoY(); | |
| 105 | + int cx2 = clip.getHiX(); | |
| 106 | + int cy2 = clip.getHiY(); | |
| 107 | + for (int i = 0; i < num; i++) { | |
| 108 | + gl.setGlyphIndex(i); | |
| 109 | + int metrics[] = gl.getMetrics(); | |
| 110 | + int gx1 = metrics[0]; | |
| 111 | + int gy1 = metrics[1]; | |
| 112 | + int w = metrics[2]; | |
| 113 | + int gx2 = gx1 + w; | |
| 114 | + int gy2 = gy1 + metrics[3]; | |
| 115 | + int off = 0; | |
| 116 | + if (gx1 < cx1) { | |
| 117 | + off = cx1 - gx1; | |
| 118 | + gx1 = cx1; | |
| 119 | + } | |
| 120 | + if (gy1 < cy1) { | |
| 121 | + off += (cy1 - gy1) * w; | |
| 122 | + gy1 = cy1; | |
| 123 | + } | |
| 124 | + if (gx2 > cx2) gx2 = cx2; | |
| 125 | + if (gy2 > cy2) gy2 = cy2; | |
| 126 | + if (gx2 > gx1 && gy2 > gy1) { | |
| 127 | + byte alpha[] = gl.getGrayBits(); | |
| 128 | + maskop.MaskFill(sg2d, dest, sg2d.composite, | |
| 129 | + gx1, gy1, gx2 - gx1, gy2 - gy1, | |
| 130 | + alpha, off, w); | |
| 131 | + } | |
| 132 | + } | |
| 133 | + } | |
| 134 | + } | |
| 135 | + | |
| 136 | + public GraphicsPrimitive traceWrap() { | |
| 137 | + return new TraceDrawGlyphList(this); | |
| 138 | + } | |
| 139 | + | |
| 140 | + private static class TraceDrawGlyphList extends DrawGlyphList { | |
| 141 | + DrawGlyphList target; | |
| 142 | + | |
| 143 | + public TraceDrawGlyphList(DrawGlyphList target) { | |
| 144 | + super(target.getSourceType(), | |
| 145 | + target.getCompositeType(), | |
| 146 | + target.getDestType()); | |
| 147 | + this.target = target; | |
| 148 | + } | |
| 149 | + | |
| 150 | + public GraphicsPrimitive traceWrap() { | |
| 151 | + return this; | |
| 152 | + } | |
| 153 | + | |
| 154 | + public void DrawGlyphList(SunGraphics2D sg2d, SurfaceData dest, | |
| 155 | + GlyphList glyphs) | |
| 156 | + { | |
| 157 | + tracePrimitive(target); | |
| 158 | + target.DrawGlyphList(sg2d, dest, glyphs); | |
| 159 | + } | |
| 160 | + } | |
| 161 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,159 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.loops; | |
| 27 | + | |
| 28 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 29 | +import sun.java2d.pipe.Region; | |
| 30 | +import sun.java2d.SunGraphics2D; | |
| 31 | +import sun.java2d.SurfaceData; | |
| 32 | +import sun.font.GlyphList; | |
| 33 | + | |
| 34 | +/** | |
| 35 | + * DrawGlyphListAA - loops for AATextRenderer pipe | |
| 36 | + * 1) draw anti-aliased text onto destination surface | |
| 37 | + * 2) must accept output area [x, y, dx, dy] | |
| 38 | + * from within the surface description data for clip rect | |
| 39 | + */ | |
| 40 | +public class DrawGlyphListAA extends GraphicsPrimitive { | |
| 41 | + | |
| 42 | + public final static String methodSignature = "DrawGlyphListAA(...)".toString(); | |
| 43 | + | |
| 44 | + public final static int primTypeID = makePrimTypeID(); | |
| 45 | + | |
| 46 | + public static DrawGlyphListAA locate(SurfaceType srctype, | |
| 47 | + CompositeType comptype, | |
| 48 | + SurfaceType dsttype) | |
| 49 | + { | |
| 50 | + return (DrawGlyphListAA) | |
| 51 | + GraphicsPrimitiveMgr.locate(primTypeID, | |
| 52 | + srctype, comptype, dsttype); | |
| 53 | + } | |
| 54 | + | |
| 55 | + protected DrawGlyphListAA(SurfaceType srctype, | |
| 56 | + CompositeType comptype, | |
| 57 | + SurfaceType dsttype) | |
| 58 | + { | |
| 59 | + super(methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 60 | + } | |
| 61 | + | |
| 62 | + public DrawGlyphListAA(long pNativePrim, | |
| 63 | + SurfaceType srctype, | |
| 64 | + CompositeType comptype, | |
| 65 | + SurfaceType dsttype) | |
| 66 | + { | |
| 67 | + super(pNativePrim, methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 68 | + } | |
| 69 | + | |
| 70 | + public native void DrawGlyphListAA(SunGraphics2D sg2d, SurfaceData dest, | |
| 71 | + GlyphList srcData); | |
| 72 | + | |
| 73 | + static { | |
| 74 | + GraphicsPrimitiveMgr.registerGeneral( | |
| 75 | + new DrawGlyphListAA(null, null, null)); | |
| 76 | + } | |
| 77 | + | |
| 78 | + public GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 79 | + CompositeType comptype, | |
| 80 | + SurfaceType dsttype) { | |
| 81 | + return new General(srctype, comptype, dsttype); | |
| 82 | + } | |
| 83 | + | |
| 84 | + public static class General extends DrawGlyphListAA { | |
| 85 | + MaskFill maskop; | |
| 86 | + | |
| 87 | + public General(SurfaceType srctype, | |
| 88 | + CompositeType comptype, | |
| 89 | + SurfaceType dsttype) | |
| 90 | + { | |
| 91 | + super(srctype, comptype, dsttype); | |
| 92 | + maskop = MaskFill.locate(srctype, comptype, dsttype); | |
| 93 | + } | |
| 94 | + | |
| 95 | + public void DrawGlyphListAA(SunGraphics2D sg2d, SurfaceData dest, | |
| 96 | + GlyphList gl) | |
| 97 | + { | |
| 98 | + gl.getBounds(); // Don't delete, bug 4895493 | |
| 99 | + int num = gl.getNumGlyphs(); | |
| 100 | + Region clip = sg2d.getCompClip(); | |
| 101 | + int cx1 = clip.getLoX(); | |
| 102 | + int cy1 = clip.getLoY(); | |
| 103 | + int cx2 = clip.getHiX(); | |
| 104 | + int cy2 = clip.getHiY(); | |
| 105 | + for (int i = 0; i < num; i++) { | |
| 106 | + gl.setGlyphIndex(i); | |
| 107 | + int metrics[] = gl.getMetrics(); | |
| 108 | + int gx1 = metrics[0]; | |
| 109 | + int gy1 = metrics[1]; | |
| 110 | + int w = metrics[2]; | |
| 111 | + int gx2 = gx1 + w; | |
| 112 | + int gy2 = gy1 + metrics[3]; | |
| 113 | + int off = 0; | |
| 114 | + if (gx1 < cx1) { | |
| 115 | + off = cx1 - gx1; | |
| 116 | + gx1 = cx1; | |
| 117 | + } | |
| 118 | + if (gy1 < cy1) { | |
| 119 | + off += (cy1 - gy1) * w; | |
| 120 | + gy1 = cy1; | |
| 121 | + } | |
| 122 | + if (gx2 > cx2) gx2 = cx2; | |
| 123 | + if (gy2 > cy2) gy2 = cy2; | |
| 124 | + if (gx2 > gx1 && gy2 > gy1) { | |
| 125 | + byte alpha[] = gl.getGrayBits(); | |
| 126 | + maskop.MaskFill(sg2d, dest, sg2d.composite, | |
| 127 | + gx1, gy1, gx2 - gx1, gy2 - gy1, | |
| 128 | + alpha, off, w); | |
| 129 | + } | |
| 130 | + } | |
| 131 | + } | |
| 132 | + } | |
| 133 | + | |
| 134 | + public GraphicsPrimitive traceWrap() { | |
| 135 | + return new TraceDrawGlyphListAA(this); | |
| 136 | + } | |
| 137 | + | |
| 138 | + private static class TraceDrawGlyphListAA extends DrawGlyphListAA { | |
| 139 | + DrawGlyphListAA target; | |
| 140 | + | |
| 141 | + public TraceDrawGlyphListAA(DrawGlyphListAA target) { | |
| 142 | + super(target.getSourceType(), | |
| 143 | + target.getCompositeType(), | |
| 144 | + target.getDestType()); | |
| 145 | + this.target = target; | |
| 146 | + } | |
| 147 | + | |
| 148 | + public GraphicsPrimitive traceWrap() { | |
| 149 | + return this; | |
| 150 | + } | |
| 151 | + | |
| 152 | + public void DrawGlyphListAA(SunGraphics2D sg2d, SurfaceData dest, | |
| 153 | + GlyphList glyphs) | |
| 154 | + { | |
| 155 | + tracePrimitive(target); | |
| 156 | + target.DrawGlyphListAA(sg2d, dest, glyphs); | |
| 157 | + } | |
| 158 | + } | |
| 159 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,117 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.loops; | |
| 27 | + | |
| 28 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 29 | +import sun.java2d.pipe.Region; | |
| 30 | +import sun.java2d.SunGraphics2D; | |
| 31 | +import sun.java2d.SurfaceData; | |
| 32 | +import sun.font.GlyphList; | |
| 33 | + | |
| 34 | +/** | |
| 35 | + * DrawGlyphListLCD- loops for LCDTextRenderer pipe | |
| 36 | + * 1) draw LCD anti-aliased text onto destination surface | |
| 37 | + * 2) must accept output area [x, y, dx, dy] | |
| 38 | + * from within the surface description data for clip rect | |
| 39 | + */ | |
| 40 | +public class DrawGlyphListLCD extends GraphicsPrimitive { | |
| 41 | + | |
| 42 | + public final static String | |
| 43 | + methodSignature = "DrawGlyphListLCD(...)".toString(); | |
| 44 | + | |
| 45 | + public final static int primTypeID = makePrimTypeID(); | |
| 46 | + | |
| 47 | + public static DrawGlyphListLCD locate(SurfaceType srctype, | |
| 48 | + CompositeType comptype, | |
| 49 | + SurfaceType dsttype) | |
| 50 | + { | |
| 51 | + return (DrawGlyphListLCD) | |
| 52 | + GraphicsPrimitiveMgr.locate(primTypeID, | |
| 53 | + srctype, comptype, dsttype); | |
| 54 | + } | |
| 55 | + | |
| 56 | + protected DrawGlyphListLCD(SurfaceType srctype, | |
| 57 | + CompositeType comptype, | |
| 58 | + SurfaceType dsttype) | |
| 59 | + { | |
| 60 | + super(methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 61 | + } | |
| 62 | + | |
| 63 | + public DrawGlyphListLCD(long pNativePrim, | |
| 64 | + SurfaceType srctype, | |
| 65 | + CompositeType comptype, | |
| 66 | + SurfaceType dsttype) | |
| 67 | + { | |
| 68 | + super(pNativePrim, methodSignature, primTypeID, | |
| 69 | + srctype, comptype, dsttype); | |
| 70 | + } | |
| 71 | + | |
| 72 | + public native void DrawGlyphListLCD(SunGraphics2D sg2d, SurfaceData dest, | |
| 73 | + GlyphList srcData); | |
| 74 | + | |
| 75 | + static { | |
| 76 | + GraphicsPrimitiveMgr.registerGeneral( | |
| 77 | + new DrawGlyphListLCD(null, null, null)); | |
| 78 | + } | |
| 79 | + | |
| 80 | + public GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 81 | + CompositeType comptype, | |
| 82 | + SurfaceType dsttype) { | |
| 83 | + /* Do not return a General loop. SunGraphics2D determines whether | |
| 84 | + * to use LCD or standard AA text based on whether there is an | |
| 85 | + * installed loop. | |
| 86 | + * This can be uncommented once there is a General loop which can | |
| 87 | + * handle one byte per colour component masks properly. | |
| 88 | + */ | |
| 89 | + return null; | |
| 90 | + } | |
| 91 | + | |
| 92 | + public GraphicsPrimitive traceWrap() { | |
| 93 | + return new TraceDrawGlyphListLCD(this); | |
| 94 | + } | |
| 95 | + | |
| 96 | + private static class TraceDrawGlyphListLCD extends DrawGlyphListLCD { | |
| 97 | + DrawGlyphListLCD target; | |
| 98 | + | |
| 99 | + public TraceDrawGlyphListLCD(DrawGlyphListLCD target) { | |
| 100 | + super(target.getSourceType(), | |
| 101 | + target.getCompositeType(), | |
| 102 | + target.getDestType()); | |
| 103 | + this.target = target; | |
| 104 | + } | |
| 105 | + | |
| 106 | + public GraphicsPrimitive traceWrap() { | |
| 107 | + return this; | |
| 108 | + } | |
| 109 | + | |
| 110 | + public void DrawGlyphListLCD(SunGraphics2D sg2d, SurfaceData dest, | |
| 111 | + GlyphList glyphs) | |
| 112 | + { | |
| 113 | + tracePrimitive(target); | |
| 114 | + target.DrawGlyphListLCD(sg2d, dest, glyphs); | |
| 115 | + } | |
| 116 | + } | |
| 117 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,114 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +/* | |
| 27 | + * @author Charlton Innovations, Inc. | |
| 28 | + */ | |
| 29 | + | |
| 30 | +package sun.java2d.loops; | |
| 31 | + | |
| 32 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 33 | +import java.awt.Color; | |
| 34 | +import java.awt.image.ColorModel; | |
| 35 | +import java.awt.image.Raster; | |
| 36 | +import sun.java2d.SunGraphics2D; | |
| 37 | +import sun.java2d.SurfaceData; | |
| 38 | + | |
| 39 | +/** | |
| 40 | + * DrawLine | |
| 41 | + * 1) draw solid color single width line onto destination surface | |
| 42 | + * 2) must accept output area [x, y, dx, dy] | |
| 43 | + * from within the surface description data for clip rect | |
| 44 | + */ | |
| 45 | +public class DrawLine extends GraphicsPrimitive | |
| 46 | +{ | |
| 47 | + public final static String methodSignature = "DrawLine(...)".toString(); | |
| 48 | + | |
| 49 | + public final static int primTypeID = makePrimTypeID(); | |
| 50 | + | |
| 51 | + public static DrawLine locate(SurfaceType srctype, | |
| 52 | + CompositeType comptype, | |
| 53 | + SurfaceType dsttype) | |
| 54 | + { | |
| 55 | + return (DrawLine) GraphicsPrimitiveMgr.locate(primTypeID, | |
| 56 | + srctype, comptype, dsttype); | |
| 57 | + } | |
| 58 | + | |
| 59 | + protected DrawLine(SurfaceType srctype, | |
| 60 | + CompositeType comptype, | |
| 61 | + SurfaceType dsttype) | |
| 62 | + { | |
| 63 | + super(methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 64 | + } | |
| 65 | + | |
| 66 | + public DrawLine(long pNativePrim, | |
| 67 | + SurfaceType srctype, | |
| 68 | + CompositeType comptype, | |
| 69 | + SurfaceType dsttype) | |
| 70 | + { | |
| 71 | + super(pNativePrim, methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 72 | + } | |
| 73 | + | |
| 74 | + /** | |
| 75 | + * All DrawLine implementors must have this invoker method | |
| 76 | + */ | |
| 77 | + public native void DrawLine(SunGraphics2D sg2d, SurfaceData dest, | |
| 78 | + int x1, int y1, int x2, int y2); | |
| 79 | + | |
| 80 | + public GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 81 | + CompositeType comptype, | |
| 82 | + SurfaceType dsttype) | |
| 83 | + { | |
| 84 | + // REMIND: use FillSpans or converter object? | |
| 85 | + throw new InternalError("DrawLine not implemented for "+ | |
| 86 | + srctype+" with "+comptype); | |
| 87 | + } | |
| 88 | + | |
| 89 | + public GraphicsPrimitive traceWrap() { | |
| 90 | + return new TraceDrawLine(this); | |
| 91 | + } | |
| 92 | + | |
| 93 | + private static class TraceDrawLine extends DrawLine { | |
| 94 | + DrawLine target; | |
| 95 | + | |
| 96 | + public TraceDrawLine(DrawLine target) { | |
| 97 | + super(target.getSourceType(), | |
| 98 | + target.getCompositeType(), | |
| 99 | + target.getDestType()); | |
| 100 | + this.target = target; | |
| 101 | + } | |
| 102 | + | |
| 103 | + public GraphicsPrimitive traceWrap() { | |
| 104 | + return this; | |
| 105 | + } | |
| 106 | + | |
| 107 | + public void DrawLine(SunGraphics2D sg2d, SurfaceData dest, | |
| 108 | + int x1, int y1, int x2, int y2) | |
| 109 | + { | |
| 110 | + tracePrimitive(target); | |
| 111 | + target.DrawLine(sg2d, dest, x1, y1, x2, y2); | |
| 112 | + } | |
| 113 | + } | |
| 114 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,123 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +/* | |
| 27 | + * @author Jim Graham | |
| 28 | + */ | |
| 29 | + | |
| 30 | +package sun.java2d.loops; | |
| 31 | + | |
| 32 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 33 | +import sun.java2d.SunGraphics2D; | |
| 34 | +import sun.java2d.SurfaceData; | |
| 35 | + | |
| 36 | +/** | |
| 37 | + * DrawParallelogram | |
| 38 | + * 1) fill the area between the 4 edges of an outer parallelogram | |
| 39 | + * (as specified by an origin and 2 delta vectors) | |
| 40 | + * but also outside the 4 edges of an inner parallelogram | |
| 41 | + * (as specified by proportional amounts of the outer delta vectors) | |
| 42 | + */ | |
| 43 | +public class DrawParallelogram extends GraphicsPrimitive | |
| 44 | +{ | |
| 45 | + public final static String methodSignature = | |
| 46 | + "DrawParallelogram(...)".toString(); | |
| 47 | + | |
| 48 | + public final static int primTypeID = makePrimTypeID(); | |
| 49 | + | |
| 50 | + public static DrawParallelogram locate(SurfaceType srctype, | |
| 51 | + CompositeType comptype, | |
| 52 | + SurfaceType dsttype) | |
| 53 | + { | |
| 54 | + return (DrawParallelogram) | |
| 55 | + GraphicsPrimitiveMgr.locate(primTypeID, | |
| 56 | + srctype, comptype, dsttype); | |
| 57 | + } | |
| 58 | + | |
| 59 | + protected DrawParallelogram(SurfaceType srctype, | |
| 60 | + CompositeType comptype, | |
| 61 | + SurfaceType dsttype) | |
| 62 | + { | |
| 63 | + super(methodSignature, primTypeID, | |
| 64 | + srctype, comptype, dsttype); | |
| 65 | + } | |
| 66 | + | |
| 67 | + public DrawParallelogram(long pNativePrim, | |
| 68 | + SurfaceType srctype, | |
| 69 | + CompositeType comptype, | |
| 70 | + SurfaceType dsttype) | |
| 71 | + { | |
| 72 | + super(pNativePrim, methodSignature, primTypeID, | |
| 73 | + srctype, comptype, dsttype); | |
| 74 | + } | |
| 75 | + | |
| 76 | + /** | |
| 77 | + * All DrawParallelogram implementors must have this invoker method | |
| 78 | + */ | |
| 79 | + public native void DrawParallelogram(SunGraphics2D sg, SurfaceData dest, | |
| 80 | + double x, double y, | |
| 81 | + double dx1, double dy1, | |
| 82 | + double dx2, double dy2, | |
| 83 | + double lw1, double lw2); | |
| 84 | + | |
| 85 | + public GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 86 | + CompositeType comptype, | |
| 87 | + SurfaceType dsttype) | |
| 88 | + { | |
| 89 | + // REMIND: iterate with a FillRect primitive? | |
| 90 | + throw new InternalError("DrawParallelogram not implemented for "+ | |
| 91 | + srctype+" with "+comptype); | |
| 92 | + } | |
| 93 | + | |
| 94 | + public GraphicsPrimitive traceWrap() { | |
| 95 | + return new TraceDrawParallelogram(this); | |
| 96 | + } | |
| 97 | + | |
| 98 | + private static class TraceDrawParallelogram extends DrawParallelogram { | |
| 99 | + DrawParallelogram target; | |
| 100 | + | |
| 101 | + public TraceDrawParallelogram(DrawParallelogram target) { | |
| 102 | + super(target.getSourceType(), | |
| 103 | + target.getCompositeType(), | |
| 104 | + target.getDestType()); | |
| 105 | + this.target = target; | |
| 106 | + } | |
| 107 | + | |
| 108 | + public GraphicsPrimitive traceWrap() { | |
| 109 | + return this; | |
| 110 | + } | |
| 111 | + | |
| 112 | + public void DrawParallelogram(SunGraphics2D sg2d, SurfaceData dest, | |
| 113 | + double x, double y, | |
| 114 | + double dx1, double dy1, | |
| 115 | + double dx2, double dy2, | |
| 116 | + double lw1, double lw2) | |
| 117 | + { | |
| 118 | + tracePrimitive(target); | |
| 119 | + target.DrawParallelogram(sg2d, dest, | |
| 120 | + x, y, dx1, dy1, dx2, dy2, lw1, lw2); | |
| 121 | + } | |
| 122 | + } | |
| 123 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,114 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.loops; | |
| 27 | + | |
| 28 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 29 | +import sun.java2d.SunGraphics2D; | |
| 30 | +import sun.java2d.SurfaceData; | |
| 31 | +import java.awt.geom.Path2D; | |
| 32 | + | |
| 33 | +/** | |
| 34 | + * DrawPath | |
| 35 | + * 1. draw single-width line path onto destination surface | |
| 36 | + * 2. must accept output area [x, y, dx, dy] | |
| 37 | + * from within the surface description data for clip rect | |
| 38 | + */ | |
| 39 | +public class DrawPath extends GraphicsPrimitive { | |
| 40 | + | |
| 41 | + public final static String methodSignature = | |
| 42 | + "DrawPath(...)".toString(); | |
| 43 | + | |
| 44 | + public final static int primTypeID = makePrimTypeID(); | |
| 45 | + | |
| 46 | + public static DrawPath locate(SurfaceType srctype, | |
| 47 | + CompositeType comptype, | |
| 48 | + SurfaceType dsttype) | |
| 49 | + { | |
| 50 | + return (DrawPath) | |
| 51 | + GraphicsPrimitiveMgr.locate(primTypeID, | |
| 52 | + srctype, comptype, dsttype); | |
| 53 | + } | |
| 54 | + | |
| 55 | + protected DrawPath(SurfaceType srctype, | |
| 56 | + CompositeType comptype, | |
| 57 | + SurfaceType dsttype) | |
| 58 | + { | |
| 59 | + super(methodSignature, primTypeID, | |
| 60 | + srctype, comptype, dsttype); | |
| 61 | + } | |
| 62 | + | |
| 63 | + public DrawPath(long pNativePrim, | |
| 64 | + SurfaceType srctype, | |
| 65 | + CompositeType comptype, | |
| 66 | + SurfaceType dsttype) | |
| 67 | + { | |
| 68 | + super(pNativePrim, methodSignature, primTypeID, | |
| 69 | + srctype, comptype, dsttype); | |
| 70 | + } | |
| 71 | + | |
| 72 | + | |
| 73 | + /** | |
| 74 | + * All DrawPath implementors must have this invoker method | |
| 75 | + */ | |
| 76 | + public native void DrawPath(SunGraphics2D sg2d, SurfaceData sData, | |
| 77 | + int transX, int transY, | |
| 78 | + Path2D.Float p2df); | |
| 79 | + | |
| 80 | + public GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 81 | + CompositeType comptype, | |
| 82 | + SurfaceType dsttype) | |
| 83 | + { | |
| 84 | + throw new InternalError("DrawPath not implemented for "+ | |
| 85 | + srctype+" with "+comptype); | |
| 86 | + } | |
| 87 | + | |
| 88 | + public GraphicsPrimitive traceWrap() { | |
| 89 | + return new TraceDrawPath(this); | |
| 90 | + } | |
| 91 | + | |
| 92 | + private static class TraceDrawPath extends DrawPath { | |
| 93 | + DrawPath target; | |
| 94 | + | |
| 95 | + public TraceDrawPath(DrawPath target) { | |
| 96 | + super(target.getSourceType(), | |
| 97 | + target.getCompositeType(), | |
| 98 | + target.getDestType()); | |
| 99 | + this.target = target; | |
| 100 | + } | |
| 101 | + | |
| 102 | + public GraphicsPrimitive traceWrap() { | |
| 103 | + return this; | |
| 104 | + } | |
| 105 | + | |
| 106 | + public void DrawPath(SunGraphics2D sg2d, SurfaceData sData, | |
| 107 | + int transX, int transY, | |
| 108 | + Path2D.Float p2df) | |
| 109 | + { | |
| 110 | + tracePrimitive(target); | |
| 111 | + target.DrawPath(sg2d, sData, transX, transY, p2df); | |
| 112 | + } | |
| 113 | + } | |
| 114 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,120 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +/* | |
| 27 | + * @author Charlton Innovations, Inc. | |
| 28 | + */ | |
| 29 | + | |
| 30 | +package sun.java2d.loops; | |
| 31 | + | |
| 32 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 33 | +import sun.java2d.SunGraphics2D; | |
| 34 | +import sun.java2d.SurfaceData; | |
| 35 | + | |
| 36 | +/** | |
| 37 | + * DrawPolygons | |
| 38 | + * 1) draw single-width line polygons onto destination surface | |
| 39 | + * 2) must accept output area [x, y, dx, dy] | |
| 40 | + * from within the surface description data for clip rect | |
| 41 | + */ | |
| 42 | +public class DrawPolygons extends GraphicsPrimitive | |
| 43 | +{ | |
| 44 | + public final static String methodSignature = "DrawPolygons(...)".toString(); | |
| 45 | + | |
| 46 | + public final static int primTypeID = makePrimTypeID(); | |
| 47 | + | |
| 48 | + public static DrawPolygons locate(SurfaceType srctype, | |
| 49 | + CompositeType comptype, | |
| 50 | + SurfaceType dsttype) | |
| 51 | + { | |
| 52 | + return (DrawPolygons) | |
| 53 | + GraphicsPrimitiveMgr.locate(primTypeID, | |
| 54 | + srctype, comptype, dsttype); | |
| 55 | + } | |
| 56 | + | |
| 57 | + protected DrawPolygons(SurfaceType srctype, | |
| 58 | + CompositeType comptype, | |
| 59 | + SurfaceType dsttype) | |
| 60 | + { | |
| 61 | + super(methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 62 | + } | |
| 63 | + | |
| 64 | + public DrawPolygons(long pNativePrim, | |
| 65 | + SurfaceType srctype, | |
| 66 | + CompositeType comptype, | |
| 67 | + SurfaceType dsttype) | |
| 68 | + { | |
| 69 | + super(pNativePrim, methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 70 | + } | |
| 71 | + | |
| 72 | + /** | |
| 73 | + * All DrawPolygon implementors must have this invoker method | |
| 74 | + */ | |
| 75 | + public native void DrawPolygons(SunGraphics2D sg2d, SurfaceData sData, | |
| 76 | + int xPoints[], int yPoints[], | |
| 77 | + int nPoints[], int numPolys, | |
| 78 | + int transX, int transY, | |
| 79 | + boolean close); | |
| 80 | + | |
| 81 | + public GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 82 | + CompositeType comptype, | |
| 83 | + SurfaceType dsttype) | |
| 84 | + { | |
| 85 | + // REMIND: use FillSpans or converter object? | |
| 86 | + throw new InternalError("DrawPolygons not implemented for "+ | |
| 87 | + srctype+" with "+comptype); | |
| 88 | + } | |
| 89 | + | |
| 90 | + public GraphicsPrimitive traceWrap() { | |
| 91 | + return new TraceDrawPolygons(this); | |
| 92 | + } | |
| 93 | + | |
| 94 | + private static class TraceDrawPolygons extends DrawPolygons { | |
| 95 | + DrawPolygons target; | |
| 96 | + | |
| 97 | + public TraceDrawPolygons(DrawPolygons target) { | |
| 98 | + super(target.getSourceType(), | |
| 99 | + target.getCompositeType(), | |
| 100 | + target.getDestType()); | |
| 101 | + this.target = target; | |
| 102 | + } | |
| 103 | + | |
| 104 | + public GraphicsPrimitive traceWrap() { | |
| 105 | + return this; | |
| 106 | + } | |
| 107 | + | |
| 108 | + public void DrawPolygons(SunGraphics2D sg2d, SurfaceData sData, | |
| 109 | + int xPoints[], int yPoints[], | |
| 110 | + int nPoints[], int numPolys, | |
| 111 | + int transX, int transY, | |
| 112 | + boolean close) | |
| 113 | + { | |
| 114 | + tracePrimitive(target); | |
| 115 | + target.DrawPolygons(sg2d, sData, | |
| 116 | + xPoints, yPoints, nPoints, numPolys, | |
| 117 | + transX, transY, close); | |
| 118 | + } | |
| 119 | + } | |
| 120 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,115 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +/* | |
| 27 | + * @author Charlton Innovations, Inc. | |
| 28 | + */ | |
| 29 | + | |
| 30 | +package sun.java2d.loops; | |
| 31 | + | |
| 32 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 33 | +import java.awt.Color; | |
| 34 | +import java.awt.image.ColorModel; | |
| 35 | +import java.awt.image.Raster; | |
| 36 | +import sun.java2d.SunGraphics2D; | |
| 37 | +import sun.java2d.SurfaceData; | |
| 38 | + | |
| 39 | +/** | |
| 40 | + * DrawRect | |
| 41 | + * 1) draw single-width line rectangle onto destination surface | |
| 42 | + * 2) must accept output area [x, y, dx, dy] | |
| 43 | + * from within the surface description data for clip rect | |
| 44 | + */ | |
| 45 | +public class DrawRect extends GraphicsPrimitive | |
| 46 | +{ | |
| 47 | + public final static String methodSignature = "DrawRect(...)".toString(); | |
| 48 | + | |
| 49 | + public final static int primTypeID = makePrimTypeID(); | |
| 50 | + | |
| 51 | + public static DrawRect locate(SurfaceType srctype, | |
| 52 | + CompositeType comptype, | |
| 53 | + SurfaceType dsttype) | |
| 54 | + { | |
| 55 | + return (DrawRect) | |
| 56 | + GraphicsPrimitiveMgr.locate(primTypeID, | |
| 57 | + srctype, comptype, dsttype); | |
| 58 | + } | |
| 59 | + | |
| 60 | + protected DrawRect(SurfaceType srctype, | |
| 61 | + CompositeType comptype, | |
| 62 | + SurfaceType dsttype) | |
| 63 | + { | |
| 64 | + super(methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 65 | + } | |
| 66 | + | |
| 67 | + public DrawRect(long pNativePrim, | |
| 68 | + SurfaceType srctype, | |
| 69 | + CompositeType comptype, | |
| 70 | + SurfaceType dsttype) | |
| 71 | + { | |
| 72 | + super(pNativePrim, methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 73 | + } | |
| 74 | + | |
| 75 | + /** | |
| 76 | + * All DrawRect implementors must have this invoker method | |
| 77 | + */ | |
| 78 | + public native void DrawRect(SunGraphics2D sg2d, SurfaceData dest, | |
| 79 | + int x1, int y1, int w, int h); | |
| 80 | + | |
| 81 | + public GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 82 | + CompositeType comptype, | |
| 83 | + SurfaceType dsttype) | |
| 84 | + { | |
| 85 | + // REMIND: use FillSpans or converter object? | |
| 86 | + throw new InternalError("DrawRect not implemented for "+ | |
| 87 | + srctype+" with "+comptype); | |
| 88 | + } | |
| 89 | + | |
| 90 | + public GraphicsPrimitive traceWrap() { | |
| 91 | + return new TraceDrawRect(this); | |
| 92 | + } | |
| 93 | + | |
| 94 | + private static class TraceDrawRect extends DrawRect { | |
| 95 | + DrawRect target; | |
| 96 | + | |
| 97 | + public TraceDrawRect(DrawRect target) { | |
| 98 | + super(target.getSourceType(), | |
| 99 | + target.getCompositeType(), | |
| 100 | + target.getDestType()); | |
| 101 | + this.target = target; | |
| 102 | + } | |
| 103 | + | |
| 104 | + public GraphicsPrimitive traceWrap() { | |
| 105 | + return this; | |
| 106 | + } | |
| 107 | + | |
| 108 | + public void DrawRect(SunGraphics2D sg2d, SurfaceData dest, | |
| 109 | + int x1, int y1, int w, int h) | |
| 110 | + { | |
| 111 | + tracePrimitive(target); | |
| 112 | + target.DrawRect(sg2d, dest, x1, y1, w, h); | |
| 113 | + } | |
| 114 | + } | |
| 115 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,118 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +/* | |
| 27 | + * @author Jim Graham | |
| 28 | + */ | |
| 29 | + | |
| 30 | +package sun.java2d.loops; | |
| 31 | + | |
| 32 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 33 | +import sun.java2d.SunGraphics2D; | |
| 34 | +import sun.java2d.SurfaceData; | |
| 35 | + | |
| 36 | +/** | |
| 37 | + * FillParallelogram | |
| 38 | + * 1) fill the area between the 4 edges of a parallelogram | |
| 39 | + * (as specified by an origin and 2 delta vectors) | |
| 40 | + */ | |
| 41 | +public class FillParallelogram extends GraphicsPrimitive | |
| 42 | +{ | |
| 43 | + public final static String methodSignature = | |
| 44 | + "FillParallelogram(...)".toString(); | |
| 45 | + | |
| 46 | + public final static int primTypeID = makePrimTypeID(); | |
| 47 | + | |
| 48 | + public static FillParallelogram locate(SurfaceType srctype, | |
| 49 | + CompositeType comptype, | |
| 50 | + SurfaceType dsttype) | |
| 51 | + { | |
| 52 | + return (FillParallelogram) | |
| 53 | + GraphicsPrimitiveMgr.locate(primTypeID, | |
| 54 | + srctype, comptype, dsttype); | |
| 55 | + } | |
| 56 | + | |
| 57 | + protected FillParallelogram(SurfaceType srctype, | |
| 58 | + CompositeType comptype, | |
| 59 | + SurfaceType dsttype) | |
| 60 | + { | |
| 61 | + super(methodSignature, primTypeID, | |
| 62 | + srctype, comptype, dsttype); | |
| 63 | + } | |
| 64 | + | |
| 65 | + public FillParallelogram(long pNativePrim, | |
| 66 | + SurfaceType srctype, | |
| 67 | + CompositeType comptype, | |
| 68 | + SurfaceType dsttype) | |
| 69 | + { | |
| 70 | + super(pNativePrim, methodSignature, primTypeID, | |
| 71 | + srctype, comptype, dsttype); | |
| 72 | + } | |
| 73 | + | |
| 74 | + /** | |
| 75 | + * All FillParallelogram implementors must have this invoker method | |
| 76 | + */ | |
| 77 | + public native void FillParallelogram(SunGraphics2D sg2d, SurfaceData dest, | |
| 78 | + double x0, double y0, | |
| 79 | + double dx1, double dy1, | |
| 80 | + double dx2, double dy2); | |
| 81 | + | |
| 82 | + public GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 83 | + CompositeType comptype, | |
| 84 | + SurfaceType dsttype) | |
| 85 | + { | |
| 86 | + // REMIND: iterate with a FillRect primitive? | |
| 87 | + throw new InternalError("FillParallelogram not implemented for "+ | |
| 88 | + srctype+" with "+comptype); | |
| 89 | + } | |
| 90 | + | |
| 91 | + public GraphicsPrimitive traceWrap() { | |
| 92 | + return new TraceFillParallelogram(this); | |
| 93 | + } | |
| 94 | + | |
| 95 | + private static class TraceFillParallelogram extends FillParallelogram { | |
| 96 | + FillParallelogram target; | |
| 97 | + | |
| 98 | + public TraceFillParallelogram(FillParallelogram target) { | |
| 99 | + super(target.getSourceType(), | |
| 100 | + target.getCompositeType(), | |
| 101 | + target.getDestType()); | |
| 102 | + this.target = target; | |
| 103 | + } | |
| 104 | + | |
| 105 | + public GraphicsPrimitive traceWrap() { | |
| 106 | + return this; | |
| 107 | + } | |
| 108 | + | |
| 109 | + public void FillParallelogram(SunGraphics2D sg2d, SurfaceData dest, | |
| 110 | + double x0, double y0, | |
| 111 | + double dx1, double dy1, | |
| 112 | + double dx2, double dy2) | |
| 113 | + { | |
| 114 | + tracePrimitive(target); | |
| 115 | + target.FillParallelogram(sg2d, dest, x0, y0, dx1, dy1, dx2, dy2); | |
| 116 | + } | |
| 117 | + } | |
| 118 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,114 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.loops; | |
| 27 | + | |
| 28 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 29 | +import sun.java2d.SunGraphics2D; | |
| 30 | +import sun.java2d.SurfaceData; | |
| 31 | +import java.awt.geom.Path2D; | |
| 32 | + | |
| 33 | +/** | |
| 34 | + * FillPath | |
| 35 | + * 1. fill path onto destination surface | |
| 36 | + * 2. must accept output area [x, y, dx, dy] | |
| 37 | + * from within the surface description data for clip rect | |
| 38 | + */ | |
| 39 | +public class FillPath extends GraphicsPrimitive { | |
| 40 | + | |
| 41 | + public final static String methodSignature = | |
| 42 | + "FillPath(...)".toString(); | |
| 43 | + | |
| 44 | + public final static int primTypeID = makePrimTypeID(); | |
| 45 | + | |
| 46 | + public static FillPath locate(SurfaceType srctype, | |
| 47 | + CompositeType comptype, | |
| 48 | + SurfaceType dsttype) | |
| 49 | + { | |
| 50 | + return (FillPath) | |
| 51 | + GraphicsPrimitiveMgr.locate(primTypeID, | |
| 52 | + srctype, comptype, dsttype); | |
| 53 | + } | |
| 54 | + | |
| 55 | + protected FillPath(SurfaceType srctype, | |
| 56 | + CompositeType comptype, | |
| 57 | + SurfaceType dsttype) | |
| 58 | + { | |
| 59 | + super(methodSignature, primTypeID, | |
| 60 | + srctype, comptype, dsttype); | |
| 61 | + } | |
| 62 | + | |
| 63 | + public FillPath(long pNativePrim, | |
| 64 | + SurfaceType srctype, | |
| 65 | + CompositeType comptype, | |
| 66 | + SurfaceType dsttype) | |
| 67 | + { | |
| 68 | + super(pNativePrim, methodSignature, primTypeID, | |
| 69 | + srctype, comptype, dsttype); | |
| 70 | + } | |
| 71 | + | |
| 72 | + | |
| 73 | + /** | |
| 74 | + * All FillPath implementors must have this invoker method | |
| 75 | + */ | |
| 76 | + public native void FillPath(SunGraphics2D sg2d, SurfaceData sData, | |
| 77 | + int transX, int transY, | |
| 78 | + Path2D.Float p2df); | |
| 79 | + | |
| 80 | + public GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 81 | + CompositeType comptype, | |
| 82 | + SurfaceType dsttype) | |
| 83 | + { | |
| 84 | + throw new InternalError("FillPath not implemented for "+ | |
| 85 | + srctype+" with "+comptype); | |
| 86 | + } | |
| 87 | + | |
| 88 | + public GraphicsPrimitive traceWrap() { | |
| 89 | + return new TraceFillPath(this); | |
| 90 | + } | |
| 91 | + | |
| 92 | + private static class TraceFillPath extends FillPath { | |
| 93 | + FillPath target; | |
| 94 | + | |
| 95 | + public TraceFillPath(FillPath target) { | |
| 96 | + super(target.getSourceType(), | |
| 97 | + target.getCompositeType(), | |
| 98 | + target.getDestType()); | |
| 99 | + this.target = target; | |
| 100 | + } | |
| 101 | + | |
| 102 | + public GraphicsPrimitive traceWrap() { | |
| 103 | + return this; | |
| 104 | + } | |
| 105 | + | |
| 106 | + public void FillPath(SunGraphics2D sg2d, SurfaceData sData, | |
| 107 | + int transX, int transY, | |
| 108 | + Path2D.Float p2df) | |
| 109 | + { | |
| 110 | + tracePrimitive(target); | |
| 111 | + target.FillPath(sg2d, sData, transX, transY, p2df); | |
| 112 | + } | |
| 113 | + } | |
| 114 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,135 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +/* | |
| 27 | + * @author Charlton Innovations, Inc. | |
| 28 | + */ | |
| 29 | + | |
| 30 | +package sun.java2d.loops; | |
| 31 | + | |
| 32 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 33 | +import java.awt.Color; | |
| 34 | +import java.awt.image.ColorModel; | |
| 35 | +import java.awt.image.Raster; | |
| 36 | +import sun.java2d.SunGraphics2D; | |
| 37 | +import sun.java2d.SurfaceData; | |
| 38 | + | |
| 39 | +/** | |
| 40 | + * FillRect | |
| 41 | + * 1) draw solid color rectangle onto destination surface | |
| 42 | + * 2) must accept output area [x, y, dx, dy] | |
| 43 | + * from within the surface description data for clip rect | |
| 44 | + */ | |
| 45 | +public class FillRect extends GraphicsPrimitive | |
| 46 | +{ | |
| 47 | + public final static String methodSignature = "FillRect(...)".toString(); | |
| 48 | + | |
| 49 | + public final static int primTypeID = makePrimTypeID(); | |
| 50 | + | |
| 51 | + public static FillRect locate(SurfaceType srctype, | |
| 52 | + CompositeType comptype, | |
| 53 | + SurfaceType dsttype) | |
| 54 | + { | |
| 55 | + return (FillRect) | |
| 56 | + GraphicsPrimitiveMgr.locate(primTypeID, | |
| 57 | + srctype, comptype, dsttype); | |
| 58 | + } | |
| 59 | + | |
| 60 | + protected FillRect(SurfaceType srctype, | |
| 61 | + CompositeType comptype, | |
| 62 | + SurfaceType dsttype) | |
| 63 | + { | |
| 64 | + super(methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 65 | + } | |
| 66 | + | |
| 67 | + public FillRect(long pNativePrim, | |
| 68 | + SurfaceType srctype, | |
| 69 | + CompositeType comptype, | |
| 70 | + SurfaceType dsttype) | |
| 71 | + { | |
| 72 | + super(pNativePrim, methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 73 | + } | |
| 74 | + | |
| 75 | + /** | |
| 76 | + * All FillRect implementors must have this invoker method | |
| 77 | + */ | |
| 78 | + public native void FillRect(SunGraphics2D sg2d, SurfaceData dest, | |
| 79 | + int x, int y, int w, int h); | |
| 80 | + | |
| 81 | + static { | |
| 82 | + GraphicsPrimitiveMgr.registerGeneral(new FillRect(null, null, null)); | |
| 83 | + } | |
| 84 | + | |
| 85 | + public GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 86 | + CompositeType comptype, | |
| 87 | + SurfaceType dsttype) | |
| 88 | + { | |
| 89 | + return new General(srctype, comptype, dsttype); | |
| 90 | + } | |
| 91 | + | |
| 92 | + public static class General extends FillRect { | |
| 93 | + public MaskFill fillop; | |
| 94 | + | |
| 95 | + public General(SurfaceType srctype, | |
| 96 | + CompositeType comptype, | |
| 97 | + SurfaceType dsttype) | |
| 98 | + { | |
| 99 | + super(srctype, comptype, dsttype); | |
| 100 | + fillop = MaskFill.locate(srctype, comptype, dsttype); | |
| 101 | + } | |
| 102 | + | |
| 103 | + public void FillRect(SunGraphics2D sg2d, SurfaceData dest, | |
| 104 | + int x, int y, int w, int h) | |
| 105 | + { | |
| 106 | + fillop.MaskFill(sg2d, dest, sg2d.composite, x, y, w, h, null, 0, 0); | |
| 107 | + } | |
| 108 | + } | |
| 109 | + | |
| 110 | + public GraphicsPrimitive traceWrap() { | |
| 111 | + return new TraceFillRect(this); | |
| 112 | + } | |
| 113 | + | |
| 114 | + private static class TraceFillRect extends FillRect { | |
| 115 | + FillRect target; | |
| 116 | + | |
| 117 | + public TraceFillRect(FillRect target) { | |
| 118 | + super(target.getSourceType(), | |
| 119 | + target.getCompositeType(), | |
| 120 | + target.getDestType()); | |
| 121 | + this.target = target; | |
| 122 | + } | |
| 123 | + | |
| 124 | + public GraphicsPrimitive traceWrap() { | |
| 125 | + return this; | |
| 126 | + } | |
| 127 | + | |
| 128 | + public void FillRect(SunGraphics2D sg2d, SurfaceData dest, | |
| 129 | + int x, int y, int w, int h) | |
| 130 | + { | |
| 131 | + tracePrimitive(target); | |
| 132 | + target.FillRect(sg2d, dest, x, y, w, h); | |
| 133 | + } | |
| 134 | + } | |
| 135 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,122 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 2002, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | + /* | |
| 27 | + * @author Jim Graham | |
| 28 | + * @author Charlton Innovations, Inc. | |
| 29 | + */ | |
| 30 | + | |
| 31 | +package sun.java2d.loops; | |
| 32 | + | |
| 33 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 34 | +import sun.java2d.pipe.SpanIterator; | |
| 35 | +import java.awt.Color; | |
| 36 | +import java.awt.image.ColorModel; | |
| 37 | +import java.awt.image.Raster; | |
| 38 | +import sun.java2d.SunGraphics2D; | |
| 39 | +import sun.java2d.SurfaceData; | |
| 40 | + | |
| 41 | +/** | |
| 42 | + * FillSpans | |
| 43 | + * 1) draw solid color onto destination surface | |
| 44 | + * 2) rectangular areas to fill come from SpanIterator | |
| 45 | + */ | |
| 46 | +public class FillSpans extends GraphicsPrimitive | |
| 47 | +{ | |
| 48 | + public final static String methodSignature = "FillSpans(...)".toString(); | |
| 49 | + | |
| 50 | + public final static int primTypeID = makePrimTypeID(); | |
| 51 | + | |
| 52 | + public static FillSpans locate(SurfaceType srctype, | |
| 53 | + CompositeType comptype, | |
| 54 | + SurfaceType dsttype) | |
| 55 | + { | |
| 56 | + return (FillSpans) | |
| 57 | + GraphicsPrimitiveMgr.locate(primTypeID, | |
| 58 | + srctype, comptype, dsttype); | |
| 59 | + } | |
| 60 | + | |
| 61 | + protected FillSpans(SurfaceType srctype, | |
| 62 | + CompositeType comptype, | |
| 63 | + SurfaceType dsttype) | |
| 64 | + { | |
| 65 | + super(methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 66 | + } | |
| 67 | + | |
| 68 | + public FillSpans(long pNativePrim, | |
| 69 | + SurfaceType srctype, | |
| 70 | + CompositeType comptype, | |
| 71 | + SurfaceType dsttype) | |
| 72 | + { | |
| 73 | + super(pNativePrim, methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 74 | + } | |
| 75 | + | |
| 76 | + private native void FillSpans(SunGraphics2D sg2d, SurfaceData dest, | |
| 77 | + int pixel, long pIterator, SpanIterator si); | |
| 78 | + | |
| 79 | + /** | |
| 80 | + * All FillSpan implementors must have this invoker method | |
| 81 | + */ | |
| 82 | + public void FillSpans(SunGraphics2D sg2d, SurfaceData dest, | |
| 83 | + SpanIterator si) | |
| 84 | + { | |
| 85 | + FillSpans(sg2d, dest, sg2d.pixel, si.getNativeIterator(), si); | |
| 86 | + } | |
| 87 | + | |
| 88 | + public GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 89 | + CompositeType comptype, | |
| 90 | + SurfaceType dsttype) | |
| 91 | + { | |
| 92 | + // REMIND: iterate with a FillRect primitive? | |
| 93 | + throw new InternalError("FillSpans not implemented for "+ | |
| 94 | + srctype+" with "+comptype); | |
| 95 | + } | |
| 96 | + | |
| 97 | + public GraphicsPrimitive traceWrap() { | |
| 98 | + return new TraceFillSpans(this); | |
| 99 | + } | |
| 100 | + | |
| 101 | + private static class TraceFillSpans extends FillSpans { | |
| 102 | + FillSpans target; | |
| 103 | + | |
| 104 | + public TraceFillSpans(FillSpans target) { | |
| 105 | + super(target.getSourceType(), | |
| 106 | + target.getCompositeType(), | |
| 107 | + target.getDestType()); | |
| 108 | + this.target = target; | |
| 109 | + } | |
| 110 | + | |
| 111 | + public GraphicsPrimitive traceWrap() { | |
| 112 | + return this; | |
| 113 | + } | |
| 114 | + | |
| 115 | + public void FillSpans(SunGraphics2D sg2d, SurfaceData dest, | |
| 116 | + SpanIterator si) | |
| 117 | + { | |
| 118 | + tracePrimitive(target); | |
| 119 | + target.FillSpans(sg2d, dest, si); | |
| 120 | + } | |
| 121 | + } | |
| 122 | +} | |
Binary file not shown.
| @@ -0,0 +1,89 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1999, 2005, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.loops; | |
| 27 | + | |
| 28 | +import java.awt.Font; | |
| 29 | +import java.awt.geom.AffineTransform; | |
| 30 | + | |
| 31 | +import sun.font.Font2D; | |
| 32 | +import sun.font.FontStrike; | |
| 33 | +import sun.font.FontStrikeDesc; | |
| 34 | + | |
| 35 | +/* | |
| 36 | + * A FontInfo object holds all calculated or derived data needed | |
| 37 | + * to handle rendering operations based on a particular set of | |
| 38 | + * Graphics2D rendering attributes. | |
| 39 | + * Note that this does not use a Font2DHandle, and also has a reference | |
| 40 | + * to the strike which also references the Font2D. | |
| 41 | + * So presently, until SG2D objects no longer reference this FontInfo, | |
| 42 | + * there is still some potential for a bad Font2D to be used for a short | |
| 43 | + * time. I am reluctant to add the overhead of that machinery here without | |
| 44 | + * a proven benefit. | |
| 45 | + */ | |
| 46 | +public class FontInfo implements Cloneable { | |
| 47 | + public Font font; | |
| 48 | + public Font2D font2D; | |
| 49 | + public FontStrike fontStrike; | |
| 50 | + public double[] devTx; | |
| 51 | + public double[] glyphTx; | |
| 52 | + public int pixelHeight; | |
| 53 | + public float originX; | |
| 54 | + public float originY; | |
| 55 | + public int aaHint; | |
| 56 | + public boolean lcdRGBOrder; | |
| 57 | + /* lcdSubPixPos is used if FM is ON for HRGB/HBGR LCD text mode */ | |
| 58 | + public boolean lcdSubPixPos; | |
| 59 | + | |
| 60 | + public String mtx(double[] matrix) { | |
| 61 | + return ("["+ | |
| 62 | + matrix[0]+", "+ | |
| 63 | + matrix[1]+", "+ | |
| 64 | + matrix[2]+", "+ | |
| 65 | + matrix[3]+ | |
| 66 | + "]"); | |
| 67 | + } | |
| 68 | + | |
| 69 | + public Object clone() { | |
| 70 | + try { | |
| 71 | + return super.clone(); | |
| 72 | + } catch (CloneNotSupportedException e) { | |
| 73 | + return null; | |
| 74 | + } | |
| 75 | + } | |
| 76 | + | |
| 77 | + public String toString() { | |
| 78 | + return ("FontInfo["+ | |
| 79 | + "font="+font+", "+ | |
| 80 | + "devTx="+mtx(devTx)+", "+ | |
| 81 | + "glyphTx="+mtx(glyphTx)+", "+ | |
| 82 | + "pixelHeight="+pixelHeight+", "+ | |
| 83 | + "origin=("+originX+","+originY+"), "+ | |
| 84 | + "aaHint="+aaHint+", "+ | |
| 85 | + "lcdRGBOrder="+(lcdRGBOrder ? "RGB" : "BGR")+ | |
| 86 | + "lcdSubPixPos="+lcdSubPixPos+ | |
| 87 | + "]"); | |
| 88 | + } | |
| 89 | +} | |
Binary file not shown.
| @@ -0,0 +1,1125 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +/* | |
| 27 | + * @author Charlton Innovations, Inc. | |
| 28 | + */ | |
| 29 | + | |
| 30 | +package sun.java2d.loops; | |
| 31 | + | |
| 32 | +import java.awt.image.WritableRaster; | |
| 33 | +import java.awt.image.DataBuffer; | |
| 34 | +import java.awt.image.ColorModel; | |
| 35 | +import java.awt.geom.Path2D; | |
| 36 | +import java.awt.geom.PathIterator; | |
| 37 | +import java.awt.geom.AffineTransform; | |
| 38 | +import sun.java2d.pipe.Region; | |
| 39 | +import sun.java2d.pipe.SpanIterator; | |
| 40 | +import sun.java2d.SunGraphics2D; | |
| 41 | +import sun.java2d.SurfaceData; | |
| 42 | +import sun.java2d.loops.ProcessPath; | |
| 43 | +import sun.font.GlyphList; | |
| 44 | + | |
| 45 | +/** | |
| 46 | + * GeneralRenderer collection | |
| 47 | + * Basically, a collection of components which permit basic | |
| 48 | + * rendering to occur on rasters of any format | |
| 49 | + */ | |
| 50 | + | |
| 51 | +public final class GeneralRenderer { | |
| 52 | + public static void register() { | |
| 53 | + Class owner = GeneralRenderer.class; | |
| 54 | + GraphicsPrimitive[] primitives = { | |
| 55 | + new GraphicsPrimitiveProxy(owner, "SetFillRectANY", | |
| 56 | + FillRect.methodSignature, | |
| 57 | + FillRect.primTypeID, | |
| 58 | + SurfaceType.AnyColor, | |
| 59 | + CompositeType.SrcNoEa, | |
| 60 | + SurfaceType.Any), | |
| 61 | + new GraphicsPrimitiveProxy(owner, "SetFillPathANY", | |
| 62 | + FillPath.methodSignature, | |
| 63 | + FillPath.primTypeID, | |
| 64 | + SurfaceType.AnyColor, | |
| 65 | + CompositeType.SrcNoEa, | |
| 66 | + SurfaceType.Any), | |
| 67 | + new GraphicsPrimitiveProxy(owner, "SetFillSpansANY", | |
| 68 | + FillSpans.methodSignature, | |
| 69 | + FillSpans.primTypeID, | |
| 70 | + SurfaceType.AnyColor, | |
| 71 | + CompositeType.SrcNoEa, | |
| 72 | + SurfaceType.Any), | |
| 73 | + new GraphicsPrimitiveProxy(owner, "SetDrawLineANY", | |
| 74 | + DrawLine.methodSignature, | |
| 75 | + DrawLine.primTypeID, | |
| 76 | + SurfaceType.AnyColor, | |
| 77 | + CompositeType.SrcNoEa, | |
| 78 | + SurfaceType.Any), | |
| 79 | + new GraphicsPrimitiveProxy(owner, "SetDrawPolygonsANY", | |
| 80 | + DrawPolygons.methodSignature, | |
| 81 | + DrawPolygons.primTypeID, | |
| 82 | + SurfaceType.AnyColor, | |
| 83 | + CompositeType.SrcNoEa, | |
| 84 | + SurfaceType.Any), | |
| 85 | + new GraphicsPrimitiveProxy(owner, "SetDrawPathANY", | |
| 86 | + DrawPath.methodSignature, | |
| 87 | + DrawPath.primTypeID, | |
| 88 | + SurfaceType.AnyColor, | |
| 89 | + CompositeType.SrcNoEa, | |
| 90 | + SurfaceType.Any), | |
| 91 | + new GraphicsPrimitiveProxy(owner, "SetDrawRectANY", | |
| 92 | + DrawRect.methodSignature, | |
| 93 | + DrawRect.primTypeID, | |
| 94 | + SurfaceType.AnyColor, | |
| 95 | + CompositeType.SrcNoEa, | |
| 96 | + SurfaceType.Any), | |
| 97 | + | |
| 98 | + new GraphicsPrimitiveProxy(owner, "XorFillRectANY", | |
| 99 | + FillRect.methodSignature, | |
| 100 | + FillRect.primTypeID, | |
| 101 | + SurfaceType.AnyColor, | |
| 102 | + CompositeType.Xor, | |
| 103 | + SurfaceType.Any), | |
| 104 | + new GraphicsPrimitiveProxy(owner, "XorFillPathANY", | |
| 105 | + FillPath.methodSignature, | |
| 106 | + FillPath.primTypeID, | |
| 107 | + SurfaceType.AnyColor, | |
| 108 | + CompositeType.Xor, | |
| 109 | + SurfaceType.Any), | |
| 110 | + new GraphicsPrimitiveProxy(owner, "XorFillSpansANY", | |
| 111 | + FillSpans.methodSignature, | |
| 112 | + FillSpans.primTypeID, | |
| 113 | + SurfaceType.AnyColor, | |
| 114 | + CompositeType.Xor, | |
| 115 | + SurfaceType.Any), | |
| 116 | + new GraphicsPrimitiveProxy(owner, "XorDrawLineANY", | |
| 117 | + DrawLine.methodSignature, | |
| 118 | + DrawLine.primTypeID, | |
| 119 | + SurfaceType.AnyColor, | |
| 120 | + CompositeType.Xor, | |
| 121 | + SurfaceType.Any), | |
| 122 | + new GraphicsPrimitiveProxy(owner, "XorDrawPolygonsANY", | |
| 123 | + DrawPolygons.methodSignature, | |
| 124 | + DrawPolygons.primTypeID, | |
| 125 | + SurfaceType.AnyColor, | |
| 126 | + CompositeType.Xor, | |
| 127 | + SurfaceType.Any), | |
| 128 | + new GraphicsPrimitiveProxy(owner, "XorDrawPathANY", | |
| 129 | + DrawPath.methodSignature, | |
| 130 | + DrawPath.primTypeID, | |
| 131 | + SurfaceType.AnyColor, | |
| 132 | + CompositeType.Xor, | |
| 133 | + SurfaceType.Any), | |
| 134 | + new GraphicsPrimitiveProxy(owner, "XorDrawRectANY", | |
| 135 | + DrawRect.methodSignature, | |
| 136 | + DrawRect.primTypeID, | |
| 137 | + SurfaceType.AnyColor, | |
| 138 | + CompositeType.Xor, | |
| 139 | + SurfaceType.Any), | |
| 140 | + new GraphicsPrimitiveProxy(owner, "XorDrawGlyphListANY", | |
| 141 | + DrawGlyphList.methodSignature, | |
| 142 | + DrawGlyphList.primTypeID, | |
| 143 | + SurfaceType.AnyColor, | |
| 144 | + CompositeType.Xor, | |
| 145 | + SurfaceType.Any), | |
| 146 | + new GraphicsPrimitiveProxy(owner, "XorDrawGlyphListAAANY", | |
| 147 | + DrawGlyphListAA.methodSignature, | |
| 148 | + DrawGlyphListAA.primTypeID, | |
| 149 | + SurfaceType.AnyColor, | |
| 150 | + CompositeType.Xor, | |
| 151 | + SurfaceType.Any), | |
| 152 | + }; | |
| 153 | + GraphicsPrimitiveMgr.register(primitives); | |
| 154 | + } | |
| 155 | + | |
| 156 | + static void doDrawPoly(SurfaceData sData, PixelWriter pw, | |
| 157 | + int xPoints[], int yPoints[], int off, int nPoints, | |
| 158 | + Region clip, int transx, int transy, boolean close) | |
| 159 | + { | |
| 160 | + int mx, my, x1, y1; | |
| 161 | + int[] tmp = null; | |
| 162 | + | |
| 163 | + if (nPoints <= 0) { | |
| 164 | + return; | |
| 165 | + } | |
| 166 | + mx = x1 = xPoints[off] + transx; | |
| 167 | + my = y1 = yPoints[off] + transy; | |
| 168 | + while (--nPoints > 0) { | |
| 169 | + ++off; | |
| 170 | + int x2 = xPoints[off] + transx; | |
| 171 | + int y2 = yPoints[off] + transy; | |
| 172 | + tmp = GeneralRenderer.doDrawLine(sData, pw, tmp, clip, | |
| 173 | + x1, y1, x2, y2); | |
| 174 | + x1 = x2; | |
| 175 | + y1 = y2; | |
| 176 | + } | |
| 177 | + if (close && (x1 != mx || y1 != my)) { | |
| 178 | + tmp = GeneralRenderer.doDrawLine(sData, pw, tmp, clip, | |
| 179 | + x1, y1, mx, my); | |
| 180 | + } | |
| 181 | + } | |
| 182 | + | |
| 183 | + static void doSetRect(SurfaceData sData, PixelWriter pw, | |
| 184 | + int x1, int y1, int x2, int y2) { | |
| 185 | + WritableRaster dstRast = | |
| 186 | + (WritableRaster) sData.getRaster(x1, y1, x2-x1, y2-y1); | |
| 187 | + pw.setRaster(dstRast); | |
| 188 | + | |
| 189 | + while (y1 < y2) { | |
| 190 | + for (int x = x1; x < x2; x++) { | |
| 191 | + pw.writePixel(x, y1); | |
| 192 | + } | |
| 193 | + y1++; | |
| 194 | + } | |
| 195 | + } | |
| 196 | + | |
| 197 | + static int[] doDrawLine(SurfaceData sData, PixelWriter pw, int[] boundPts, | |
| 198 | + Region clip, | |
| 199 | + int origx1, int origy1, int origx2, int origy2) | |
| 200 | + { | |
| 201 | + if (boundPts == null) { | |
| 202 | + boundPts = new int[8]; | |
| 203 | + } | |
| 204 | + boundPts[0] = origx1; | |
| 205 | + boundPts[1] = origy1; | |
| 206 | + boundPts[2] = origx2; | |
| 207 | + boundPts[3] = origy2; | |
| 208 | + if (!adjustLine(boundPts, | |
| 209 | + clip.getLoX(), clip.getLoY(), | |
| 210 | + clip.getHiX(), clip.getHiY())) | |
| 211 | + { | |
| 212 | + return boundPts; | |
| 213 | + } | |
| 214 | + int x1 = boundPts[0]; | |
| 215 | + int y1 = boundPts[1]; | |
| 216 | + int x2 = boundPts[2]; | |
| 217 | + int y2 = boundPts[3]; | |
| 218 | + | |
| 219 | + WritableRaster dstRast = (WritableRaster) | |
| 220 | + sData.getRaster(Math.min(x1, x2), Math.min(y1, y2), | |
| 221 | + Math.abs(x1 - x2) + 1, Math.abs(y1 - y2) + 1); | |
| 222 | + pw.setRaster(dstRast); | |
| 223 | + | |
| 224 | + /* this could be made smaller, more elegant, more traditional. */ | |
| 225 | + if (x1 == x2) { | |
| 226 | + if (y1 > y2) { | |
| 227 | + do { | |
| 228 | + pw.writePixel(x1, y1); | |
| 229 | + y1--; | |
| 230 | + } while (y1 >= y2); | |
| 231 | + } else { | |
| 232 | + do { | |
| 233 | + pw.writePixel(x1, y1); | |
| 234 | + y1++; | |
| 235 | + } while (y1 <= y2); | |
| 236 | + } | |
| 237 | + } else if (y1 == y2) { | |
| 238 | + if (x1 > x2) { | |
| 239 | + do { | |
| 240 | + pw.writePixel(x1, y1); | |
| 241 | + x1--; | |
| 242 | + } while (x1 >= x2); | |
| 243 | + } else { | |
| 244 | + do { | |
| 245 | + pw.writePixel(x1, y1); | |
| 246 | + x1++; | |
| 247 | + } while (x1 <= x2); | |
| 248 | + } | |
| 249 | + } else { | |
| 250 | + int dx = boundPts[4]; | |
| 251 | + int dy = boundPts[5]; | |
| 252 | + int ax = boundPts[6]; | |
| 253 | + int ay = boundPts[7]; | |
| 254 | + int steps; | |
| 255 | + int bumpmajor; | |
| 256 | + int bumpminor; | |
| 257 | + int errminor; | |
| 258 | + int errmajor; | |
| 259 | + int error; | |
| 260 | + boolean xmajor; | |
| 261 | + | |
| 262 | + if (ax >= ay) { | |
| 263 | + /* x is dominant */ | |
| 264 | + xmajor = true; | |
| 265 | + errmajor = ay * 2; | |
| 266 | + errminor = ax * 2; | |
| 267 | + bumpmajor = (dx < 0) ? -1 : 1; | |
| 268 | + bumpminor = (dy < 0) ? -1 : 1; | |
| 269 | + ax = -ax; /* For clipping adjustment below */ | |
| 270 | + steps = x2 - x1; | |
| 271 | + } else { | |
| 272 | + /* y is dominant */ | |
| 273 | + xmajor = false; | |
| 274 | + errmajor = ax * 2; | |
| 275 | + errminor = ay * 2; | |
| 276 | + bumpmajor = (dy < 0) ? -1 : 1; | |
| 277 | + bumpminor = (dx < 0) ? -1 : 1; | |
| 278 | + ay = -ay; /* For clipping adjustment below */ | |
| 279 | + steps = y2 - y1; | |
| 280 | + } | |
| 281 | + error = - (errminor / 2); | |
| 282 | + if (y1 != origy1) { | |
| 283 | + int ysteps = y1 - origy1; | |
| 284 | + if (ysteps < 0) { | |
| 285 | + ysteps = -ysteps; | |
| 286 | + } | |
| 287 | + error += ysteps * ax * 2; | |
| 288 | + } | |
| 289 | + if (x1 != origx1) { | |
| 290 | + int xsteps = x1 - origx1; | |
| 291 | + if (xsteps < 0) { | |
| 292 | + xsteps = -xsteps; | |
| 293 | + } | |
| 294 | + error += xsteps * ay * 2; | |
| 295 | + } | |
| 296 | + if (steps < 0) { | |
| 297 | + steps = -steps; | |
| 298 | + } | |
| 299 | + if (xmajor) { | |
| 300 | + do { | |
| 301 | + pw.writePixel(x1, y1); | |
| 302 | + x1 += bumpmajor; | |
| 303 | + error += errmajor; | |
| 304 | + if (error >= 0) { | |
| 305 | + y1 += bumpminor; | |
| 306 | + error -= errminor; | |
| 307 | + } | |
| 308 | + } while (--steps >= 0); | |
| 309 | + } else { | |
| 310 | + do { | |
| 311 | + pw.writePixel(x1, y1); | |
| 312 | + y1 += bumpmajor; | |
| 313 | + error += errmajor; | |
| 314 | + if (error >= 0) { | |
| 315 | + x1 += bumpminor; | |
| 316 | + error -= errminor; | |
| 317 | + } | |
| 318 | + } while (--steps >= 0); | |
| 319 | + } | |
| 320 | + } | |
| 321 | + return boundPts; | |
| 322 | + } | |
| 323 | + | |
| 324 | + public static void doDrawRect(PixelWriter pw, | |
| 325 | + SunGraphics2D sg2d, SurfaceData sData, | |
| 326 | + int x, int y, int w, int h) | |
| 327 | + { | |
| 328 | + if (w < 0 || h < 0) { | |
| 329 | + return; | |
| 330 | + } | |
| 331 | + int x2 = Region.dimAdd(Region.dimAdd(x, w), 1); | |
| 332 | + int y2 = Region.dimAdd(Region.dimAdd(y, h), 1); | |
| 333 | + Region r = sg2d.getCompClip().getBoundsIntersectionXYXY(x, y, x2, y2); | |
| 334 | + if (r.isEmpty()) { | |
| 335 | + return; | |
| 336 | + } | |
| 337 | + int cx1 = r.getLoX(); | |
| 338 | + int cy1 = r.getLoY(); | |
| 339 | + int cx2 = r.getHiX(); | |
| 340 | + int cy2 = r.getHiY(); | |
| 341 | + | |
| 342 | + if (w < 2 || h < 2) { | |
| 343 | + doSetRect(sData, pw, cx1, cy1, cx2, cy2); | |
| 344 | + return; | |
| 345 | + } | |
| 346 | + | |
| 347 | + | |
| 348 | + if (cy1 == y) { | |
| 349 | + doSetRect(sData, pw, cx1, cy1, cx2, cy1+1); | |
| 350 | + } | |
| 351 | + if (cx1 == x) { | |
| 352 | + doSetRect(sData, pw, cx1, cy1+1, cx1+1, cy2-1); | |
| 353 | + } | |
| 354 | + if (cx2 == x2) { | |
| 355 | + doSetRect(sData, pw, cx2-1, cy1+1, cx2, cy2-1); | |
| 356 | + } | |
| 357 | + if (cy2 == y2) { | |
| 358 | + doSetRect(sData, pw, cx1, cy2-1, cx2, cy2); | |
| 359 | + } | |
| 360 | + } | |
| 361 | + | |
| 362 | + /* | |
| 363 | + * REMIND: For now this will field both AA and non-AA requests and | |
| 364 | + * use a simple threshold to choose pixels if the supplied grey | |
| 365 | + * bits are antialiased. We should really find a way to disable | |
| 366 | + * AA text at a higher level or to have the GlyphList be able to | |
| 367 | + * reset the glyphs to non-AA after construction. | |
| 368 | + */ | |
| 369 | + static void doDrawGlyphList(SurfaceData sData, PixelWriter pw, | |
| 370 | + GlyphList gl, Region clip) | |
| 371 | + { | |
| 372 | + int[] bounds = gl.getBounds(); | |
| 373 | + clip.clipBoxToBounds(bounds); | |
| 374 | + int cx1 = bounds[0]; | |
| 375 | + int cy1 = bounds[1]; | |
| 376 | + int cx2 = bounds[2]; | |
| 377 | + int cy2 = bounds[3]; | |
| 378 | + | |
| 379 | + WritableRaster dstRast = | |
| 380 | + (WritableRaster) sData.getRaster(cx1, cy1, cx2 - cx1, cy2 - cy1); | |
| 381 | + pw.setRaster(dstRast); | |
| 382 | + | |
| 383 | + int num = gl.getNumGlyphs(); | |
| 384 | + for (int i = 0; i < num; i++) { | |
| 385 | + gl.setGlyphIndex(i); | |
| 386 | + int metrics[] = gl.getMetrics(); | |
| 387 | + int gx1 = metrics[0]; | |
| 388 | + int gy1 = metrics[1]; | |
| 389 | + int w = metrics[2]; | |
| 390 | + int gx2 = gx1 + w; | |
| 391 | + int gy2 = gy1 + metrics[3]; | |
| 392 | + int off = 0; | |
| 393 | + if (gx1 < cx1) { | |
| 394 | + off = cx1 - gx1; | |
| 395 | + gx1 = cx1; | |
| 396 | + } | |
| 397 | + if (gy1 < cy1) { | |
| 398 | + off += (cy1 - gy1) * w; | |
| 399 | + gy1 = cy1; | |
| 400 | + } | |
| 401 | + if (gx2 > cx2) gx2 = cx2; | |
| 402 | + if (gy2 > cy2) gy2 = cy2; | |
| 403 | + if (gx2 > gx1 && gy2 > gy1) { | |
| 404 | + byte alpha[] = gl.getGrayBits(); | |
| 405 | + w -= (gx2 - gx1); | |
| 406 | + for (int y = gy1; y < gy2; y++) { | |
| 407 | + for (int x = gx1; x < gx2; x++) { | |
| 408 | + if (alpha[off++] < 0) { | |
| 409 | + pw.writePixel(x, y); | |
| 410 | + } | |
| 411 | + } | |
| 412 | + off += w; | |
| 413 | + } | |
| 414 | + } | |
| 415 | + } | |
| 416 | + } | |
| 417 | + | |
| 418 | + static final int OUTCODE_TOP = 1; | |
| 419 | + static final int OUTCODE_BOTTOM = 2; | |
| 420 | + static final int OUTCODE_LEFT = 4; | |
| 421 | + static final int OUTCODE_RIGHT = 8; | |
| 422 | + | |
| 423 | + static int outcode(int x, int y, int xmin, int ymin, int xmax, int ymax) { | |
| 424 | + int code; | |
| 425 | + if (y < ymin) { | |
| 426 | + code = OUTCODE_TOP; | |
| 427 | + } else if (y > ymax) { | |
| 428 | + code = OUTCODE_BOTTOM; | |
| 429 | + } else { | |
| 430 | + code = 0; | |
| 431 | + } | |
| 432 | + if (x < xmin) { | |
| 433 | + code |= OUTCODE_LEFT; | |
| 434 | + } else if (x > xmax) { | |
| 435 | + code |= OUTCODE_RIGHT; | |
| 436 | + } | |
| 437 | + return code; | |
| 438 | + } | |
| 439 | + | |
| 440 | + public static boolean adjustLine(int [] boundPts, | |
| 441 | + int cxmin, int cymin, int cx2, int cy2) | |
| 442 | + { | |
| 443 | + int cxmax = cx2 - 1; | |
| 444 | + int cymax = cy2 - 1; | |
| 445 | + int x1 = boundPts[0]; | |
| 446 | + int y1 = boundPts[1]; | |
| 447 | + int x2 = boundPts[2]; | |
| 448 | + int y2 = boundPts[3]; | |
| 449 | + | |
| 450 | + if ((cxmax < cxmin) || (cymax < cymin)) { | |
| 451 | + return false; | |
| 452 | + } | |
| 453 | + | |
| 454 | + if (x1 == x2) { | |
| 455 | + if (x1 < cxmin || x1 > cxmax) { | |
| 456 | + return false; | |
| 457 | + } | |
| 458 | + if (y1 > y2) { | |
| 459 | + int t = y1; | |
| 460 | + y1 = y2; | |
| 461 | + y2 = t; | |
| 462 | + } | |
| 463 | + if (y1 < cymin) { | |
| 464 | + y1 = cymin; | |
| 465 | + } | |
| 466 | + if (y2 > cymax) { | |
| 467 | + y2 = cymax; | |
| 468 | + } | |
| 469 | + if (y1 > y2) { | |
| 470 | + return false; | |
| 471 | + } | |
| 472 | + boundPts[1] = y1; | |
| 473 | + boundPts[3] = y2; | |
| 474 | + } else if (y1 == y2) { | |
| 475 | + if (y1 < cymin || y1 > cymax) { | |
| 476 | + return false; | |
| 477 | + } | |
| 478 | + if (x1 > x2) { | |
| 479 | + int t = x1; | |
| 480 | + x1 = x2; | |
| 481 | + x2 = t; | |
| 482 | + } | |
| 483 | + if (x1 < cxmin) { | |
| 484 | + x1 = cxmin; | |
| 485 | + } | |
| 486 | + if (x2 > cxmax) { | |
| 487 | + x2 = cxmax; | |
| 488 | + } | |
| 489 | + if (x1 > x2) { | |
| 490 | + return false; | |
| 491 | + } | |
| 492 | + boundPts[0] = x1; | |
| 493 | + boundPts[2] = x2; | |
| 494 | + } else { | |
| 495 | + /* REMIND: This could overflow... */ | |
| 496 | + int outcode1, outcode2; | |
| 497 | + int dx = x2 - x1; | |
| 498 | + int dy = y2 - y1; | |
| 499 | + int ax = (dx < 0) ? -dx : dx; | |
| 500 | + int ay = (dy < 0) ? -dy : dy; | |
| 501 | + boolean xmajor = (ax >= ay); | |
| 502 | + | |
| 503 | + outcode1 = outcode(x1, y1, cxmin, cymin, cxmax, cymax); | |
| 504 | + outcode2 = outcode(x2, y2, cxmin, cymin, cxmax, cymax); | |
| 505 | + while ((outcode1 | outcode2) != 0) { | |
| 506 | + int xsteps, ysteps; | |
| 507 | + if ((outcode1 & outcode2) != 0) { | |
| 508 | + return false; | |
| 509 | + } | |
| 510 | + if (outcode1 != 0) { | |
| 511 | + if (0 != (outcode1 & (OUTCODE_TOP | OUTCODE_BOTTOM))) { | |
| 512 | + if (0 != (outcode1 & OUTCODE_TOP)) { | |
| 513 | + y1 = cymin; | |
| 514 | + } else { | |
| 515 | + y1 = cymax; | |
| 516 | + } | |
| 517 | + ysteps = y1 - boundPts[1]; | |
| 518 | + if (ysteps < 0) { | |
| 519 | + ysteps = -ysteps; | |
| 520 | + } | |
| 521 | + xsteps = 2 * ysteps * ax + ay; | |
| 522 | + if (xmajor) { | |
| 523 | + xsteps += ay - ax - 1; | |
| 524 | + } | |
| 525 | + xsteps = xsteps / (2 * ay); | |
| 526 | + if (dx < 0) { | |
| 527 | + xsteps = -xsteps; | |
| 528 | + } | |
| 529 | + x1 = boundPts[0] + xsteps; | |
| 530 | + } else if (0 != | |
| 531 | + (outcode1 & (OUTCODE_LEFT | OUTCODE_RIGHT))) { | |
| 532 | + if (0 != (outcode1 & OUTCODE_LEFT)) { | |
| 533 | + x1 = cxmin; | |
| 534 | + } else { | |
| 535 | + x1 = cxmax; | |
| 536 | + } | |
| 537 | + xsteps = x1 - boundPts[0]; | |
| 538 | + if (xsteps < 0) { | |
| 539 | + xsteps = -xsteps; | |
| 540 | + } | |
| 541 | + ysteps = 2 * xsteps * ay + ax; | |
| 542 | + if (!xmajor) { | |
| 543 | + ysteps += ax - ay - 1; | |
| 544 | + } | |
| 545 | + ysteps = ysteps / (2 * ax); | |
| 546 | + if (dy < 0) { | |
| 547 | + ysteps = -ysteps; | |
| 548 | + } | |
| 549 | + y1 = boundPts[1] + ysteps; | |
| 550 | + } | |
| 551 | + outcode1 = outcode(x1, y1, cxmin, cymin, cxmax, cymax); | |
| 552 | + } else { | |
| 553 | + if (0 != (outcode2 & (OUTCODE_TOP | OUTCODE_BOTTOM))) { | |
| 554 | + if (0 != (outcode2 & OUTCODE_TOP)) { | |
| 555 | + y2 = cymin; | |
| 556 | + } else { | |
| 557 | + y2 = cymax; | |
| 558 | + } | |
| 559 | + ysteps = y2 - boundPts[3]; | |
| 560 | + if (ysteps < 0) { | |
| 561 | + ysteps = -ysteps; | |
| 562 | + } | |
| 563 | + xsteps = 2 * ysteps * ax + ay; | |
| 564 | + if (xmajor) { | |
| 565 | + xsteps += ay - ax; | |
| 566 | + } else { | |
| 567 | + xsteps -= 1; | |
| 568 | + } | |
| 569 | + xsteps = xsteps / (2 * ay); | |
| 570 | + if (dx > 0) { | |
| 571 | + xsteps = -xsteps; | |
| 572 | + } | |
| 573 | + x2 = boundPts[2] + xsteps; | |
| 574 | + } else if (0 != | |
| 575 | + (outcode2 & (OUTCODE_LEFT | OUTCODE_RIGHT))) { | |
| 576 | + if (0 != (outcode2 & OUTCODE_LEFT)) { | |
| 577 | + x2 = cxmin; | |
| 578 | + } else { | |
| 579 | + x2 = cxmax; | |
| 580 | + } | |
| 581 | + xsteps = x2 - boundPts[2]; | |
| 582 | + if (xsteps < 0) { | |
| 583 | + xsteps = -xsteps; | |
| 584 | + } | |
| 585 | + ysteps = 2 * xsteps * ay + ax; | |
| 586 | + if (xmajor) { | |
| 587 | + ysteps -= 1; | |
| 588 | + } else { | |
| 589 | + ysteps += ax - ay; | |
| 590 | + } | |
| 591 | + ysteps = ysteps / (2 * ax); | |
| 592 | + if (dy > 0) { | |
| 593 | + ysteps = -ysteps; | |
| 594 | + } | |
| 595 | + y2 = boundPts[3] + ysteps; | |
| 596 | + } | |
| 597 | + outcode2 = outcode(x2, y2, cxmin, cymin, cxmax, cymax); | |
| 598 | + } | |
| 599 | + } | |
| 600 | + boundPts[0] = x1; | |
| 601 | + boundPts[1] = y1; | |
| 602 | + boundPts[2] = x2; | |
| 603 | + boundPts[3] = y2; | |
| 604 | + boundPts[4] = dx; | |
| 605 | + boundPts[5] = dy; | |
| 606 | + boundPts[6] = ax; | |
| 607 | + boundPts[7] = ay; | |
| 608 | + } | |
| 609 | + return true; | |
| 610 | + } | |
| 611 | + | |
| 612 | + static PixelWriter createSolidPixelWriter(SunGraphics2D sg2d, | |
| 613 | + SurfaceData sData) | |
| 614 | + { | |
| 615 | + ColorModel dstCM = sData.getColorModel(); | |
| 616 | + Object srcPixel = dstCM.getDataElements(sg2d.eargb, null); | |
| 617 | + | |
| 618 | + return new SolidPixelWriter(srcPixel); | |
| 619 | + } | |
| 620 | + | |
| 621 | + static PixelWriter createXorPixelWriter(SunGraphics2D sg2d, | |
| 622 | + SurfaceData sData) | |
| 623 | + { | |
| 624 | + ColorModel dstCM = sData.getColorModel(); | |
| 625 | + | |
| 626 | + Object srcPixel = dstCM.getDataElements(sg2d.eargb, null); | |
| 627 | + | |
| 628 | + XORComposite comp = (XORComposite)sg2d.getComposite(); | |
| 629 | + int xorrgb = comp.getXorColor().getRGB(); | |
| 630 | + Object xorPixel = dstCM.getDataElements(xorrgb, null); | |
| 631 | + | |
| 632 | + switch (dstCM.getTransferType()) { | |
| 633 | + case DataBuffer.TYPE_BYTE: | |
| 634 | + return new XorPixelWriter.ByteData(srcPixel, xorPixel); | |
| 635 | + case DataBuffer.TYPE_SHORT: | |
| 636 | + case DataBuffer.TYPE_USHORT: | |
| 637 | + return new XorPixelWriter.ShortData(srcPixel, xorPixel); | |
| 638 | + case DataBuffer.TYPE_INT: | |
| 639 | + return new XorPixelWriter.IntData(srcPixel, xorPixel); | |
| 640 | + case DataBuffer.TYPE_FLOAT: | |
| 641 | + return new XorPixelWriter.FloatData(srcPixel, xorPixel); | |
| 642 | + case DataBuffer.TYPE_DOUBLE: | |
| 643 | + return new XorPixelWriter.DoubleData(srcPixel, xorPixel); | |
| 644 | + default: | |
| 645 | + throw new InternalError("Unsupported XOR pixel type"); | |
| 646 | + } | |
| 647 | + } | |
| 648 | +} | |
| 649 | + | |
| 650 | +class SetFillRectANY extends FillRect { | |
| 651 | + SetFillRectANY() { | |
| 652 | + super(SurfaceType.AnyColor, | |
| 653 | + CompositeType.SrcNoEa, | |
| 654 | + SurfaceType.Any); | |
| 655 | + } | |
| 656 | + | |
| 657 | + public void FillRect(SunGraphics2D sg2d, SurfaceData sData, | |
| 658 | + int x, int y, int w, int h) | |
| 659 | + { | |
| 660 | + PixelWriter pw = GeneralRenderer.createSolidPixelWriter(sg2d, sData); | |
| 661 | + | |
| 662 | + Region r = sg2d.getCompClip().getBoundsIntersectionXYWH(x, y, w, h); | |
| 663 | + | |
| 664 | + GeneralRenderer.doSetRect(sData, pw, | |
| 665 | + r.getLoX(), r.getLoY(), | |
| 666 | + r.getHiX(), r.getHiY()); | |
| 667 | + } | |
| 668 | +} | |
| 669 | + | |
| 670 | +class PixelWriterDrawHandler extends ProcessPath.DrawHandler { | |
| 671 | + PixelWriter pw; | |
| 672 | + SurfaceData sData; | |
| 673 | + Region clip; | |
| 674 | + | |
| 675 | + public PixelWriterDrawHandler(SurfaceData sData, PixelWriter pw, | |
| 676 | + Region clip, int strokeHint) { | |
| 677 | + super(clip.getLoX(), clip.getLoY(), | |
| 678 | + clip.getHiX(), clip.getHiY(), | |
| 679 | + strokeHint); | |
| 680 | + this.sData = sData; | |
| 681 | + this.pw = pw; | |
| 682 | + this.clip = clip; | |
| 683 | + } | |
| 684 | + | |
| 685 | + public void drawLine(int x0, int y0, int x1, int y1) { | |
| 686 | + GeneralRenderer.doDrawLine(sData, pw, null, clip, | |
| 687 | + x0, y0, x1, y1); | |
| 688 | + } | |
| 689 | + | |
| 690 | + public void drawPixel(int x0, int y0) { | |
| 691 | + GeneralRenderer.doSetRect(sData, pw, x0, y0, x0 + 1, y0 + 1); | |
| 692 | + } | |
| 693 | + | |
| 694 | + public void drawScanline(int x0, int x1, int y0) { | |
| 695 | + GeneralRenderer.doSetRect(sData, pw, x0, y0, x1 + 1, y0 + 1); | |
| 696 | + } | |
| 697 | +} | |
| 698 | + | |
| 699 | +class SetFillPathANY extends FillPath { | |
| 700 | + SetFillPathANY() { | |
| 701 | + super(SurfaceType.AnyColor, CompositeType.SrcNoEa, | |
| 702 | + SurfaceType.Any); | |
| 703 | + } | |
| 704 | + | |
| 705 | + public void FillPath(SunGraphics2D sg2d, SurfaceData sData, | |
| 706 | + int transx, int transy, | |
| 707 | + Path2D.Float p2df) | |
| 708 | + { | |
| 709 | + PixelWriter pw = GeneralRenderer.createSolidPixelWriter(sg2d, sData); | |
| 710 | + ProcessPath.fillPath( | |
| 711 | + new PixelWriterDrawHandler(sData, pw, sg2d.getCompClip(), | |
| 712 | + sg2d.strokeHint), | |
| 713 | + p2df, transx, transy); | |
| 714 | + } | |
| 715 | +} | |
| 716 | + | |
| 717 | +class SetFillSpansANY extends FillSpans { | |
| 718 | + SetFillSpansANY() { | |
| 719 | + super(SurfaceType.AnyColor, | |
| 720 | + CompositeType.SrcNoEa, | |
| 721 | + SurfaceType.Any); | |
| 722 | + } | |
| 723 | + | |
| 724 | + public void FillSpans(SunGraphics2D sg2d, SurfaceData sData, | |
| 725 | + SpanIterator si) | |
| 726 | + { | |
| 727 | + PixelWriter pw = GeneralRenderer.createSolidPixelWriter(sg2d, sData); | |
| 728 | + | |
| 729 | + int span[] = new int[4]; | |
| 730 | + while (si.nextSpan(span)) { | |
| 731 | + GeneralRenderer.doSetRect(sData, pw, | |
| 732 | + span[0], span[1], span[2], span[3]); | |
| 733 | + } | |
| 734 | + } | |
| 735 | +} | |
| 736 | + | |
| 737 | +class SetDrawLineANY extends DrawLine { | |
| 738 | + SetDrawLineANY() { | |
| 739 | + super(SurfaceType.AnyColor, | |
| 740 | + CompositeType.SrcNoEa, | |
| 741 | + SurfaceType.Any); | |
| 742 | + } | |
| 743 | + | |
| 744 | + public void DrawLine(SunGraphics2D sg2d, SurfaceData sData, | |
| 745 | + int x1, int y1, int x2, int y2) | |
| 746 | + { | |
| 747 | + PixelWriter pw = GeneralRenderer.createSolidPixelWriter(sg2d, sData); | |
| 748 | + | |
| 749 | + if (y1 >= y2) { | |
| 750 | + GeneralRenderer.doDrawLine(sData, pw, null, | |
| 751 | + sg2d.getCompClip(), | |
| 752 | + x2, y2, x1, y1); | |
| 753 | + } else { | |
| 754 | + GeneralRenderer.doDrawLine(sData, pw, null, | |
| 755 | + sg2d.getCompClip(), | |
| 756 | + x1, y1, x2, y2); | |
| 757 | + } | |
| 758 | + } | |
| 759 | +} | |
| 760 | + | |
| 761 | +class SetDrawPolygonsANY extends DrawPolygons { | |
| 762 | + SetDrawPolygonsANY() { | |
| 763 | + super(SurfaceType.AnyColor, | |
| 764 | + CompositeType.SrcNoEa, | |
| 765 | + SurfaceType.Any); | |
| 766 | + } | |
| 767 | + | |
| 768 | + public void DrawPolygons(SunGraphics2D sg2d, SurfaceData sData, | |
| 769 | + int xPoints[], int yPoints[], | |
| 770 | + int nPoints[], int numPolys, | |
| 771 | + int transx, int transy, | |
| 772 | + boolean close) | |
| 773 | + { | |
| 774 | + PixelWriter pw = GeneralRenderer.createSolidPixelWriter(sg2d, sData); | |
| 775 | + | |
| 776 | + int off = 0; | |
| 777 | + Region clip = sg2d.getCompClip(); | |
| 778 | + for (int i = 0; i < numPolys; i++) { | |
| 779 | + int numpts = nPoints[i]; | |
| 780 | + GeneralRenderer.doDrawPoly(sData, pw, | |
| 781 | + xPoints, yPoints, off, numpts, | |
| 782 | + clip, transx, transy, close); | |
| 783 | + off += numpts; | |
| 784 | + } | |
| 785 | + } | |
| 786 | +} | |
| 787 | + | |
| 788 | +class SetDrawPathANY extends DrawPath { | |
| 789 | + SetDrawPathANY() { | |
| 790 | + super(SurfaceType.AnyColor, | |
| 791 | + CompositeType.SrcNoEa, | |
| 792 | + SurfaceType.Any); | |
| 793 | + } | |
| 794 | + | |
| 795 | + public void DrawPath(SunGraphics2D sg2d, SurfaceData sData, | |
| 796 | + int transx, int transy, | |
| 797 | + Path2D.Float p2df) | |
| 798 | + { | |
| 799 | + PixelWriter pw = GeneralRenderer.createSolidPixelWriter(sg2d, sData); | |
| 800 | + ProcessPath.drawPath( | |
| 801 | + new PixelWriterDrawHandler(sData, pw, sg2d.getCompClip(), | |
| 802 | + sg2d.strokeHint), | |
| 803 | + p2df, transx, transy | |
| 804 | + ); | |
| 805 | + } | |
| 806 | +} | |
| 807 | + | |
| 808 | +class SetDrawRectANY extends DrawRect { | |
| 809 | + SetDrawRectANY() { | |
| 810 | + super(SurfaceType.AnyColor, | |
| 811 | + CompositeType.SrcNoEa, | |
| 812 | + SurfaceType.Any); | |
| 813 | + } | |
| 814 | + | |
| 815 | + public void DrawRect(SunGraphics2D sg2d, SurfaceData sData, | |
| 816 | + int x, int y, int w, int h) | |
| 817 | + { | |
| 818 | + PixelWriter pw = GeneralRenderer.createSolidPixelWriter(sg2d, sData); | |
| 819 | + | |
| 820 | + GeneralRenderer.doDrawRect(pw, sg2d, sData, x, y, w, h); | |
| 821 | + } | |
| 822 | +} | |
| 823 | + | |
| 824 | +class XorFillRectANY extends FillRect { | |
| 825 | + XorFillRectANY() { | |
| 826 | + super(SurfaceType.AnyColor, | |
| 827 | + CompositeType.Xor, | |
| 828 | + SurfaceType.Any); | |
| 829 | + } | |
| 830 | + | |
| 831 | + public void FillRect(SunGraphics2D sg2d, SurfaceData sData, | |
| 832 | + int x, int y, int w, int h) | |
| 833 | + { | |
| 834 | + PixelWriter pw = GeneralRenderer.createXorPixelWriter(sg2d, sData); | |
| 835 | + | |
| 836 | + Region r = sg2d.getCompClip().getBoundsIntersectionXYWH(x, y, w, h); | |
| 837 | + | |
| 838 | + GeneralRenderer.doSetRect(sData, pw, | |
| 839 | + r.getLoX(), r.getLoY(), | |
| 840 | + r.getHiX(), r.getHiY()); | |
| 841 | + } | |
| 842 | +} | |
| 843 | + | |
| 844 | +class XorFillPathANY extends FillPath { | |
| 845 | + XorFillPathANY() { | |
| 846 | + super(SurfaceType.AnyColor, CompositeType.Xor, | |
| 847 | + SurfaceType.Any); | |
| 848 | + } | |
| 849 | + | |
| 850 | + public void FillPath(SunGraphics2D sg2d, SurfaceData sData, | |
| 851 | + int transx, int transy, | |
| 852 | + Path2D.Float p2df) | |
| 853 | + { | |
| 854 | + PixelWriter pw = GeneralRenderer.createXorPixelWriter(sg2d, sData); | |
| 855 | + ProcessPath.fillPath( | |
| 856 | + new PixelWriterDrawHandler(sData, pw, sg2d.getCompClip(), | |
| 857 | + sg2d.strokeHint), | |
| 858 | + p2df, transx, transy); | |
| 859 | + } | |
| 860 | +} | |
| 861 | + | |
| 862 | +class XorFillSpansANY extends FillSpans { | |
| 863 | + XorFillSpansANY() { | |
| 864 | + super(SurfaceType.AnyColor, | |
| 865 | + CompositeType.Xor, | |
| 866 | + SurfaceType.Any); | |
| 867 | + } | |
| 868 | + | |
| 869 | + public void FillSpans(SunGraphics2D sg2d, SurfaceData sData, | |
| 870 | + SpanIterator si) | |
| 871 | + { | |
| 872 | + PixelWriter pw = GeneralRenderer.createXorPixelWriter(sg2d, sData); | |
| 873 | + | |
| 874 | + int span[] = new int[4]; | |
| 875 | + while (si.nextSpan(span)) { | |
| 876 | + GeneralRenderer.doSetRect(sData, pw, | |
| 877 | + span[0], span[1], span[2], span[3]); | |
| 878 | + } | |
| 879 | + } | |
| 880 | +} | |
| 881 | + | |
| 882 | +class XorDrawLineANY extends DrawLine { | |
| 883 | + XorDrawLineANY() { | |
| 884 | + super(SurfaceType.AnyColor, | |
| 885 | + CompositeType.Xor, | |
| 886 | + SurfaceType.Any); | |
| 887 | + } | |
| 888 | + | |
| 889 | + public void DrawLine(SunGraphics2D sg2d, SurfaceData sData, | |
| 890 | + int x1, int y1, int x2, int y2) | |
| 891 | + { | |
| 892 | + PixelWriter pw = GeneralRenderer.createXorPixelWriter(sg2d, sData); | |
| 893 | + | |
| 894 | + if (y1 >= y2) { | |
| 895 | + GeneralRenderer.doDrawLine(sData, pw, null, | |
| 896 | + sg2d.getCompClip(), | |
| 897 | + x2, y2, x1, y1); | |
| 898 | + } else { | |
| 899 | + GeneralRenderer.doDrawLine(sData, pw, null, | |
| 900 | + sg2d.getCompClip(), | |
| 901 | + x1, y1, x2, y2); | |
| 902 | + } | |
| 903 | + } | |
| 904 | +} | |
| 905 | + | |
| 906 | +class XorDrawPolygonsANY extends DrawPolygons { | |
| 907 | + XorDrawPolygonsANY() { | |
| 908 | + super(SurfaceType.AnyColor, | |
| 909 | + CompositeType.Xor, | |
| 910 | + SurfaceType.Any); | |
| 911 | + } | |
| 912 | + | |
| 913 | + public void DrawPolygons(SunGraphics2D sg2d, SurfaceData sData, | |
| 914 | + int xPoints[], int yPoints[], | |
| 915 | + int nPoints[], int numPolys, | |
| 916 | + int transx, int transy, | |
| 917 | + boolean close) | |
| 918 | + { | |
| 919 | + PixelWriter pw = GeneralRenderer.createXorPixelWriter(sg2d, sData); | |
| 920 | + | |
| 921 | + int off = 0; | |
| 922 | + Region clip = sg2d.getCompClip(); | |
| 923 | + for (int i = 0; i < numPolys; i++) { | |
| 924 | + int numpts = nPoints[i]; | |
| 925 | + GeneralRenderer.doDrawPoly(sData, pw, | |
| 926 | + xPoints, yPoints, off, numpts, | |
| 927 | + clip, transx, transy, close); | |
| 928 | + off += numpts; | |
| 929 | + } | |
| 930 | + } | |
| 931 | +} | |
| 932 | + | |
| 933 | +class XorDrawPathANY extends DrawPath { | |
| 934 | + XorDrawPathANY() { | |
| 935 | + super(SurfaceType.AnyColor, | |
| 936 | + CompositeType.Xor, | |
| 937 | + SurfaceType.Any); | |
| 938 | + } | |
| 939 | + | |
| 940 | + public void DrawPath(SunGraphics2D sg2d, SurfaceData sData, | |
| 941 | + int transx, int transy, Path2D.Float p2df) | |
| 942 | + { | |
| 943 | + PixelWriter pw = GeneralRenderer.createXorPixelWriter(sg2d, sData); | |
| 944 | + ProcessPath.drawPath( | |
| 945 | + new PixelWriterDrawHandler(sData, pw, sg2d.getCompClip(), | |
| 946 | + sg2d.strokeHint), | |
| 947 | + p2df, transx, transy | |
| 948 | + ); | |
| 949 | + } | |
| 950 | +} | |
| 951 | + | |
| 952 | +class XorDrawRectANY extends DrawRect { | |
| 953 | + XorDrawRectANY() { | |
| 954 | + super(SurfaceType.AnyColor, | |
| 955 | + CompositeType.Xor, | |
| 956 | + SurfaceType.Any); | |
| 957 | + } | |
| 958 | + | |
| 959 | + public void DrawRect(SunGraphics2D sg2d, SurfaceData sData, | |
| 960 | + int x, int y, int w, int h) | |
| 961 | + { | |
| 962 | + PixelWriter pw = GeneralRenderer.createXorPixelWriter(sg2d, sData); | |
| 963 | + | |
| 964 | + GeneralRenderer.doDrawRect(pw, sg2d, sData, x, y, w, h); | |
| 965 | + } | |
| 966 | +} | |
| 967 | + | |
| 968 | +class XorDrawGlyphListANY extends DrawGlyphList { | |
| 969 | + XorDrawGlyphListANY() { | |
| 970 | + super(SurfaceType.AnyColor, | |
| 971 | + CompositeType.Xor, | |
| 972 | + SurfaceType.Any); | |
| 973 | + } | |
| 974 | + | |
| 975 | + public void DrawGlyphList(SunGraphics2D sg2d, SurfaceData sData, | |
| 976 | + GlyphList gl) | |
| 977 | + { | |
| 978 | + PixelWriter pw = GeneralRenderer.createXorPixelWriter(sg2d, sData); | |
| 979 | + GeneralRenderer.doDrawGlyphList(sData, pw, gl, sg2d.getCompClip()); | |
| 980 | + } | |
| 981 | +} | |
| 982 | + | |
| 983 | +class XorDrawGlyphListAAANY extends DrawGlyphListAA { | |
| 984 | + XorDrawGlyphListAAANY() { | |
| 985 | + super(SurfaceType.AnyColor, | |
| 986 | + CompositeType.Xor, | |
| 987 | + SurfaceType.Any); | |
| 988 | + } | |
| 989 | + | |
| 990 | + public void DrawGlyphListAA(SunGraphics2D sg2d, SurfaceData sData, | |
| 991 | + GlyphList gl) | |
| 992 | + { | |
| 993 | + PixelWriter pw = GeneralRenderer.createXorPixelWriter(sg2d, sData); | |
| 994 | + GeneralRenderer.doDrawGlyphList(sData, pw, gl, sg2d.getCompClip()); | |
| 995 | + } | |
| 996 | +} | |
| 997 | + | |
| 998 | +abstract class PixelWriter { | |
| 999 | + protected WritableRaster dstRast; | |
| 1000 | + | |
| 1001 | + public void setRaster(WritableRaster dstRast) { | |
| 1002 | + this.dstRast = dstRast; | |
| 1003 | + } | |
| 1004 | + | |
| 1005 | + public abstract void writePixel(int x, int y); | |
| 1006 | +} | |
| 1007 | + | |
| 1008 | +class SolidPixelWriter extends PixelWriter { | |
| 1009 | + protected Object srcData; | |
| 1010 | + | |
| 1011 | + SolidPixelWriter(Object srcPixel) { | |
| 1012 | + this.srcData = srcPixel; | |
| 1013 | + } | |
| 1014 | + | |
| 1015 | + public void writePixel(int x, int y) { | |
| 1016 | + dstRast.setDataElements(x, y, srcData); | |
| 1017 | + } | |
| 1018 | +} | |
| 1019 | + | |
| 1020 | +abstract class XorPixelWriter extends PixelWriter { | |
| 1021 | + protected ColorModel dstCM; | |
| 1022 | + | |
| 1023 | + public void writePixel(int x, int y) { | |
| 1024 | + Object dstPixel = dstRast.getDataElements(x, y, null); | |
| 1025 | + xorPixel(dstPixel); | |
| 1026 | + dstRast.setDataElements(x, y, dstPixel); | |
| 1027 | + } | |
| 1028 | + | |
| 1029 | + protected abstract void xorPixel(Object pixData); | |
| 1030 | + | |
| 1031 | + public static class ByteData extends XorPixelWriter { | |
| 1032 | + byte[] xorData; | |
| 1033 | + | |
| 1034 | + ByteData(Object srcPixel, Object xorPixel) { | |
| 1035 | + this.xorData = (byte[]) srcPixel; | |
| 1036 | + xorPixel(xorPixel); | |
| 1037 | + this.xorData = (byte[]) xorPixel; | |
| 1038 | + } | |
| 1039 | + | |
| 1040 | + protected void xorPixel(Object pixData) { | |
| 1041 | + byte[] dstData = (byte[]) pixData; | |
| 1042 | + for (int i = 0; i < dstData.length; i++) { | |
| 1043 | + dstData[i] ^= xorData[i]; | |
| 1044 | + } | |
| 1045 | + } | |
| 1046 | + } | |
| 1047 | + | |
| 1048 | + public static class ShortData extends XorPixelWriter { | |
| 1049 | + short[] xorData; | |
| 1050 | + | |
| 1051 | + ShortData(Object srcPixel, Object xorPixel) { | |
| 1052 | + this.xorData = (short[]) srcPixel; | |
| 1053 | + xorPixel(xorPixel); | |
| 1054 | + this.xorData = (short[]) xorPixel; | |
| 1055 | + } | |
| 1056 | + | |
| 1057 | + protected void xorPixel(Object pixData) { | |
| 1058 | + short[] dstData = (short[]) pixData; | |
| 1059 | + for (int i = 0; i < dstData.length; i++) { | |
| 1060 | + dstData[i] ^= xorData[i]; | |
| 1061 | + } | |
| 1062 | + } | |
| 1063 | + } | |
| 1064 | + | |
| 1065 | + public static class IntData extends XorPixelWriter { | |
| 1066 | + int[] xorData; | |
| 1067 | + | |
| 1068 | + IntData(Object srcPixel, Object xorPixel) { | |
| 1069 | + this.xorData = (int[]) srcPixel; | |
| 1070 | + xorPixel(xorPixel); | |
| 1071 | + this.xorData = (int[]) xorPixel; | |
| 1072 | + } | |
| 1073 | + | |
| 1074 | + protected void xorPixel(Object pixData) { | |
| 1075 | + int[] dstData = (int[]) pixData; | |
| 1076 | + for (int i = 0; i < dstData.length; i++) { | |
| 1077 | + dstData[i] ^= xorData[i]; | |
| 1078 | + } | |
| 1079 | + } | |
| 1080 | + } | |
| 1081 | + | |
| 1082 | + public static class FloatData extends XorPixelWriter { | |
| 1083 | + int[] xorData; | |
| 1084 | + | |
| 1085 | + FloatData(Object srcPixel, Object xorPixel) { | |
| 1086 | + float[] srcData = (float[]) srcPixel; | |
| 1087 | + float[] xorData = (float[]) xorPixel; | |
| 1088 | + this.xorData = new int[srcData.length]; | |
| 1089 | + for (int i = 0; i < srcData.length; i++) { | |
| 1090 | + this.xorData[i] = (Float.floatToIntBits(srcData[i]) ^ | |
| 1091 | + Float.floatToIntBits(xorData[i])); | |
| 1092 | + } | |
| 1093 | + } | |
| 1094 | + | |
| 1095 | + protected void xorPixel(Object pixData) { | |
| 1096 | + float[] dstData = (float[]) pixData; | |
| 1097 | + for (int i = 0; i < dstData.length; i++) { | |
| 1098 | + int v = Float.floatToIntBits(dstData[i]) ^ xorData[i]; | |
| 1099 | + dstData[i] = Float.intBitsToFloat(v); | |
| 1100 | + } | |
| 1101 | + } | |
| 1102 | + } | |
| 1103 | + | |
| 1104 | + public static class DoubleData extends XorPixelWriter { | |
| 1105 | + long[] xorData; | |
| 1106 | + | |
| 1107 | + DoubleData(Object srcPixel, Object xorPixel) { | |
| 1108 | + double[] srcData = (double[]) srcPixel; | |
| 1109 | + double[] xorData = (double[]) xorPixel; | |
| 1110 | + this.xorData = new long[srcData.length]; | |
| 1111 | + for (int i = 0; i < srcData.length; i++) { | |
| 1112 | + this.xorData[i] = (Double.doubleToLongBits(srcData[i]) ^ | |
| 1113 | + Double.doubleToLongBits(xorData[i])); | |
| 1114 | + } | |
| 1115 | + } | |
| 1116 | + | |
| 1117 | + protected void xorPixel(Object pixData) { | |
| 1118 | + double[] dstData = (double[]) pixData; | |
| 1119 | + for (int i = 0; i < dstData.length; i++) { | |
| 1120 | + long v = Double.doubleToLongBits(dstData[i]) ^ xorData[i]; | |
| 1121 | + dstData[i] = Double.longBitsToDouble(v); | |
| 1122 | + } | |
| 1123 | + } | |
| 1124 | + } | |
| 1125 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,623 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +/* | |
| 27 | + * @author Charlton Innovations, Inc. | |
| 28 | + */ | |
| 29 | + | |
| 30 | +package sun.java2d.loops; | |
| 31 | + | |
| 32 | +import java.awt.image.BufferedImage; | |
| 33 | +import java.awt.AlphaComposite; | |
| 34 | +import java.awt.Rectangle; | |
| 35 | +import sun.awt.image.BufImgSurfaceData; | |
| 36 | +import sun.java2d.SurfaceData; | |
| 37 | +import sun.java2d.pipe.Region; | |
| 38 | +import java.lang.reflect.Field; | |
| 39 | +import java.util.StringTokenizer; | |
| 40 | +import java.util.Iterator; | |
| 41 | +import java.util.HashMap; | |
| 42 | +import java.util.Map; | |
| 43 | +import java.io.PrintStream; | |
| 44 | +import java.io.OutputStream; | |
| 45 | +import java.io.FileOutputStream; | |
| 46 | +import java.io.FileNotFoundException; | |
| 47 | +import java.security.AccessController; | |
| 48 | +import java.security.PrivilegedAction; | |
| 49 | +import sun.security.action.GetPropertyAction; | |
| 50 | + | |
| 51 | +/** | |
| 52 | + * defines interface for primitives which can be placed into | |
| 53 | + * the graphic component manager framework | |
| 54 | + */ | |
| 55 | +public abstract class GraphicsPrimitive { | |
| 56 | + | |
| 57 | + protected static interface GeneralBinaryOp { | |
| 58 | + /** | |
| 59 | + * This method allows the setupGeneralBinaryOp method to set | |
| 60 | + * the converters into the General version of the Primitive. | |
| 61 | + */ | |
| 62 | + public void setPrimitives(Blit srcconverter, | |
| 63 | + Blit dstconverter, | |
| 64 | + GraphicsPrimitive genericop, | |
| 65 | + Blit resconverter); | |
| 66 | + | |
| 67 | + /** | |
| 68 | + * These 4 methods are implemented automatically for any | |
| 69 | + * GraphicsPrimitive. They are used by setupGeneralBinaryOp | |
| 70 | + * to retrieve the information needed to find the right | |
| 71 | + * converter primitives. | |
| 72 | + */ | |
| 73 | + public SurfaceType getSourceType(); | |
| 74 | + public CompositeType getCompositeType(); | |
| 75 | + public SurfaceType getDestType(); | |
| 76 | + public String getSignature(); | |
| 77 | + public int getPrimTypeID(); | |
| 78 | + } | |
| 79 | + | |
| 80 | + protected static interface GeneralUnaryOp { | |
| 81 | + /** | |
| 82 | + * This method allows the setupGeneralUnaryOp method to set | |
| 83 | + * the converters into the General version of the Primitive. | |
| 84 | + */ | |
| 85 | + public void setPrimitives(Blit dstconverter, | |
| 86 | + GraphicsPrimitive genericop, | |
| 87 | + Blit resconverter); | |
| 88 | + | |
| 89 | + /** | |
| 90 | + * These 3 methods are implemented automatically for any | |
| 91 | + * GraphicsPrimitive. They are used by setupGeneralUnaryOp | |
| 92 | + * to retrieve the information needed to find the right | |
| 93 | + * converter primitives. | |
| 94 | + */ | |
| 95 | + public CompositeType getCompositeType(); | |
| 96 | + public SurfaceType getDestType(); | |
| 97 | + public String getSignature(); | |
| 98 | + public int getPrimTypeID(); | |
| 99 | + } | |
| 100 | + | |
| 101 | + /** | |
| 102 | + * INSTANCE DATA MEMBERS DESCRIBING CHARACTERISTICS OF THIS PRIMITIVE | |
| 103 | + **/ | |
| 104 | + | |
| 105 | + // Making these be instance data members (instead of virtual methods | |
| 106 | + // overridden by subclasses) is actually cheaper, since each class | |
| 107 | + // is a singleton. As instance data members with final accessors, | |
| 108 | + // accesses can be inlined. | |
| 109 | + private String methodSignature; | |
| 110 | + private int uniqueID; | |
| 111 | + private static int unusedPrimID = 1; | |
| 112 | + | |
| 113 | + private SurfaceType sourceType; | |
| 114 | + private CompositeType compositeType; | |
| 115 | + private SurfaceType destType; | |
| 116 | + | |
| 117 | + private long pNativePrim; // Native blit loop info | |
| 118 | + | |
| 119 | + public synchronized static final int makePrimTypeID() { | |
| 120 | + if (unusedPrimID > 255) { | |
| 121 | + throw new InternalError("primitive id overflow"); | |
| 122 | + } | |
| 123 | + return unusedPrimID++; | |
| 124 | + } | |
| 125 | + | |
| 126 | + public synchronized static final int makeUniqueID(int primTypeID, | |
| 127 | + SurfaceType src, | |
| 128 | + CompositeType cmp, | |
| 129 | + SurfaceType dst) | |
| 130 | + { | |
| 131 | + return (primTypeID << 24) | | |
| 132 | + (dst.getUniqueID() << 16) | | |
| 133 | + (cmp.getUniqueID() << 8) | | |
| 134 | + (src.getUniqueID()); | |
| 135 | + } | |
| 136 | + | |
| 137 | + /** | |
| 138 | + * Create a new GraphicsPrimitive with all of the required | |
| 139 | + * descriptive information. | |
| 140 | + */ | |
| 141 | + protected GraphicsPrimitive(String methodSignature, | |
| 142 | + int primTypeID, | |
| 143 | + SurfaceType sourceType, | |
| 144 | + CompositeType compositeType, | |
| 145 | + SurfaceType destType) | |
| 146 | + { | |
| 147 | + this.methodSignature = methodSignature; | |
| 148 | + this.sourceType = sourceType; | |
| 149 | + this.compositeType = compositeType; | |
| 150 | + this.destType = destType; | |
| 151 | + | |
| 152 | + if(sourceType == null || compositeType == null || destType == null) { | |
| 153 | + this.uniqueID = primTypeID << 24; | |
| 154 | + } else { | |
| 155 | + this.uniqueID = GraphicsPrimitive.makeUniqueID(primTypeID, | |
| 156 | + sourceType, | |
| 157 | + compositeType, | |
| 158 | + destType); | |
| 159 | + } | |
| 160 | + } | |
| 161 | + | |
| 162 | + /** | |
| 163 | + * Create a new GraphicsPrimitive for native invocation | |
| 164 | + * with all of the required descriptive information. | |
| 165 | + */ | |
| 166 | + protected GraphicsPrimitive(long pNativePrim, | |
| 167 | + String methodSignature, | |
| 168 | + int primTypeID, | |
| 169 | + SurfaceType sourceType, | |
| 170 | + CompositeType compositeType, | |
| 171 | + SurfaceType destType) | |
| 172 | + { | |
| 173 | + this.pNativePrim = pNativePrim; | |
| 174 | + this.methodSignature = methodSignature; | |
| 175 | + this.sourceType = sourceType; | |
| 176 | + this.compositeType = compositeType; | |
| 177 | + this.destType = destType; | |
| 178 | + | |
| 179 | + if(sourceType == null || compositeType == null || destType == null) { | |
| 180 | + this.uniqueID = primTypeID << 24; | |
| 181 | + } else { | |
| 182 | + this.uniqueID = GraphicsPrimitive.makeUniqueID(primTypeID, | |
| 183 | + sourceType, | |
| 184 | + compositeType, | |
| 185 | + destType); | |
| 186 | + } | |
| 187 | + } | |
| 188 | + | |
| 189 | + /** | |
| 190 | + * METHODS TO DESCRIBE THE SURFACES PRIMITIVES | |
| 191 | + * CAN OPERATE ON AND THE FUNCTIONALITY THEY IMPLEMENT | |
| 192 | + **/ | |
| 193 | + | |
| 194 | + /** | |
| 195 | + * Gets instance ID of this graphics primitive. | |
| 196 | + * | |
| 197 | + * Instance ID is comprised of four distinct ids (ORed together) | |
| 198 | + * that uniquely identify each instance of a GraphicsPrimitive | |
| 199 | + * object. The four ids making up instance ID are: | |
| 200 | + * 1. primitive id - identifier shared by all primitives of the | |
| 201 | + * same type (eg. all Blits have the same primitive id) | |
| 202 | + * 2. sourcetype id - identifies source surface type | |
| 203 | + * 3. desttype id - identifies destination surface type | |
| 204 | + * 4. compositetype id - identifies composite used | |
| 205 | + * | |
| 206 | + * @return instance ID | |
| 207 | + */ | |
| 208 | + public final int getUniqueID() { | |
| 209 | + return uniqueID; | |
| 210 | + } | |
| 211 | + | |
| 212 | + /** | |
| 213 | + */ | |
| 214 | + public final String getSignature() { | |
| 215 | + return methodSignature; | |
| 216 | + } | |
| 217 | + | |
| 218 | + /** | |
| 219 | + * Gets unique id for this GraphicsPrimitive type. | |
| 220 | + * | |
| 221 | + * This id is used to identify the TYPE of primitive (Blit vs. BlitBg) | |
| 222 | + * as opposed to INSTANCE of primitive. | |
| 223 | + * | |
| 224 | + * @return primitive ID | |
| 225 | + */ | |
| 226 | + public final int getPrimTypeID() { | |
| 227 | + return uniqueID >>> 24; | |
| 228 | + } | |
| 229 | + | |
| 230 | + /** | |
| 231 | + */ | |
| 232 | + public final long getNativePrim() { | |
| 233 | + return pNativePrim; | |
| 234 | + } | |
| 235 | + | |
| 236 | + /** | |
| 237 | + */ | |
| 238 | + public final SurfaceType getSourceType() { | |
| 239 | + return sourceType; | |
| 240 | + } | |
| 241 | + | |
| 242 | + /** | |
| 243 | + */ | |
| 244 | + public final CompositeType getCompositeType() { | |
| 245 | + return compositeType; | |
| 246 | + } | |
| 247 | + | |
| 248 | + /** | |
| 249 | + */ | |
| 250 | + public final SurfaceType getDestType() { | |
| 251 | + return destType; | |
| 252 | + } | |
| 253 | + | |
| 254 | + /** | |
| 255 | + * Return true if this primitive can be used for the given signature | |
| 256 | + * surfaces, and composite. | |
| 257 | + * | |
| 258 | + * @param signature The signature of the given operation. Must be | |
| 259 | + * == (not just .equals) the signature string given by the | |
| 260 | + * abstract class that declares the operation. | |
| 261 | + * @param srctype The surface type for the source of the operation | |
| 262 | + * @param comptype The composite type for the operation | |
| 263 | + * @param dsttype The surface type for the destination of the operation | |
| 264 | + */ | |
| 265 | + public final boolean satisfies(String signature, | |
| 266 | + SurfaceType srctype, | |
| 267 | + CompositeType comptype, | |
| 268 | + SurfaceType dsttype) | |
| 269 | + { | |
| 270 | + if (signature != methodSignature) { | |
| 271 | + return false; | |
| 272 | + } | |
| 273 | + while (true) { | |
| 274 | + if (srctype == null) { | |
| 275 | + return false; | |
| 276 | + } | |
| 277 | + if (srctype.equals(sourceType)) { | |
| 278 | + break; | |
| 279 | + } | |
| 280 | + srctype = srctype.getSuperType(); | |
| 281 | + } | |
| 282 | + while (true) { | |
| 283 | + if (comptype == null) { | |
| 284 | + return false; | |
| 285 | + } | |
| 286 | + if (comptype.equals(compositeType)) { | |
| 287 | + break; | |
| 288 | + } | |
| 289 | + comptype = comptype.getSuperType(); | |
| 290 | + } | |
| 291 | + while (true) { | |
| 292 | + if (dsttype == null) { | |
| 293 | + return false; | |
| 294 | + } | |
| 295 | + if (dsttype.equals(destType)) { | |
| 296 | + break; | |
| 297 | + } | |
| 298 | + dsttype = dsttype.getSuperType(); | |
| 299 | + } | |
| 300 | + return true; | |
| 301 | + } | |
| 302 | + | |
| 303 | + // | |
| 304 | + // A version of satisfies used for regression testing | |
| 305 | + // | |
| 306 | + final boolean satisfiesSameAs(GraphicsPrimitive other) { | |
| 307 | + return (methodSignature == other.methodSignature && | |
| 308 | + sourceType.equals(other.sourceType) && | |
| 309 | + compositeType.equals(other.compositeType) && | |
| 310 | + destType.equals(other.destType)); | |
| 311 | + } | |
| 312 | + | |
| 313 | + public abstract GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 314 | + CompositeType comptype, | |
| 315 | + SurfaceType dsttype); | |
| 316 | + | |
| 317 | + public abstract GraphicsPrimitive traceWrap(); | |
| 318 | + | |
| 319 | + static HashMap traceMap; | |
| 320 | + | |
| 321 | + public static int traceflags; | |
| 322 | + public static String tracefile; | |
| 323 | + public static PrintStream traceout; | |
| 324 | + | |
| 325 | + public static final int TRACELOG = 1; | |
| 326 | + public static final int TRACETIMESTAMP = 2; | |
| 327 | + public static final int TRACECOUNTS = 4; | |
| 328 | + | |
| 329 | + static { | |
| 330 | + GetPropertyAction gpa = new GetPropertyAction("sun.java2d.trace"); | |
| 331 | + String trace = (String)AccessController.doPrivileged(gpa); | |
| 332 | + if (trace != null) { | |
| 333 | + boolean verbose = false; | |
| 334 | + int traceflags = 0; | |
| 335 | + StringTokenizer st = new StringTokenizer(trace, ","); | |
| 336 | + while (st.hasMoreTokens()) { | |
| 337 | + String tok = st.nextToken(); | |
| 338 | + if (tok.equalsIgnoreCase("count")) { | |
| 339 | + traceflags |= GraphicsPrimitive.TRACECOUNTS; | |
| 340 | + } else if (tok.equalsIgnoreCase("log")) { | |
| 341 | + traceflags |= GraphicsPrimitive.TRACELOG; | |
| 342 | + } else if (tok.equalsIgnoreCase("timestamp")) { | |
| 343 | + traceflags |= GraphicsPrimitive.TRACETIMESTAMP; | |
| 344 | + } else if (tok.equalsIgnoreCase("verbose")) { | |
| 345 | + verbose = true; | |
| 346 | + } else if (tok.regionMatches(true, 0, "out:", 0, 4)) { | |
| 347 | + tracefile = tok.substring(4); | |
| 348 | + } else { | |
| 349 | + if (!tok.equalsIgnoreCase("help")) { | |
| 350 | + System.err.println("unrecognized token: "+tok); | |
| 351 | + } | |
| 352 | + System.err.println("usage: -Dsun.java2d.trace="+ | |
| 353 | + "[log[,timestamp]],[count],"+ | |
| 354 | + "[out:<filename>],[help],[verbose]"); | |
| 355 | + } | |
| 356 | + } | |
| 357 | + if (verbose) { | |
| 358 | + System.err.print("GraphicsPrimitive logging "); | |
| 359 | + if ((traceflags & GraphicsPrimitive.TRACELOG) != 0) { | |
| 360 | + System.err.println("enabled"); | |
| 361 | + System.err.print("GraphicsPrimitive timetamps "); | |
| 362 | + if ((traceflags & GraphicsPrimitive.TRACETIMESTAMP) != 0) { | |
| 363 | + System.err.println("enabled"); | |
| 364 | + } else { | |
| 365 | + System.err.println("disabled"); | |
| 366 | + } | |
| 367 | + } else { | |
| 368 | + System.err.println("[and timestamps] disabled"); | |
| 369 | + } | |
| 370 | + System.err.print("GraphicsPrimitive invocation counts "); | |
| 371 | + if ((traceflags & GraphicsPrimitive.TRACECOUNTS) != 0) { | |
| 372 | + System.err.println("enabled"); | |
| 373 | + } else { | |
| 374 | + System.err.println("disabled"); | |
| 375 | + } | |
| 376 | + System.err.print("GraphicsPrimitive trace output to "); | |
| 377 | + if (tracefile == null) { | |
| 378 | + System.err.println("System.err"); | |
| 379 | + } else { | |
| 380 | + System.err.println("file '"+tracefile+"'"); | |
| 381 | + } | |
| 382 | + } | |
| 383 | + GraphicsPrimitive.traceflags = traceflags; | |
| 384 | + } | |
| 385 | + } | |
| 386 | + | |
| 387 | + public static boolean tracingEnabled() { | |
| 388 | + return (traceflags != 0); | |
| 389 | + } | |
| 390 | + | |
| 391 | + private static PrintStream getTraceOutputFile() { | |
| 392 | + if (traceout == null) { | |
| 393 | + if (tracefile != null) { | |
| 394 | + Object o = | |
| 395 | + AccessController.doPrivileged(new PrivilegedAction() { | |
| 396 | + public Object run() { | |
| 397 | + try { | |
| 398 | + return new FileOutputStream(tracefile); | |
| 399 | + } catch (FileNotFoundException e) { | |
| 400 | + return null; | |
| 401 | + } | |
| 402 | + } | |
| 403 | + }); | |
| 404 | + if (o != null) { | |
| 405 | + traceout = new PrintStream((OutputStream) o); | |
| 406 | + } else { | |
| 407 | + traceout = System.err; | |
| 408 | + } | |
| 409 | + } else { | |
| 410 | + traceout = System.err; | |
| 411 | + } | |
| 412 | + } | |
| 413 | + return traceout; | |
| 414 | + } | |
| 415 | + | |
| 416 | + public static class TraceReporter extends Thread { | |
| 417 | + public static void setShutdownHook() { | |
| 418 | + AccessController.doPrivileged(new PrivilegedAction() { | |
| 419 | + public Object run() { | |
| 420 | + TraceReporter t = new TraceReporter(); | |
| 421 | + t.setContextClassLoader(null); | |
| 422 | + Runtime.getRuntime().addShutdownHook(t); | |
| 423 | + return null; | |
| 424 | + } | |
| 425 | + }); | |
| 426 | + } | |
| 427 | + | |
| 428 | + public void run() { | |
| 429 | + PrintStream ps = getTraceOutputFile(); | |
| 430 | + Iterator iterator = traceMap.entrySet().iterator(); | |
| 431 | + long total = 0; | |
| 432 | + int numprims = 0; | |
| 433 | + while (iterator.hasNext()) { | |
| 434 | + Map.Entry me = (Map.Entry) iterator.next(); | |
| 435 | + Object prim = me.getKey(); | |
| 436 | + int[] count = (int[]) me.getValue(); | |
| 437 | + if (count[0] == 1) { | |
| 438 | + ps.print("1 call to "); | |
| 439 | + } else { | |
| 440 | + ps.print(count[0]+" calls to "); | |
| 441 | + } | |
| 442 | + ps.println(prim); | |
| 443 | + numprims++; | |
| 444 | + total += count[0]; | |
| 445 | + } | |
| 446 | + if (numprims == 0) { | |
| 447 | + ps.println("No graphics primitives executed"); | |
| 448 | + } else if (numprims > 1) { | |
| 449 | + ps.println(total+" total calls to "+ | |
| 450 | + numprims+" different primitives"); | |
| 451 | + } | |
| 452 | + } | |
| 453 | + } | |
| 454 | + | |
| 455 | + public synchronized static void tracePrimitive(Object prim) { | |
| 456 | + if ((traceflags & TRACECOUNTS) != 0) { | |
| 457 | + if (traceMap == null) { | |
| 458 | + traceMap = new HashMap(); | |
| 459 | + TraceReporter.setShutdownHook(); | |
| 460 | + } | |
| 461 | + Object o = traceMap.get(prim); | |
| 462 | + if (o == null) { | |
| 463 | + o = new int[1]; | |
| 464 | + traceMap.put(prim, o); | |
| 465 | + } | |
| 466 | + ((int[]) o)[0]++; | |
| 467 | + } | |
| 468 | + if ((traceflags & TRACELOG) != 0) { | |
| 469 | + PrintStream ps = getTraceOutputFile(); | |
| 470 | + if ((traceflags & TRACETIMESTAMP) != 0) { | |
| 471 | + ps.print(System.currentTimeMillis()+": "); | |
| 472 | + } | |
| 473 | + ps.println(prim); | |
| 474 | + } | |
| 475 | + } | |
| 476 | + | |
| 477 | + protected void setupGeneralBinaryOp(GeneralBinaryOp gbo) { | |
| 478 | + int primID = gbo.getPrimTypeID(); | |
| 479 | + String methodSignature = gbo.getSignature(); | |
| 480 | + SurfaceType srctype = gbo.getSourceType(); | |
| 481 | + CompositeType comptype = gbo.getCompositeType(); | |
| 482 | + SurfaceType dsttype = gbo.getDestType(); | |
| 483 | + Blit convertsrc, convertdst, convertres; | |
| 484 | + GraphicsPrimitive performop; | |
| 485 | + | |
| 486 | + convertsrc = createConverter(srctype, SurfaceType.IntArgb); | |
| 487 | + performop = GraphicsPrimitiveMgr.locatePrim(primID, | |
| 488 | + SurfaceType.IntArgb, | |
| 489 | + comptype, dsttype); | |
| 490 | + if (performop != null) { | |
| 491 | + convertdst = null; | |
| 492 | + convertres = null; | |
| 493 | + } else { | |
| 494 | + performop = getGeneralOp(primID, comptype); | |
| 495 | + if (performop == null) { | |
| 496 | + throw new InternalError("Cannot construct general op for "+ | |
| 497 | + methodSignature+" "+comptype); | |
| 498 | + } | |
| 499 | + convertdst = createConverter(dsttype, SurfaceType.IntArgb); | |
| 500 | + convertres = createConverter(SurfaceType.IntArgb, dsttype); | |
| 501 | + } | |
| 502 | + | |
| 503 | + gbo.setPrimitives(convertsrc, convertdst, performop, convertres); | |
| 504 | + } | |
| 505 | + | |
| 506 | + protected void setupGeneralUnaryOp(GeneralUnaryOp guo) { | |
| 507 | + int primID = guo.getPrimTypeID(); | |
| 508 | + String methodSignature = guo.getSignature(); | |
| 509 | + CompositeType comptype = guo.getCompositeType(); | |
| 510 | + SurfaceType dsttype = guo.getDestType(); | |
| 511 | + | |
| 512 | + Blit convertdst = createConverter(dsttype, SurfaceType.IntArgb); | |
| 513 | + GraphicsPrimitive performop = getGeneralOp(primID, comptype); | |
| 514 | + Blit convertres = createConverter(SurfaceType.IntArgb, dsttype); | |
| 515 | + if (convertdst == null || performop == null || convertres == null) { | |
| 516 | + throw new InternalError("Cannot construct binary op for "+ | |
| 517 | + comptype+" "+dsttype); | |
| 518 | + } | |
| 519 | + | |
| 520 | + guo.setPrimitives(convertdst, performop, convertres); | |
| 521 | + } | |
| 522 | + | |
| 523 | + protected static Blit createConverter(SurfaceType srctype, | |
| 524 | + SurfaceType dsttype) | |
| 525 | + { | |
| 526 | + if (srctype.equals(dsttype)) { | |
| 527 | + return null; | |
| 528 | + } | |
| 529 | + Blit cv = Blit.getFromCache(srctype, CompositeType.SrcNoEa, dsttype); | |
| 530 | + if (cv == null) { | |
| 531 | + throw new InternalError("Cannot construct converter for "+ | |
| 532 | + srctype+"=>"+dsttype); | |
| 533 | + } | |
| 534 | + return cv; | |
| 535 | + } | |
| 536 | + | |
| 537 | + protected static SurfaceData convertFrom(Blit ob, SurfaceData srcData, | |
| 538 | + int srcX, int srcY, int w, int h, | |
| 539 | + SurfaceData dstData) | |
| 540 | + { | |
| 541 | + return convertFrom(ob, srcData, | |
| 542 | + srcX, srcY, w, h, dstData, | |
| 543 | + BufferedImage.TYPE_INT_ARGB); | |
| 544 | + } | |
| 545 | + | |
| 546 | + protected static SurfaceData convertFrom(Blit ob, SurfaceData srcData, | |
| 547 | + int srcX, int srcY, int w, int h, | |
| 548 | + SurfaceData dstData, int type) | |
| 549 | + { | |
| 550 | + if (dstData != null) { | |
| 551 | + Rectangle r = dstData.getBounds(); | |
| 552 | + if (w > r.width || h > r.height) { | |
| 553 | + dstData = null; | |
| 554 | + } | |
| 555 | + } | |
| 556 | + if (dstData == null) { | |
| 557 | + BufferedImage dstBI = new BufferedImage(w, h, type); | |
| 558 | + dstData = BufImgSurfaceData.createData(dstBI); | |
| 559 | + } | |
| 560 | + ob.Blit(srcData, dstData, AlphaComposite.Src, null, | |
| 561 | + srcX, srcY, 0, 0, w, h); | |
| 562 | + return dstData; | |
| 563 | + } | |
| 564 | + | |
| 565 | + protected static void convertTo(Blit ob, | |
| 566 | + SurfaceData srcImg, SurfaceData dstImg, | |
| 567 | + Region clip, | |
| 568 | + int dstX, int dstY, int w, int h) | |
| 569 | + { | |
| 570 | + if (ob != null) { | |
| 571 | + ob.Blit(srcImg, dstImg, AlphaComposite.Src, clip, | |
| 572 | + 0, 0, dstX, dstY, w, h); | |
| 573 | + } | |
| 574 | + } | |
| 575 | + | |
| 576 | + protected static GraphicsPrimitive getGeneralOp(int primID, | |
| 577 | + CompositeType comptype) | |
| 578 | + { | |
| 579 | + return GraphicsPrimitiveMgr.locatePrim(primID, | |
| 580 | + SurfaceType.IntArgb, | |
| 581 | + comptype, | |
| 582 | + SurfaceType.IntArgb); | |
| 583 | + } | |
| 584 | + | |
| 585 | + public static String simplename(Field[] fields, Object o) { | |
| 586 | + for (int i = 0; i < fields.length; i++) { | |
| 587 | + Field f = fields[i]; | |
| 588 | + try { | |
| 589 | + if (o == f.get(null)) { | |
| 590 | + return f.getName(); | |
| 591 | + } | |
| 592 | + } catch (Exception e) { | |
| 593 | + } | |
| 594 | + } | |
| 595 | + return "\""+o.toString()+"\""; | |
| 596 | + } | |
| 597 | + | |
| 598 | + public static String simplename(SurfaceType st) { | |
| 599 | + return simplename(SurfaceType.class.getDeclaredFields(), st); | |
| 600 | + } | |
| 601 | + | |
| 602 | + public static String simplename(CompositeType ct) { | |
| 603 | + return simplename(CompositeType.class.getDeclaredFields(), ct); | |
| 604 | + } | |
| 605 | + | |
| 606 | + private String cachedname; | |
| 607 | + | |
| 608 | + public String toString() { | |
| 609 | + if (cachedname == null) { | |
| 610 | + String sig = methodSignature; | |
| 611 | + int index = sig.indexOf('('); | |
| 612 | + if (index >= 0) { | |
| 613 | + sig = sig.substring(0, index); | |
| 614 | + } | |
| 615 | + cachedname = (getClass().getName()+"::"+ | |
| 616 | + sig+"("+ | |
| 617 | + simplename(sourceType)+", "+ | |
| 618 | + simplename(compositeType)+", "+ | |
| 619 | + simplename(destType)+")"); | |
| 620 | + } | |
| 621 | + return cachedname; | |
| 622 | + } | |
| 623 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,330 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +/* | |
| 27 | + * @author Charlton Innovations, Inc. | |
| 28 | + */ | |
| 29 | + | |
| 30 | +package sun.java2d.loops; | |
| 31 | + | |
| 32 | +import java.util.Comparator; | |
| 33 | +import java.util.Arrays; | |
| 34 | +import sun.java2d.SunGraphics2D; | |
| 35 | + | |
| 36 | +/** | |
| 37 | + * GraphicsComponentMgr provides services to | |
| 38 | + * 1. register primitives for later use | |
| 39 | + * 2. locate an instance of a primitve based on characteristics | |
| 40 | + */ | |
| 41 | +public final class GraphicsPrimitiveMgr { | |
| 42 | + | |
| 43 | + private static final boolean debugTrace = false; | |
| 44 | + private static GraphicsPrimitive primitives[]; | |
| 45 | + private static GraphicsPrimitive generalPrimitives[]; | |
| 46 | + private static boolean needssort = true; | |
| 47 | + | |
| 48 | + private static native void initIDs(Class GP, Class ST, Class CT, | |
| 49 | + Class SG2D, Class Color, Class AT, | |
| 50 | + Class XORComp, Class AlphaComp, | |
| 51 | + Class Path2D, Class Path2DFloat, | |
| 52 | + Class SHints); | |
| 53 | + private static native void registerNativeLoops(); | |
| 54 | + | |
| 55 | + static { | |
| 56 | + initIDs(GraphicsPrimitive.class, | |
| 57 | + SurfaceType.class, | |
| 58 | + CompositeType.class, | |
| 59 | + SunGraphics2D.class, | |
| 60 | + java.awt.Color.class, | |
| 61 | + java.awt.geom.AffineTransform.class, | |
| 62 | + XORComposite.class, | |
| 63 | + java.awt.AlphaComposite.class, | |
| 64 | + java.awt.geom.Path2D.class, | |
| 65 | + java.awt.geom.Path2D.Float.class, | |
| 66 | + sun.awt.SunHints.class); | |
| 67 | + CustomComponent.register(); | |
| 68 | + GeneralRenderer.register(); | |
| 69 | + registerNativeLoops(); | |
| 70 | + } | |
| 71 | + | |
| 72 | + private static class PrimitiveSpec { | |
| 73 | + public int uniqueID; | |
| 74 | + } | |
| 75 | + | |
| 76 | + private static Comparator primSorter = new Comparator() { | |
| 77 | + public int compare(Object o1, Object o2) { | |
| 78 | + int id1 = ((GraphicsPrimitive) o1).getUniqueID(); | |
| 79 | + int id2 = ((GraphicsPrimitive) o2).getUniqueID(); | |
| 80 | + | |
| 81 | + return (id1 == id2 ? 0 : (id1 < id2 ? -1 : 1)); | |
| 82 | + } | |
| 83 | + }; | |
| 84 | + | |
| 85 | + private static Comparator primFinder = new Comparator() { | |
| 86 | + public int compare(Object o1, Object o2) { | |
| 87 | + int id1 = ((GraphicsPrimitive) o1).getUniqueID(); | |
| 88 | + int id2 = ((PrimitiveSpec) o2).uniqueID; | |
| 89 | + | |
| 90 | + return (id1 == id2 ? 0 : (id1 < id2 ? -1 : 1)); | |
| 91 | + } | |
| 92 | + }; | |
| 93 | + | |
| 94 | + /** | |
| 95 | + * Ensure that noone can instantiate this class. | |
| 96 | + */ | |
| 97 | + private GraphicsPrimitiveMgr() { | |
| 98 | + } | |
| 99 | + | |
| 100 | + public synchronized static void register(GraphicsPrimitive[] newPrimitives) | |
| 101 | + { | |
| 102 | + GraphicsPrimitive[] devCollection = primitives; | |
| 103 | + int oldSize = 0; | |
| 104 | + int newSize = newPrimitives.length; | |
| 105 | + if (debugTrace) { | |
| 106 | + writeLog("Registering " + newSize + " primitives"); | |
| 107 | + for (int i = 0; i < newSize; i++) { | |
| 108 | + writeLog(newPrimitives[i].toString()); | |
| 109 | + } | |
| 110 | + } | |
| 111 | + if (devCollection != null) { | |
| 112 | + oldSize = devCollection.length; | |
| 113 | + } | |
| 114 | + GraphicsPrimitive[] temp = new GraphicsPrimitive[oldSize + newSize]; | |
| 115 | + if (devCollection != null) { | |
| 116 | + System.arraycopy(devCollection, 0, temp, 0, oldSize); | |
| 117 | + } | |
| 118 | + System.arraycopy(newPrimitives, 0, temp, oldSize, newSize); | |
| 119 | + needssort = true; | |
| 120 | + primitives = temp; | |
| 121 | + } | |
| 122 | + | |
| 123 | + public synchronized static void registerGeneral(GraphicsPrimitive gen) { | |
| 124 | + if (generalPrimitives == null) { | |
| 125 | + generalPrimitives = new GraphicsPrimitive[] {gen}; | |
| 126 | + return; | |
| 127 | + } | |
| 128 | + int len = generalPrimitives.length; | |
| 129 | + GraphicsPrimitive[] newGen = new GraphicsPrimitive[len + 1]; | |
| 130 | + System.arraycopy(generalPrimitives, 0, newGen, 0, len); | |
| 131 | + newGen[len] = gen; | |
| 132 | + generalPrimitives = newGen; | |
| 133 | + } | |
| 134 | + | |
| 135 | + public synchronized static GraphicsPrimitive locate(int primTypeID, | |
| 136 | + SurfaceType dsttype) | |
| 137 | + { | |
| 138 | + return locate(primTypeID, | |
| 139 | + SurfaceType.OpaqueColor, | |
| 140 | + CompositeType.Src, | |
| 141 | + dsttype); | |
| 142 | + } | |
| 143 | + | |
| 144 | + public synchronized static GraphicsPrimitive locate(int primTypeID, | |
| 145 | + SurfaceType srctype, | |
| 146 | + CompositeType comptype, | |
| 147 | + SurfaceType dsttype) | |
| 148 | + { | |
| 149 | + /* | |
| 150 | + System.out.println("Looking for:"); | |
| 151 | + System.out.println(" method: "+signature); | |
| 152 | + System.out.println(" from: "+srctype); | |
| 153 | + System.out.println(" by: "+comptype); | |
| 154 | + System.out.println(" to: "+dsttype); | |
| 155 | + */ | |
| 156 | + GraphicsPrimitive prim = locatePrim(primTypeID, | |
| 157 | + srctype, comptype, dsttype); | |
| 158 | + | |
| 159 | + if (prim == null) { | |
| 160 | + //System.out.println("Trying general loop"); | |
| 161 | + prim = locateGeneral(primTypeID); | |
| 162 | + if (prim != null) { | |
| 163 | + prim = prim.makePrimitive(srctype, comptype, dsttype); | |
| 164 | + if (prim != null && GraphicsPrimitive.traceflags != 0) { | |
| 165 | + prim = prim.traceWrap(); | |
| 166 | + } | |
| 167 | + } | |
| 168 | + } | |
| 169 | + return prim; | |
| 170 | + } | |
| 171 | + | |
| 172 | + public synchronized static GraphicsPrimitive | |
| 173 | + locatePrim(int primTypeID, | |
| 174 | + SurfaceType srctype, | |
| 175 | + CompositeType comptype, | |
| 176 | + SurfaceType dsttype) | |
| 177 | + { | |
| 178 | + /* | |
| 179 | + System.out.println("Looking for:"); | |
| 180 | + System.out.println(" method: "+signature); | |
| 181 | + System.out.println(" from: "+srctype); | |
| 182 | + System.out.println(" by: "+comptype); | |
| 183 | + System.out.println(" to: "+dsttype); | |
| 184 | + */ | |
| 185 | + SurfaceType src, dst; | |
| 186 | + CompositeType cmp; | |
| 187 | + GraphicsPrimitive prim; | |
| 188 | + PrimitiveSpec spec = new PrimitiveSpec(); | |
| 189 | + | |
| 190 | + for (dst = dsttype; dst != null; dst = dst.getSuperType()) { | |
| 191 | + for (src = srctype; src != null; src = src.getSuperType()) { | |
| 192 | + for (cmp = comptype; cmp != null; cmp = cmp.getSuperType()) { | |
| 193 | + /* | |
| 194 | + System.out.println("Trying:"); | |
| 195 | + System.out.println(" method: "+spec.methodSignature); | |
| 196 | + System.out.println(" from: "+spec.sourceType); | |
| 197 | + System.out.println(" by: "+spec.compType); | |
| 198 | + System.out.println(" to: "+spec.destType); | |
| 199 | + */ | |
| 200 | + | |
| 201 | + spec.uniqueID = | |
| 202 | + GraphicsPrimitive.makeUniqueID(primTypeID, src, cmp, dst); | |
| 203 | + prim = locate(spec); | |
| 204 | + if (prim != null) { | |
| 205 | + //System.out.println("<GPMgr> Found: " + prim + " in " + i + " steps"); | |
| 206 | + return prim; | |
| 207 | + } | |
| 208 | + } | |
| 209 | + } | |
| 210 | + } | |
| 211 | + return null; | |
| 212 | + } | |
| 213 | + | |
| 214 | + private static GraphicsPrimitive locateGeneral(int primTypeID) { | |
| 215 | + if (generalPrimitives == null) { | |
| 216 | + return null; | |
| 217 | + } | |
| 218 | + for (int i = 0; i < generalPrimitives.length; i++) { | |
| 219 | + GraphicsPrimitive prim = generalPrimitives[i]; | |
| 220 | + if (prim.getPrimTypeID() == primTypeID) { | |
| 221 | + return prim; | |
| 222 | + } | |
| 223 | + } | |
| 224 | + return null; | |
| 225 | + //throw new InternalError("No general handler registered for"+signature); | |
| 226 | + } | |
| 227 | + | |
| 228 | + private static GraphicsPrimitive locate(PrimitiveSpec spec) { | |
| 229 | + if (needssort) { | |
| 230 | + if (GraphicsPrimitive.traceflags != 0) { | |
| 231 | + for (int i = 0; i < primitives.length; i++) { | |
| 232 | + primitives[i] = primitives[i].traceWrap(); | |
| 233 | + } | |
| 234 | + } | |
| 235 | + Arrays.sort(primitives, primSorter); | |
| 236 | + needssort = false; | |
| 237 | + } | |
| 238 | + GraphicsPrimitive[] devCollection = primitives; | |
| 239 | + if (devCollection == null) { | |
| 240 | + return null; | |
| 241 | + } | |
| 242 | + int index = Arrays.binarySearch(devCollection, spec, primFinder); | |
| 243 | + if (index >= 0) { | |
| 244 | + GraphicsPrimitive prim = devCollection[index]; | |
| 245 | + if (prim instanceof GraphicsPrimitiveProxy) { | |
| 246 | + prim = ((GraphicsPrimitiveProxy) prim).instantiate(); | |
| 247 | + devCollection[index] = prim; | |
| 248 | + if (debugTrace) { | |
| 249 | + writeLog("Instantiated graphics primitive " + prim); | |
| 250 | + } | |
| 251 | + } | |
| 252 | + if (debugTrace) { | |
| 253 | + writeLog("Lookup found[" + index + "]["+ prim + "]"); | |
| 254 | + } | |
| 255 | + return prim; | |
| 256 | + } | |
| 257 | + if (debugTrace) { | |
| 258 | + writeLog("Lookup found nothing for:"); | |
| 259 | + writeLog(" " + spec.uniqueID); | |
| 260 | + } | |
| 261 | + return null; | |
| 262 | + } | |
| 263 | + | |
| 264 | + private static void writeLog(String str) { | |
| 265 | + if (debugTrace) { | |
| 266 | + System.err.println(str); | |
| 267 | + } | |
| 268 | + } | |
| 269 | + | |
| 270 | + /** | |
| 271 | + * Test that all of the GraphicsPrimitiveProxy objects actually | |
| 272 | + * resolve to something. Throws a RuntimeException if anything | |
| 273 | + * is wrong, an has no effect if all is well. | |
| 274 | + */ | |
| 275 | + // This is only really meant to be called from GraphicsPrimitiveProxyTest | |
| 276 | + // in the regression tests directory, but it has to be here because | |
| 277 | + // it needs access to a private data structure. It is not very | |
| 278 | + // big, though. | |
| 279 | + public static void testPrimitiveInstantiation() { | |
| 280 | + testPrimitiveInstantiation(false); | |
| 281 | + } | |
| 282 | + | |
| 283 | + public static void testPrimitiveInstantiation(boolean verbose) { | |
| 284 | + int resolved = 0; | |
| 285 | + int unresolved = 0; | |
| 286 | + GraphicsPrimitive[] prims = primitives; | |
| 287 | + for (int j = 0; j < prims.length; j++) { | |
| 288 | + GraphicsPrimitive p = prims[j]; | |
| 289 | + if (p instanceof GraphicsPrimitiveProxy) { | |
| 290 | + GraphicsPrimitive r = ((GraphicsPrimitiveProxy) p).instantiate(); | |
| 291 | + if (!r.getSignature().equals(p.getSignature()) || | |
| 292 | + r.getUniqueID() != p.getUniqueID()) { | |
| 293 | + System.out.println("r.getSignature == "+r.getSignature()); | |
| 294 | + System.out.println("r.getUniqueID == " + r.getUniqueID()); | |
| 295 | + System.out.println("p.getSignature == "+p.getSignature()); | |
| 296 | + System.out.println("p.getUniqueID == " + p.getUniqueID()); | |
| 297 | + throw new RuntimeException("Primitive " + p | |
| 298 | + + " returns wrong signature for " | |
| 299 | + + r.getClass()); | |
| 300 | + } | |
| 301 | + // instantiate checks that p.satisfiesSameAs(r) | |
| 302 | + unresolved++; | |
| 303 | + p = r; | |
| 304 | + if (verbose) { | |
| 305 | + System.out.println(p); | |
| 306 | + } | |
| 307 | + } else { | |
| 308 | + if (verbose) { | |
| 309 | + System.out.println(p + " (not proxied)."); | |
| 310 | + } | |
| 311 | + resolved++; | |
| 312 | + } | |
| 313 | + } | |
| 314 | + System.out.println(resolved+ | |
| 315 | + " graphics primitives were not proxied."); | |
| 316 | + System.out.println(unresolved+ | |
| 317 | + " proxied graphics primitives resolved correctly."); | |
| 318 | + System.out.println(resolved+unresolved+ | |
| 319 | + " total graphics primitives"); | |
| 320 | + } | |
| 321 | + | |
| 322 | + public static void main(String argv[]) { | |
| 323 | + // REMIND: Should trigger loading of platform primitives somehow... | |
| 324 | + if (needssort) { | |
| 325 | + Arrays.sort(primitives, primSorter); | |
| 326 | + needssort = false; | |
| 327 | + } | |
| 328 | + testPrimitiveInstantiation(argv.length > 0); | |
| 329 | + } | |
| 330 | +} | |
Binary file not shown.
| @@ -0,0 +1,114 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.loops; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * GraphicsPrimitiveProxy | |
| 30 | + * | |
| 31 | + * Acts as a proxy for instances of GraphicsPrimitive, enabling lazy | |
| 32 | + * classloading of these primitives. This leads to a substantial | |
| 33 | + * savings in start-up time and footprint. In the typical case, | |
| 34 | + * it has been found that a small number of GraphicsPrimitive instance | |
| 35 | + * actually end up getting instantiated. | |
| 36 | + * <p> | |
| 37 | + * Note that the makePrimitive method should never be invoked on | |
| 38 | + * a GraphicsPrimitiveProxy object since they are instantiated as | |
| 39 | + * soon as they are found in the primitive list and never returned | |
| 40 | + * to the caller. | |
| 41 | + */ | |
| 42 | +public class GraphicsPrimitiveProxy extends GraphicsPrimitive { | |
| 43 | + | |
| 44 | + private Class owner; | |
| 45 | + private String relativeClassName; | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * Create a GraphicsPrimitiveProxy for a primitive with a no-argument | |
| 49 | + * constructor. | |
| 50 | + * | |
| 51 | + * @param owner The owner class for this primitive. The primitive | |
| 52 | + * must be in the same package as this owner. | |
| 53 | + * @param relativeClassName The name of the class this is a proxy for. | |
| 54 | + * This should not include the package. | |
| 55 | + */ | |
| 56 | + public GraphicsPrimitiveProxy(Class owner, String relativeClassName, | |
| 57 | + String methodSignature, | |
| 58 | + int primID, | |
| 59 | + SurfaceType srctype, | |
| 60 | + CompositeType comptype, | |
| 61 | + SurfaceType dsttype) | |
| 62 | + { | |
| 63 | + super(methodSignature, primID, srctype, comptype, dsttype); | |
| 64 | + this.owner = owner; | |
| 65 | + this.relativeClassName = relativeClassName; | |
| 66 | + } | |
| 67 | + | |
| 68 | + public GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 69 | + CompositeType comptype, | |
| 70 | + SurfaceType dsttype) { | |
| 71 | + // This should never happen. | |
| 72 | + throw new InternalError("makePrimitive called on a Proxy!"); | |
| 73 | + } | |
| 74 | + | |
| 75 | + // | |
| 76 | + // Come up with the real instance. Called from | |
| 77 | + // GraphicsPrimitiveMgr.locate() | |
| 78 | + // | |
| 79 | + GraphicsPrimitive instantiate() { | |
| 80 | + String name = getPackageName(owner.getName()) + "." | |
| 81 | + + relativeClassName; | |
| 82 | + try { | |
| 83 | + Class clazz = Class.forName(name); | |
| 84 | + GraphicsPrimitive p = (GraphicsPrimitive) clazz.newInstance(); | |
| 85 | + if (!satisfiesSameAs(p)) { | |
| 86 | + throw new RuntimeException("Primitive " + p | |
| 87 | + + " incompatible with proxy for " | |
| 88 | + + name); | |
| 89 | + } | |
| 90 | + return p; | |
| 91 | + } catch (ClassNotFoundException ex) { | |
| 92 | + throw new RuntimeException(ex.toString()); | |
| 93 | + } catch (InstantiationException ex) { | |
| 94 | + throw new RuntimeException(ex.toString()); | |
| 95 | + } catch (IllegalAccessException ex) { | |
| 96 | + throw new RuntimeException(ex.toString()); | |
| 97 | + } | |
| 98 | + // A RuntimeException should never happen in a deployed JDK, because | |
| 99 | + // the regression test GraphicsPrimitiveProxyTest will catch any | |
| 100 | + // of these errors. | |
| 101 | + } | |
| 102 | + | |
| 103 | + private static String getPackageName(String className) { | |
| 104 | + int lastDotIdx = className.lastIndexOf('.'); | |
| 105 | + if (lastDotIdx < 0) { | |
| 106 | + return className; | |
| 107 | + } | |
| 108 | + return className.substring(0, lastDotIdx); | |
| 109 | + } | |
| 110 | + | |
| 111 | + public GraphicsPrimitive traceWrap() { | |
| 112 | + return instantiate().traceWrap(); | |
| 113 | + } | |
| 114 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,264 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.loops; | |
| 27 | + | |
| 28 | +import java.awt.Composite; | |
| 29 | +import java.lang.ref.WeakReference; | |
| 30 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 31 | +import sun.java2d.SurfaceData; | |
| 32 | +import sun.java2d.pipe.Region; | |
| 33 | + | |
| 34 | +/** | |
| 35 | + * MaskBlit | |
| 36 | + * 1) copies rectangle of pixels from one surface to another | |
| 37 | + * 2) performs compositing of colors based upon a Composite | |
| 38 | + * parameter | |
| 39 | + * 3) blends result of composite with destination using an | |
| 40 | + * alpha coverage mask | |
| 41 | + * 4) the mask may be null in which case it should be treated | |
| 42 | + * as if it were an array of all opaque values (0xff) | |
| 43 | + * | |
| 44 | + * precise behavior is undefined if the source surface | |
| 45 | + * and the destination surface are the same surface | |
| 46 | + * with overlapping regions of pixels | |
| 47 | + */ | |
| 48 | + | |
| 49 | +public class MaskBlit extends GraphicsPrimitive | |
| 50 | +{ | |
| 51 | + public static final String methodSignature = "MaskBlit(...)".toString(); | |
| 52 | + | |
| 53 | + public static final int primTypeID = makePrimTypeID(); | |
| 54 | + | |
| 55 | + private static RenderCache blitcache = new RenderCache(20); | |
| 56 | + | |
| 57 | + public static MaskBlit locate(SurfaceType srctype, | |
| 58 | + CompositeType comptype, | |
| 59 | + SurfaceType dsttype) | |
| 60 | + { | |
| 61 | + return (MaskBlit) | |
| 62 | + GraphicsPrimitiveMgr.locate(primTypeID, | |
| 63 | + srctype, comptype, dsttype); | |
| 64 | + } | |
| 65 | + | |
| 66 | + public static MaskBlit getFromCache(SurfaceType src, | |
| 67 | + CompositeType comp, | |
| 68 | + SurfaceType dst) | |
| 69 | + { | |
| 70 | + Object o = blitcache.get(src, comp, dst); | |
| 71 | + if (o != null) { | |
| 72 | + return (MaskBlit) o; | |
| 73 | + } | |
| 74 | + MaskBlit blit = locate(src, comp, dst); | |
| 75 | + if (blit == null) { | |
| 76 | + System.out.println("mask blit loop not found for:"); | |
| 77 | + System.out.println("src: "+src); | |
| 78 | + System.out.println("comp: "+comp); | |
| 79 | + System.out.println("dst: "+dst); | |
| 80 | + } else { | |
| 81 | + blitcache.put(src, comp, dst, blit); | |
| 82 | + } | |
| 83 | + return blit; | |
| 84 | + } | |
| 85 | + | |
| 86 | + protected MaskBlit(SurfaceType srctype, | |
| 87 | + CompositeType comptype, | |
| 88 | + SurfaceType dsttype) | |
| 89 | + { | |
| 90 | + super(methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 91 | + } | |
| 92 | + | |
| 93 | + public MaskBlit(long pNativePrim, | |
| 94 | + SurfaceType srctype, | |
| 95 | + CompositeType comptype, | |
| 96 | + SurfaceType dsttype) | |
| 97 | + { | |
| 98 | + super(pNativePrim, methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 99 | + } | |
| 100 | + | |
| 101 | + /** | |
| 102 | + * All MaskBlit implementors must have this invoker method | |
| 103 | + */ | |
| 104 | + public native void MaskBlit(SurfaceData src, SurfaceData dst, | |
| 105 | + Composite comp, Region clip, | |
| 106 | + int srcx, int srcy, | |
| 107 | + int dstx, int dsty, | |
| 108 | + int width, int height, | |
| 109 | + byte[] mask, int maskoff, int maskscan); | |
| 110 | + | |
| 111 | + static { | |
| 112 | + GraphicsPrimitiveMgr.registerGeneral(new MaskBlit(null, null, null)); | |
| 113 | + } | |
| 114 | + | |
| 115 | + public GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 116 | + CompositeType comptype, | |
| 117 | + SurfaceType dsttype) | |
| 118 | + { | |
| 119 | + /* | |
| 120 | + new Throwable().printStackTrace(); | |
| 121 | + System.out.println("Constructing general maskblit for:"); | |
| 122 | + System.out.println("src: "+srctype); | |
| 123 | + System.out.println("comp: "+comptype); | |
| 124 | + System.out.println("dst: "+dsttype); | |
| 125 | + */ | |
| 126 | + | |
| 127 | + if (CompositeType.Xor.equals(comptype)) { | |
| 128 | + throw new InternalError("Cannot construct MaskBlit for " + | |
| 129 | + "XOR mode"); | |
| 130 | + } | |
| 131 | + | |
| 132 | + General ob = new General(srctype, comptype, dsttype); | |
| 133 | + setupGeneralBinaryOp(ob); | |
| 134 | + return ob; | |
| 135 | + } | |
| 136 | + | |
| 137 | + private static class General | |
| 138 | + extends MaskBlit | |
| 139 | + implements GeneralBinaryOp | |
| 140 | + { | |
| 141 | + Blit convertsrc; | |
| 142 | + Blit convertdst; | |
| 143 | + MaskBlit performop; | |
| 144 | + Blit convertresult; | |
| 145 | + | |
| 146 | + WeakReference srcTmp; | |
| 147 | + WeakReference dstTmp; | |
| 148 | + | |
| 149 | + public General(SurfaceType srctype, | |
| 150 | + CompositeType comptype, | |
| 151 | + SurfaceType dsttype) | |
| 152 | + { | |
| 153 | + super(srctype, comptype, dsttype); | |
| 154 | + } | |
| 155 | + | |
| 156 | + public void setPrimitives(Blit srcconverter, | |
| 157 | + Blit dstconverter, | |
| 158 | + GraphicsPrimitive genericop, | |
| 159 | + Blit resconverter) | |
| 160 | + { | |
| 161 | + this.convertsrc = srcconverter; | |
| 162 | + this.convertdst = dstconverter; | |
| 163 | + this.performop = (MaskBlit) genericop; | |
| 164 | + this.convertresult = resconverter; | |
| 165 | + } | |
| 166 | + | |
| 167 | + public synchronized void MaskBlit(SurfaceData srcData, | |
| 168 | + SurfaceData dstData, | |
| 169 | + Composite comp, | |
| 170 | + Region clip, | |
| 171 | + int srcx, int srcy, | |
| 172 | + int dstx, int dsty, | |
| 173 | + int width, int height, | |
| 174 | + byte mask[], int offset, int scan) | |
| 175 | + { | |
| 176 | + SurfaceData src, dst; | |
| 177 | + Region opclip; | |
| 178 | + int sx, sy, dx, dy; | |
| 179 | + | |
| 180 | + if (convertsrc == null) { | |
| 181 | + src = srcData; | |
| 182 | + sx = srcx; | |
| 183 | + sy = srcy; | |
| 184 | + } else { | |
| 185 | + SurfaceData cachedSrc = null; | |
| 186 | + if (srcTmp != null) { | |
| 187 | + cachedSrc = (SurfaceData) srcTmp.get(); | |
| 188 | + } | |
| 189 | + src = convertFrom(convertsrc, srcData, srcx, srcy, | |
| 190 | + width, height, cachedSrc); | |
| 191 | + sx = 0; | |
| 192 | + sy = 0; | |
| 193 | + if (src != cachedSrc) { | |
| 194 | + srcTmp = new WeakReference(src); | |
| 195 | + } | |
| 196 | + } | |
| 197 | + | |
| 198 | + if (convertdst == null) { | |
| 199 | + dst = dstData; | |
| 200 | + dx = dstx; | |
| 201 | + dy = dsty; | |
| 202 | + opclip = clip; | |
| 203 | + } else { | |
| 204 | + // assert: convertresult != null | |
| 205 | + SurfaceData cachedDst = null; | |
| 206 | + if (dstTmp != null) { | |
| 207 | + cachedDst = (SurfaceData) dstTmp.get(); | |
| 208 | + } | |
| 209 | + dst = convertFrom(convertdst, dstData, dstx, dsty, | |
| 210 | + width, height, cachedDst); | |
| 211 | + dx = 0; | |
| 212 | + dy = 0; | |
| 213 | + opclip = null; | |
| 214 | + if (dst != cachedDst) { | |
| 215 | + dstTmp = new WeakReference(dst); | |
| 216 | + } | |
| 217 | + } | |
| 218 | + | |
| 219 | + performop.MaskBlit(src, dst, comp, opclip, | |
| 220 | + sx, sy, dx, dy, width, height, | |
| 221 | + mask, offset, scan); | |
| 222 | + | |
| 223 | + if (convertresult != null) { | |
| 224 | + // assert: convertdst != null | |
| 225 | + convertTo(convertresult, dst, dstData, clip, | |
| 226 | + dstx, dsty, width, height); | |
| 227 | + } | |
| 228 | + } | |
| 229 | + } | |
| 230 | + | |
| 231 | + public GraphicsPrimitive traceWrap() { | |
| 232 | + return new TraceMaskBlit(this); | |
| 233 | + } | |
| 234 | + | |
| 235 | + private static class TraceMaskBlit extends MaskBlit { | |
| 236 | + MaskBlit target; | |
| 237 | + | |
| 238 | + public TraceMaskBlit(MaskBlit target) { | |
| 239 | + // We need to have the same NativePrim as our | |
| 240 | + // target in case we are used with a TransformHelper | |
| 241 | + super(target.getNativePrim(), | |
| 242 | + target.getSourceType(), | |
| 243 | + target.getCompositeType(), | |
| 244 | + target.getDestType()); | |
| 245 | + this.target = target; | |
| 246 | + } | |
| 247 | + | |
| 248 | + public GraphicsPrimitive traceWrap() { | |
| 249 | + return this; | |
| 250 | + } | |
| 251 | + | |
| 252 | + public void MaskBlit(SurfaceData src, SurfaceData dst, | |
| 253 | + Composite comp, Region clip, | |
| 254 | + int srcx, int srcy, int dstx, int dsty, | |
| 255 | + int width, int height, | |
| 256 | + byte[] mask, int maskoff, int maskscan) | |
| 257 | + { | |
| 258 | + tracePrimitive(target); | |
| 259 | + target.MaskBlit(src, dst, comp, clip, | |
| 260 | + srcx, srcy, dstx, dsty, width, height, | |
| 261 | + mask, maskoff, maskscan); | |
| 262 | + } | |
| 263 | + } | |
| 264 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,273 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.loops; | |
| 27 | + | |
| 28 | +import java.awt.Paint; | |
| 29 | +import java.awt.PaintContext; | |
| 30 | +import java.awt.Composite; | |
| 31 | +import java.awt.Rectangle; | |
| 32 | +import java.awt.image.ColorModel; | |
| 33 | +import java.awt.image.BufferedImage; | |
| 34 | +import java.awt.image.WritableRaster; | |
| 35 | +import sun.awt.image.BufImgSurfaceData; | |
| 36 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 37 | +import sun.java2d.SunGraphics2D; | |
| 38 | +import sun.java2d.SurfaceData; | |
| 39 | + | |
| 40 | +/** | |
| 41 | + * MaskFill | |
| 42 | + * 1) fills rectangles of pixels on a surface | |
| 43 | + * 2) performs compositing of colors based upon a Composite | |
| 44 | + * parameter | |
| 45 | + * 3) blends result of composite with destination using an | |
| 46 | + * alpha coverage mask | |
| 47 | + * 4) the mask may be null in which case it should be treated | |
| 48 | + * as if it were an array of all opaque values (0xff) | |
| 49 | + */ | |
| 50 | +public class MaskFill extends GraphicsPrimitive | |
| 51 | +{ | |
| 52 | + public static final String methodSignature = "MaskFill(...)".toString(); | |
| 53 | + public static final String fillPgramSignature = | |
| 54 | + "FillAAPgram(...)".toString(); | |
| 55 | + public static final String drawPgramSignature = | |
| 56 | + "DrawAAPgram(...)".toString(); | |
| 57 | + | |
| 58 | + public static final int primTypeID = makePrimTypeID(); | |
| 59 | + | |
| 60 | + private static RenderCache fillcache = new RenderCache(10); | |
| 61 | + | |
| 62 | + public static MaskFill locate(SurfaceType srctype, | |
| 63 | + CompositeType comptype, | |
| 64 | + SurfaceType dsttype) | |
| 65 | + { | |
| 66 | + return (MaskFill) | |
| 67 | + GraphicsPrimitiveMgr.locate(primTypeID, | |
| 68 | + srctype, comptype, dsttype); | |
| 69 | + } | |
| 70 | + | |
| 71 | + public static MaskFill locatePrim(SurfaceType srctype, | |
| 72 | + CompositeType comptype, | |
| 73 | + SurfaceType dsttype) | |
| 74 | + { | |
| 75 | + return (MaskFill) | |
| 76 | + GraphicsPrimitiveMgr.locatePrim(primTypeID, | |
| 77 | + srctype, comptype, dsttype); | |
| 78 | + } | |
| 79 | + | |
| 80 | + /* | |
| 81 | + * Note that this uses locatePrim, not locate, so it can return | |
| 82 | + * null if there is no specific loop to handle this op... | |
| 83 | + */ | |
| 84 | + public static MaskFill getFromCache(SurfaceType src, | |
| 85 | + CompositeType comp, | |
| 86 | + SurfaceType dst) | |
| 87 | + { | |
| 88 | + Object o = fillcache.get(src, comp, dst); | |
| 89 | + if (o != null) { | |
| 90 | + return (MaskFill) o; | |
| 91 | + } | |
| 92 | + MaskFill fill = locatePrim(src, comp, dst); | |
| 93 | + if (fill != null) { | |
| 94 | + fillcache.put(src, comp, dst, fill); | |
| 95 | + } | |
| 96 | + return fill; | |
| 97 | + } | |
| 98 | + | |
| 99 | + protected MaskFill(String alternateSignature, | |
| 100 | + SurfaceType srctype, | |
| 101 | + CompositeType comptype, | |
| 102 | + SurfaceType dsttype) | |
| 103 | + { | |
| 104 | + super(alternateSignature, primTypeID, srctype, comptype, dsttype); | |
| 105 | + } | |
| 106 | + | |
| 107 | + protected MaskFill(SurfaceType srctype, | |
| 108 | + CompositeType comptype, | |
| 109 | + SurfaceType dsttype) | |
| 110 | + { | |
| 111 | + super(methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 112 | + } | |
| 113 | + | |
| 114 | + public MaskFill(long pNativePrim, | |
| 115 | + SurfaceType srctype, | |
| 116 | + CompositeType comptype, | |
| 117 | + SurfaceType dsttype) | |
| 118 | + { | |
| 119 | + super(pNativePrim, methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 120 | + } | |
| 121 | + | |
| 122 | + /** | |
| 123 | + * All MaskFill implementors must have this invoker method | |
| 124 | + */ | |
| 125 | + public native void MaskFill(SunGraphics2D sg2d, SurfaceData sData, | |
| 126 | + Composite comp, | |
| 127 | + int x, int y, int w, int h, | |
| 128 | + byte[] mask, int maskoff, int maskscan); | |
| 129 | + | |
| 130 | + public native void FillAAPgram(SunGraphics2D sg2d, SurfaceData sData, | |
| 131 | + Composite comp, | |
| 132 | + double x, double y, | |
| 133 | + double dx1, double dy1, | |
| 134 | + double dx2, double dy2); | |
| 135 | + | |
| 136 | + public native void DrawAAPgram(SunGraphics2D sg2d, SurfaceData sData, | |
| 137 | + Composite comp, | |
| 138 | + double x, double y, | |
| 139 | + double dx1, double dy1, | |
| 140 | + double dx2, double dy2, | |
| 141 | + double lw1, double lw2); | |
| 142 | + | |
| 143 | + public boolean canDoParallelograms() { | |
| 144 | + return (getNativePrim() != 0); | |
| 145 | + } | |
| 146 | + | |
| 147 | + static { | |
| 148 | + GraphicsPrimitiveMgr.registerGeneral(new MaskFill(null, null, null)); | |
| 149 | + } | |
| 150 | + | |
| 151 | + public GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 152 | + CompositeType comptype, | |
| 153 | + SurfaceType dsttype) | |
| 154 | + { | |
| 155 | + if (SurfaceType.OpaqueColor.equals(srctype) || | |
| 156 | + SurfaceType.AnyColor.equals(srctype)) | |
| 157 | + { | |
| 158 | + if (CompositeType.Xor.equals(comptype)) { | |
| 159 | + throw new InternalError("Cannot construct MaskFill for " + | |
| 160 | + "XOR mode"); | |
| 161 | + } else { | |
| 162 | + return new General(srctype, comptype, dsttype); | |
| 163 | + } | |
| 164 | + } else { | |
| 165 | + throw new InternalError("MaskFill can only fill with colors"); | |
| 166 | + } | |
| 167 | + } | |
| 168 | + | |
| 169 | + private static class General extends MaskFill { | |
| 170 | + FillRect fillop; | |
| 171 | + MaskBlit maskop; | |
| 172 | + | |
| 173 | + public General(SurfaceType srctype, | |
| 174 | + CompositeType comptype, | |
| 175 | + SurfaceType dsttype) | |
| 176 | + { | |
| 177 | + super(srctype, comptype, dsttype); | |
| 178 | + fillop = FillRect.locate(srctype, | |
| 179 | + CompositeType.SrcNoEa, | |
| 180 | + SurfaceType.IntArgb); | |
| 181 | + maskop = MaskBlit.locate(SurfaceType.IntArgb, comptype, dsttype); | |
| 182 | + } | |
| 183 | + | |
| 184 | + public void MaskFill(SunGraphics2D sg2d, | |
| 185 | + SurfaceData sData, | |
| 186 | + Composite comp, | |
| 187 | + int x, int y, int w, int h, | |
| 188 | + byte mask[], int offset, int scan) | |
| 189 | + { | |
| 190 | + BufferedImage dstBI = | |
| 191 | + new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); | |
| 192 | + SurfaceData tmpData = BufImgSurfaceData.createData(dstBI); | |
| 193 | + | |
| 194 | + // REMIND: This is not pretty. It would be nicer if we | |
| 195 | + // passed a "FillData" object to the Pixel loops, instead | |
| 196 | + // of a SunGraphics2D parameter... | |
| 197 | + int pixel = sg2d.pixel; | |
| 198 | + sg2d.pixel = tmpData.pixelFor(sg2d.getColor()); | |
| 199 | + fillop.FillRect(sg2d, tmpData, 0, 0, w, h); | |
| 200 | + sg2d.pixel = pixel; | |
| 201 | + | |
| 202 | + maskop.MaskBlit(tmpData, sData, comp, null, | |
| 203 | + 0, 0, x, y, w, h, | |
| 204 | + mask, offset, scan); | |
| 205 | + } | |
| 206 | + } | |
| 207 | + | |
| 208 | + public GraphicsPrimitive traceWrap() { | |
| 209 | + return new TraceMaskFill(this); | |
| 210 | + } | |
| 211 | + | |
| 212 | + private static class TraceMaskFill extends MaskFill { | |
| 213 | + MaskFill target; | |
| 214 | + MaskFill fillPgramTarget; | |
| 215 | + MaskFill drawPgramTarget; | |
| 216 | + | |
| 217 | + public TraceMaskFill(MaskFill target) { | |
| 218 | + super(target.getSourceType(), | |
| 219 | + target.getCompositeType(), | |
| 220 | + target.getDestType()); | |
| 221 | + this.target = target; | |
| 222 | + this.fillPgramTarget = new MaskFill(fillPgramSignature, | |
| 223 | + target.getSourceType(), | |
| 224 | + target.getCompositeType(), | |
| 225 | + target.getDestType()); | |
| 226 | + this.drawPgramTarget = new MaskFill(drawPgramSignature, | |
| 227 | + target.getSourceType(), | |
| 228 | + target.getCompositeType(), | |
| 229 | + target.getDestType()); | |
| 230 | + } | |
| 231 | + | |
| 232 | + public GraphicsPrimitive traceWrap() { | |
| 233 | + return this; | |
| 234 | + } | |
| 235 | + | |
| 236 | + public void MaskFill(SunGraphics2D sg2d, SurfaceData sData, | |
| 237 | + Composite comp, | |
| 238 | + int x, int y, int w, int h, | |
| 239 | + byte[] mask, int maskoff, int maskscan) | |
| 240 | + { | |
| 241 | + tracePrimitive(target); | |
| 242 | + target.MaskFill(sg2d, sData, comp, x, y, w, h, | |
| 243 | + mask, maskoff, maskscan); | |
| 244 | + } | |
| 245 | + | |
| 246 | + public void FillAAPgram(SunGraphics2D sg2d, SurfaceData sData, | |
| 247 | + Composite comp, | |
| 248 | + double x, double y, | |
| 249 | + double dx1, double dy1, | |
| 250 | + double dx2, double dy2) | |
| 251 | + { | |
| 252 | + tracePrimitive(fillPgramTarget); | |
| 253 | + target.FillAAPgram(sg2d, sData, comp, | |
| 254 | + x, y, dx1, dy1, dx2, dy2); | |
| 255 | + } | |
| 256 | + | |
| 257 | + public void DrawAAPgram(SunGraphics2D sg2d, SurfaceData sData, | |
| 258 | + Composite comp, | |
| 259 | + double x, double y, | |
| 260 | + double dx1, double dy1, | |
| 261 | + double dx2, double dy2, | |
| 262 | + double lw1, double lw2) | |
| 263 | + { | |
| 264 | + tracePrimitive(drawPgramTarget); | |
| 265 | + target.DrawAAPgram(sg2d, sData, comp, | |
| 266 | + x, y, dx1, dy1, dx2, dy2, lw1, lw2); | |
| 267 | + } | |
| 268 | + | |
| 269 | + public boolean canDoParallelograms() { | |
| 270 | + return target.canDoParallelograms(); | |
| 271 | + } | |
| 272 | + } | |
| 273 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,2128 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.loops; | |
| 27 | + | |
| 28 | +import java.awt.geom.Path2D; | |
| 29 | +import java.awt.geom.PathIterator; | |
| 30 | +import java.awt.geom.QuadCurve2D; | |
| 31 | +import sun.awt.SunHints; | |
| 32 | +import java.util.*; | |
| 33 | + | |
| 34 | +/* This is the java implementation of the native code from | |
| 35 | + * src/share/native/sun/java2d/loops/ProcessPath.[c,h] | |
| 36 | + * This code is written to be as much similar to the native | |
| 37 | + * as it possible. So, it sometimes does not follow java naming conventions. | |
| 38 | + * | |
| 39 | + * It's important to keep this code synchronized with native one. See more | |
| 40 | + * comments, description and high level scheme of the rendering process in the | |
| 41 | + * ProcessPath.c | |
| 42 | + */ | |
| 43 | + | |
| 44 | +public class ProcessPath { | |
| 45 | + | |
| 46 | + /* Public interfaces and methods for drawing and filling general paths */ | |
| 47 | + | |
| 48 | + public static abstract class DrawHandler { | |
| 49 | + public int xMin; | |
| 50 | + public int yMin; | |
| 51 | + public int xMax; | |
| 52 | + public int yMax; | |
| 53 | + public float xMinf; | |
| 54 | + public float yMinf; | |
| 55 | + public float xMaxf; | |
| 56 | + public float yMaxf; | |
| 57 | + | |
| 58 | + public int strokeControl; | |
| 59 | + | |
| 60 | + public DrawHandler(int xMin, int yMin, int xMax, int yMax, | |
| 61 | + int strokeControl) | |
| 62 | + { | |
| 63 | + setBounds(xMin, yMin, xMax, yMax, strokeControl); | |
| 64 | + } | |
| 65 | + | |
| 66 | + public void setBounds(int xMin, int yMin, int xMax, int yMax) | |
| 67 | + { | |
| 68 | + this.xMin = xMin; | |
| 69 | + this.yMin = yMin; | |
| 70 | + this.xMax = xMax; | |
| 71 | + this.yMax = yMax; | |
| 72 | + | |
| 73 | + /* Setting up fractional clipping box | |
| 74 | + * | |
| 75 | + * We are using following float -> int mapping: | |
| 76 | + * | |
| 77 | + * xi = floor(xf + 0.5) | |
| 78 | + * | |
| 79 | + * So, fractional values that hit the [xmin, xmax) integer interval | |
| 80 | + * will be situated inside the [xmin-0.5, xmax - 0.5) fractional | |
| 81 | + * interval. We are using EPSF constant to provide that upper | |
| 82 | + * boundary is not included. | |
| 83 | + */ | |
| 84 | + xMinf = xMin - 0.5f; | |
| 85 | + yMinf = yMin - 0.5f; | |
| 86 | + xMaxf = xMax - 0.5f - EPSF; | |
| 87 | + yMaxf = yMax - 0.5f - EPSF; | |
| 88 | + } | |
| 89 | + | |
| 90 | + public void setBounds(int xMin, int yMin, int xMax, int yMax, | |
| 91 | + int strokeControl) | |
| 92 | + { | |
| 93 | + this.strokeControl = strokeControl; | |
| 94 | + setBounds(xMin, yMin, xMax, yMax); | |
| 95 | + } | |
| 96 | + | |
| 97 | + public void adjustBounds(int bxMin, int byMin, int bxMax, int byMax) | |
| 98 | + { | |
| 99 | + if (xMin > bxMin) bxMin = xMin; | |
| 100 | + if (xMax < bxMax) bxMax = xMax; | |
| 101 | + if (yMin > byMin) byMin = yMin; | |
| 102 | + if (yMax < byMax) byMax = yMax; | |
| 103 | + setBounds(bxMin, byMin, bxMax, byMax); | |
| 104 | + } | |
| 105 | + | |
| 106 | + public DrawHandler(int xMin, int yMin, int xMax, int yMax) { | |
| 107 | + this(xMin, yMin, xMax, yMax, SunHints.INTVAL_STROKE_DEFAULT); | |
| 108 | + } | |
| 109 | + | |
| 110 | + public abstract void drawLine(int x0, int y0, int x1, int y1); | |
| 111 | + | |
| 112 | + public abstract void drawPixel(int x0, int y0); | |
| 113 | + | |
| 114 | + public abstract void drawScanline(int x0, int x1, int y0); | |
| 115 | + } | |
| 116 | + | |
| 117 | + public interface EndSubPathHandler { | |
| 118 | + public void processEndSubPath(); | |
| 119 | + } | |
| 120 | + | |
| 121 | + public static final int PH_MODE_DRAW_CLIP = 0; | |
| 122 | + public static final int PH_MODE_FILL_CLIP = 1; | |
| 123 | + | |
| 124 | + public static abstract class ProcessHandler implements EndSubPathHandler { | |
| 125 | + DrawHandler dhnd; | |
| 126 | + int clipMode; | |
| 127 | + | |
| 128 | + public ProcessHandler(DrawHandler dhnd, | |
| 129 | + int clipMode) { | |
| 130 | + this.dhnd = dhnd; | |
| 131 | + this.clipMode = clipMode; | |
| 132 | + } | |
| 133 | + | |
| 134 | + public abstract void processFixedLine(int x1, int y1, | |
| 135 | + int x2, int y2, int [] pixelInfo, | |
| 136 | + boolean checkBounds, | |
| 137 | + boolean endSubPath); | |
| 138 | + } | |
| 139 | + | |
| 140 | + public static EndSubPathHandler noopEndSubPathHandler = | |
| 141 | + new EndSubPathHandler() { | |
| 142 | + public void processEndSubPath() { } | |
| 143 | + }; | |
| 144 | + | |
| 145 | + public static boolean fillPath(DrawHandler dhnd, Path2D.Float p2df, | |
| 146 | + int transX, int transY) | |
| 147 | + { | |
| 148 | + FillProcessHandler fhnd = new FillProcessHandler(dhnd); | |
| 149 | + if (!doProcessPath(fhnd, p2df, transX, transY)) { | |
| 150 | + return false; | |
| 151 | + } | |
| 152 | + FillPolygon(fhnd, p2df.getWindingRule()); | |
| 153 | + return true; | |
| 154 | + } | |
| 155 | + | |
| 156 | + public static boolean drawPath(DrawHandler dhnd, | |
| 157 | + EndSubPathHandler endSubPath, | |
| 158 | + Path2D.Float p2df, | |
| 159 | + int transX, int transY) | |
| 160 | + { | |
| 161 | + return doProcessPath(new DrawProcessHandler(dhnd, endSubPath), | |
| 162 | + p2df, transX, transY); | |
| 163 | + } | |
| 164 | + | |
| 165 | + public static boolean drawPath(DrawHandler dhnd, | |
| 166 | + Path2D.Float p2df, | |
| 167 | + int transX, int transY) | |
| 168 | + { | |
| 169 | + return doProcessPath(new DrawProcessHandler(dhnd, | |
| 170 | + noopEndSubPathHandler), | |
| 171 | + p2df, transX, transY); | |
| 172 | + } | |
| 173 | + | |
| 174 | + /* Private implementation of the rendering process */ | |
| 175 | + | |
| 176 | + /* Boundaries used for skipping huge path segments */ | |
| 177 | + private static final float UPPER_BND = Float.MAX_VALUE/4.0f; | |
| 178 | + private static final float LOWER_BND = -UPPER_BND; | |
| 179 | + | |
| 180 | + /* Precision (in bits) used in forward differencing */ | |
| 181 | + private static final int FWD_PREC = 7; | |
| 182 | + | |
| 183 | + /* Precision (in bits) used for the rounding in the midpoint test */ | |
| 184 | + private static final int MDP_PREC = 10; | |
| 185 | + | |
| 186 | + private static final int MDP_MULT = 1 << MDP_PREC; | |
| 187 | + private static final int MDP_HALF_MULT = MDP_MULT >> 1; | |
| 188 | + | |
| 189 | + /* Boundaries used for clipping large path segments (those are inside | |
| 190 | + * [UPPER/LOWER]_BND boundaries) | |
| 191 | + */ | |
| 192 | + private static final int UPPER_OUT_BND = 1 << (30 - MDP_PREC); | |
| 193 | + private static final int LOWER_OUT_BND = -UPPER_OUT_BND; | |
| 194 | + | |
| 195 | + | |
| 196 | + /* Calculation boundaries. They are used for switching to the more slow but | |
| 197 | + * allowing larger input values method of calculation of the initial values | |
| 198 | + * of the scan converted line segments inside the FillPolygon | |
| 199 | + */ | |
| 200 | + private static final float CALC_UBND = 1 << (30 - MDP_PREC); | |
| 201 | + private static final float CALC_LBND = -CALC_UBND; | |
| 202 | + | |
| 203 | + | |
| 204 | + /* Following constants are used for providing open boundaries of the | |
| 205 | + * intervals | |
| 206 | + */ | |
| 207 | + public static final int EPSFX = 1; | |
| 208 | + public static final float EPSF = ((float)EPSFX)/MDP_MULT; | |
| 209 | + | |
| 210 | + /* Bit mask used to separate whole part from the fraction part of the | |
| 211 | + * number | |
| 212 | + */ | |
| 213 | + private static final int MDP_W_MASK = -MDP_MULT; | |
| 214 | + | |
| 215 | + /* Bit mask used to separate fractional part from the whole part of the | |
| 216 | + * number | |
| 217 | + */ | |
| 218 | + private static final int MDP_F_MASK = MDP_MULT - 1; | |
| 219 | + | |
| 220 | + /* | |
| 221 | + * Constants for the forward differencing | |
| 222 | + * of the cubic and quad curves | |
| 223 | + */ | |
| 224 | + | |
| 225 | + /* Maximum size of the cubic curve (calculated as the size of the bounding | |
| 226 | + * box of the control points) which could be rendered without splitting | |
| 227 | + */ | |
| 228 | + private static final int MAX_CUB_SIZE = 256; | |
| 229 | + | |
| 230 | + /* Maximum size of the quad curve (calculated as the size of the bounding | |
| 231 | + * box of the control points) which could be rendered without splitting | |
| 232 | + */ | |
| 233 | + private static final int MAX_QUAD_SIZE = 1024; | |
| 234 | + | |
| 235 | + /* Default power of 2 steps used in the forward differencing. Here DF prefix | |
| 236 | + * stands for DeFault. Constants below are used as initial values for the | |
| 237 | + * adaptive forward differencing algorithm. | |
| 238 | + */ | |
| 239 | + private static final int DF_CUB_STEPS = 3; | |
| 240 | + private static final int DF_QUAD_STEPS = 2; | |
| 241 | + | |
| 242 | + /* Shift of the current point of the curve for preparing to the midpoint | |
| 243 | + * rounding | |
| 244 | + */ | |
| 245 | + private static final int DF_CUB_SHIFT = FWD_PREC + DF_CUB_STEPS*3 - | |
| 246 | + MDP_PREC; | |
| 247 | + private static final int DF_QUAD_SHIFT = FWD_PREC + DF_QUAD_STEPS*2 - | |
| 248 | + MDP_PREC; | |
| 249 | + | |
| 250 | + /* Default amount of steps of the forward differencing */ | |
| 251 | + private static final int DF_CUB_COUNT = (1<<DF_CUB_STEPS); | |
| 252 | + private static final int DF_QUAD_COUNT = (1<<DF_QUAD_STEPS); | |
| 253 | + | |
| 254 | + /* Default boundary constants used to check the necessity of the restepping | |
| 255 | + */ | |
| 256 | + private static final int DF_CUB_DEC_BND = 1<<DF_CUB_STEPS*3 + FWD_PREC + 2; | |
| 257 | + private static final int DF_CUB_INC_BND = 1<<DF_CUB_STEPS*3 + FWD_PREC - 1; | |
| 258 | + private static final int DF_QUAD_DEC_BND = 1<<DF_QUAD_STEPS*2 + | |
| 259 | + FWD_PREC + 2; | |
| 260 | + private static final int DF_QUAD_INC_BND = 1<<DF_QUAD_STEPS*2 + | |
| 261 | + FWD_PREC - 1; | |
| 262 | + | |
| 263 | + /* Multipliers for the coefficients of the polynomial form of the cubic and | |
| 264 | + * quad curves representation | |
| 265 | + */ | |
| 266 | + private static final int CUB_A_SHIFT = FWD_PREC; | |
| 267 | + private static final int CUB_B_SHIFT = (DF_CUB_STEPS + FWD_PREC + 1); | |
| 268 | + private static final int CUB_C_SHIFT = (DF_CUB_STEPS*2 + FWD_PREC); | |
| 269 | + | |
| 270 | + private static final int CUB_A_MDP_MULT = (1<<CUB_A_SHIFT); | |
| 271 | + private static final int CUB_B_MDP_MULT = (1<<CUB_B_SHIFT); | |
| 272 | + private static final int CUB_C_MDP_MULT = (1<<CUB_C_SHIFT); | |
| 273 | + | |
| 274 | + private static final int QUAD_A_SHIFT = FWD_PREC; | |
| 275 | + private static final int QUAD_B_SHIFT = (DF_QUAD_STEPS + FWD_PREC); | |
| 276 | + | |
| 277 | + private static final int QUAD_A_MDP_MULT = (1<<QUAD_A_SHIFT); | |
| 278 | + private static final int QUAD_B_MDP_MULT = (1<<QUAD_B_SHIFT); | |
| 279 | + | |
| 280 | + /* Clipping macros for drawing and filling algorithms */ | |
| 281 | + private static float CLIP(float a1, float b1, float a2, float b2, | |
| 282 | + double t) { | |
| 283 | + return (float)(b1 + (double)(t - a1)*(b2 - b1) / (a2 - a1)); | |
| 284 | + } | |
| 285 | + | |
| 286 | + private static int CLIP(int a1, int b1, int a2, int b2, double t) { | |
| 287 | + return (int)(b1 + (double)(t - a1)*(b2 - b1) / (a2 - a1)); | |
| 288 | + } | |
| 289 | + | |
| 290 | + | |
| 291 | + private static final int CRES_MIN_CLIPPED = 0; | |
| 292 | + private static final int CRES_MAX_CLIPPED = 1; | |
| 293 | + private static final int CRES_NOT_CLIPPED = 3; | |
| 294 | + private static final int CRES_INVISIBLE = 4; | |
| 295 | + | |
| 296 | + private static boolean IS_CLIPPED(int res) { | |
| 297 | + return res == CRES_MIN_CLIPPED || res == CRES_MAX_CLIPPED; | |
| 298 | + } | |
| 299 | + | |
| 300 | + /* This is java implementation of the macro from ProcessGeneralPath.c. | |
| 301 | + * To keep the logic of the java code similar to the native one | |
| 302 | + * array and set of indexes are used to point out the data. | |
| 303 | + */ | |
| 304 | + private static int TESTANDCLIP(float LINE_MIN, float LINE_MAX, float[] c, | |
| 305 | + int a1, int b1, int a2, int b2) { | |
| 306 | + double t; | |
| 307 | + int res = CRES_NOT_CLIPPED; | |
| 308 | + if (c[a1] < (LINE_MIN) || c[a1] > (LINE_MAX)) { | |
| 309 | + if (c[a1] < (LINE_MIN)) { | |
| 310 | + if (c[a2] < (LINE_MIN)) { | |
| 311 | + return CRES_INVISIBLE; | |
| 312 | + }; | |
| 313 | + res = CRES_MIN_CLIPPED; | |
| 314 | + t = (LINE_MIN); | |
| 315 | + } else { | |
| 316 | + if (c[a2] > (LINE_MAX)) { | |
| 317 | + return CRES_INVISIBLE; | |
| 318 | + }; | |
| 319 | + res = CRES_MAX_CLIPPED; | |
| 320 | + t = (LINE_MAX); | |
| 321 | + } | |
| 322 | + c[b1] = CLIP(c[a1], c[b1], c[a2], c[b2], t); | |
| 323 | + c[a1] = (float)t; | |
| 324 | + } | |
| 325 | + return res; | |
| 326 | + } | |
| 327 | + | |
| 328 | + /* Integer version of the method above */ | |
| 329 | + private static int TESTANDCLIP(int LINE_MIN, int LINE_MAX, int[] c, | |
| 330 | + int a1, int b1, int a2, int b2) { | |
| 331 | + double t; | |
| 332 | + int res = CRES_NOT_CLIPPED; | |
| 333 | + if (c[a1] < (LINE_MIN) || c[a1] > (LINE_MAX)) { | |
| 334 | + if (c[a1] < (LINE_MIN)) { | |
| 335 | + if (c[a2] < (LINE_MIN)) { | |
| 336 | + return CRES_INVISIBLE; | |
| 337 | + }; | |
| 338 | + res = CRES_MIN_CLIPPED; | |
| 339 | + t = (LINE_MIN); | |
| 340 | + } else { | |
| 341 | + if (c[a2] > (LINE_MAX)) { | |
| 342 | + return CRES_INVISIBLE; | |
| 343 | + }; | |
| 344 | + res = CRES_MAX_CLIPPED; | |
| 345 | + t = (LINE_MAX); | |
| 346 | + } | |
| 347 | + c[b1] = CLIP(c[a1], c[b1], c[a2], c[b2], t); | |
| 348 | + c[a1] = (int)t; | |
| 349 | + } | |
| 350 | + return res; | |
| 351 | + } | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + /* Following method is used for clipping and clumping filled shapes. | |
| 356 | + * An example of this process is shown on the picture below: | |
| 357 | + * ----+ ----+ | |
| 358 | + * |/ | |/ | | |
| 359 | + * + | + | | |
| 360 | + * /| | I | | |
| 361 | + * / | | I | | |
| 362 | + * | | | ===> I | | |
| 363 | + * \ | | I | | |
| 364 | + * \| | I | | |
| 365 | + * + | + | | |
| 366 | + * |\ | |\ | | |
| 367 | + * | ----+ | ----+ | |
| 368 | + * boundary boundary | |
| 369 | + * | |
| 370 | + * We can only perform clipping in case of right side of the output area | |
| 371 | + * because all segments passed out the right boundary don't influence on the | |
| 372 | + * result of scan conversion algorithm (it correctly handles half open | |
| 373 | + * contours). | |
| 374 | + * | |
| 375 | + * This is java implementation of the macro from ProcessGeneralPath.c. | |
| 376 | + * To keep the logic of the java code similar to the native one | |
| 377 | + * array and set of indexes are used to point out the data. | |
| 378 | + * | |
| 379 | + */ | |
| 380 | + private static int CLIPCLAMP(float LINE_MIN, float LINE_MAX, float[] c, | |
| 381 | + int a1, int b1, int a2, int b2, | |
| 382 | + int a3, int b3) { | |
| 383 | + c[a3] = c[a1]; | |
| 384 | + c[b3] = c[b1]; | |
| 385 | + int res = TESTANDCLIP(LINE_MIN, LINE_MAX, c, a1, b1, a2, b2); | |
| 386 | + if (res == CRES_MIN_CLIPPED) { | |
| 387 | + c[a3] = c[a1]; | |
| 388 | + } else if (res == CRES_MAX_CLIPPED) { | |
| 389 | + c[a3] = c[a1]; | |
| 390 | + res = CRES_MAX_CLIPPED; | |
| 391 | + } else if (res == CRES_INVISIBLE) { | |
| 392 | + if (c[a1] > LINE_MAX) { | |
| 393 | + res = CRES_INVISIBLE; | |
| 394 | + } else { | |
| 395 | + c[a1] = LINE_MIN; | |
| 396 | + c[a2] = LINE_MIN; | |
| 397 | + res = CRES_NOT_CLIPPED; | |
| 398 | + } | |
| 399 | + } | |
| 400 | + return res; | |
| 401 | + } | |
| 402 | + | |
| 403 | + /* Integer version of the method above */ | |
| 404 | + private static int CLIPCLAMP(int LINE_MIN, int LINE_MAX, int[] c, | |
| 405 | + int a1, int b1, int a2, int b2, | |
| 406 | + int a3, int b3) { | |
| 407 | + c[a3] = c[a1]; | |
| 408 | + c[b3] = c[b1]; | |
| 409 | + int res = TESTANDCLIP(LINE_MIN, LINE_MAX, c, a1, b1, a2, b2); | |
| 410 | + if (res == CRES_MIN_CLIPPED) { | |
| 411 | + c[a3] = c[a1]; | |
| 412 | + } else if (res == CRES_MAX_CLIPPED) { | |
| 413 | + c[a3] = c[a1]; | |
| 414 | + res = CRES_MAX_CLIPPED; | |
| 415 | + } else if (res == CRES_INVISIBLE) { | |
| 416 | + if (c[a1] > LINE_MAX) { | |
| 417 | + res = CRES_INVISIBLE; | |
| 418 | + } else { | |
| 419 | + c[a1] = LINE_MIN; | |
| 420 | + c[a2] = LINE_MIN; | |
| 421 | + res = CRES_NOT_CLIPPED; | |
| 422 | + } | |
| 423 | + } | |
| 424 | + return res; | |
| 425 | + } | |
| 426 | + | |
| 427 | + private static class DrawProcessHandler extends ProcessHandler { | |
| 428 | + | |
| 429 | + EndSubPathHandler processESP; | |
| 430 | + | |
| 431 | + public DrawProcessHandler(DrawHandler dhnd, | |
| 432 | + EndSubPathHandler processESP) { | |
| 433 | + super(dhnd, PH_MODE_DRAW_CLIP); | |
| 434 | + this.dhnd = dhnd; | |
| 435 | + this.processESP = processESP; | |
| 436 | + } | |
| 437 | + | |
| 438 | + public void processEndSubPath() { | |
| 439 | + processESP.processEndSubPath(); | |
| 440 | + } | |
| 441 | + | |
| 442 | + void PROCESS_LINE(int fX0, int fY0, int fX1, int fY1, | |
| 443 | + boolean checkBounds, int[] pixelInfo) { | |
| 444 | + int X0 = fX0 >> MDP_PREC; | |
| 445 | + int Y0 = fY0 >> MDP_PREC; | |
| 446 | + int X1 = fX1 >> MDP_PREC; | |
| 447 | + int Y1 = fY1 >> MDP_PREC; | |
| 448 | + | |
| 449 | + /* Handling lines having just one pixel */ | |
| 450 | + if (((X0^X1) | (Y0^Y1)) == 0) { | |
| 451 | + if (checkBounds && | |
| 452 | + (dhnd.yMin > Y0 || | |
| 453 | + dhnd.yMax <= Y0 || | |
| 454 | + dhnd.xMin > X0 || | |
| 455 | + dhnd.xMax <= X0)) return; | |
| 456 | + | |
| 457 | + if (pixelInfo[0] == 0) { | |
| 458 | + pixelInfo[0] = 1; | |
| 459 | + pixelInfo[1] = X0; | |
| 460 | + pixelInfo[2] = Y0; | |
| 461 | + pixelInfo[3] = X0; | |
| 462 | + pixelInfo[4] = Y0; | |
| 463 | + dhnd.drawPixel(X0, Y0); | |
| 464 | + } else if ((X0 != pixelInfo[3] || Y0 != pixelInfo[4]) && | |
| 465 | + (X0 != pixelInfo[1] || Y0 != pixelInfo[2])) { | |
| 466 | + dhnd.drawPixel(X0, Y0); | |
| 467 | + pixelInfo[3] = X0; | |
| 468 | + pixelInfo[4] = Y0; | |
| 469 | + } | |
| 470 | + return; | |
| 471 | + } | |
| 472 | + | |
| 473 | + if (!checkBounds || | |
| 474 | + (dhnd.yMin <= Y0 && | |
| 475 | + dhnd.yMax > Y0 && | |
| 476 | + dhnd.xMin <= X0 && | |
| 477 | + dhnd.xMax > X0)) | |
| 478 | + { | |
| 479 | + /* Switch off first pixel of the line before drawing */ | |
| 480 | + if (pixelInfo[0] == 1 && | |
| 481 | + ((pixelInfo[1] == X0 && pixelInfo[2] == Y0) || | |
| 482 | + (pixelInfo[3] == X0 && pixelInfo[4] == Y0))) | |
| 483 | + { | |
| 484 | + dhnd.drawPixel(X0, Y0); | |
| 485 | + } | |
| 486 | + } | |
| 487 | + | |
| 488 | + dhnd.drawLine(X0, Y0, X1, Y1); | |
| 489 | + | |
| 490 | + if (pixelInfo[0] == 0) { | |
| 491 | + pixelInfo[0] = 1; | |
| 492 | + pixelInfo[1] = X0; | |
| 493 | + pixelInfo[2] = Y0; | |
| 494 | + pixelInfo[3] = X0; | |
| 495 | + pixelInfo[4] = Y0; | |
| 496 | + } | |
| 497 | + | |
| 498 | + /* Switch on last pixel of the line if it was already | |
| 499 | + * drawn during rendering of the previous segments | |
| 500 | + */ | |
| 501 | + if ((pixelInfo[1] == X1 && pixelInfo[2] == Y1) || | |
| 502 | + (pixelInfo[3] == X1 && pixelInfo[4] == Y1)) | |
| 503 | + { | |
| 504 | + if (checkBounds && | |
| 505 | + (dhnd.yMin > Y1 || | |
| 506 | + dhnd.yMax <= Y1 || | |
| 507 | + dhnd.xMin > X1 || | |
| 508 | + dhnd.xMax <= X1)) { | |
| 509 | + return; | |
| 510 | + } | |
| 511 | + | |
| 512 | + dhnd.drawPixel(X1, Y1); | |
| 513 | + } | |
| 514 | + pixelInfo[3] = X1; | |
| 515 | + pixelInfo[4] = Y1; | |
| 516 | + } | |
| 517 | + | |
| 518 | + void PROCESS_POINT(int fX, int fY, boolean checkBounds, | |
| 519 | + int[] pixelInfo) { | |
| 520 | + int _X = fX>> MDP_PREC; | |
| 521 | + int _Y = fY>> MDP_PREC; | |
| 522 | + if (checkBounds && | |
| 523 | + (dhnd.yMin > _Y || | |
| 524 | + dhnd.yMax <= _Y || | |
| 525 | + dhnd.xMin > _X || | |
| 526 | + dhnd.xMax <= _X)) return; | |
| 527 | + /* | |
| 528 | + * (_X,_Y) should be inside boundaries | |
| 529 | + * | |
| 530 | + * assert(dhnd.yMin <= _Y && | |
| 531 | + * dhnd.yMax > _Y && | |
| 532 | + * dhnd.xMin <= _X && | |
| 533 | + * dhnd.xMax > _X); | |
| 534 | + * | |
| 535 | + */ | |
| 536 | + if (pixelInfo[0] == 0) { | |
| 537 | + pixelInfo[0] = 1; | |
| 538 | + pixelInfo[1] = _X; | |
| 539 | + pixelInfo[2] = _Y; | |
| 540 | + pixelInfo[3] = _X; | |
| 541 | + pixelInfo[4] = _Y; | |
| 542 | + dhnd.drawPixel(_X, _Y); | |
| 543 | + } else if ((_X != pixelInfo[3] || _Y != pixelInfo[4]) && | |
| 544 | + (_X != pixelInfo[1] || _Y != pixelInfo[2])) { | |
| 545 | + dhnd.drawPixel(_X, _Y); | |
| 546 | + pixelInfo[3] = _X; | |
| 547 | + pixelInfo[4] = _Y; | |
| 548 | + } | |
| 549 | + } | |
| 550 | + | |
| 551 | + /* Drawing line with subpixel endpoints | |
| 552 | + * | |
| 553 | + * (x1, y1), (x2, y2) - fixed point coordinates of the endpoints | |
| 554 | + * with MDP_PREC bits for the fractional part | |
| 555 | + * | |
| 556 | + * pixelInfo - structure which keeps drawing info for avoiding | |
| 557 | + * multiple drawing at the same position on the | |
| 558 | + * screen (required for the XOR mode of drawing) | |
| 559 | + * | |
| 560 | + * pixelInfo[0] - state of the drawing | |
| 561 | + * 0 - no pixel drawn between | |
| 562 | + * moveTo/close of the path | |
| 563 | + * 1 - there are drawn pixels | |
| 564 | + * | |
| 565 | + * pixelInfo[1,2] - first pixel of the path | |
| 566 | + * between moveTo/close of the | |
| 567 | + * path | |
| 568 | + * | |
| 569 | + * pixelInfo[3,4] - last drawn pixel between | |
| 570 | + * moveTo/close of the path | |
| 571 | + * | |
| 572 | + * checkBounds - flag showing necessity of checking the clip | |
| 573 | + * | |
| 574 | + */ | |
| 575 | + public void processFixedLine(int x1, int y1, int x2, int y2, | |
| 576 | + int[] pixelInfo, boolean checkBounds, | |
| 577 | + boolean endSubPath) { | |
| 578 | + | |
| 579 | + /* Checking if line is inside a (X,Y),(X+MDP_MULT,Y+MDP_MULT) box */ | |
| 580 | + int c = ((x1 ^ x2) | (y1 ^ y2)); | |
| 581 | + int rx1, ry1, rx2, ry2; | |
| 582 | + if ((c & MDP_W_MASK) == 0) { | |
| 583 | + /* Checking for the segments with integer coordinates having | |
| 584 | + * the same start and end points | |
| 585 | + */ | |
| 586 | + if (c == 0) { | |
| 587 | + PROCESS_POINT(x1 + MDP_HALF_MULT, y1 + MDP_HALF_MULT, | |
| 588 | + checkBounds, pixelInfo); | |
| 589 | + } | |
| 590 | + return; | |
| 591 | + } | |
| 592 | + | |
| 593 | + if (x1 == x2 || y1 == y2) { | |
| 594 | + rx1 = x1 + MDP_HALF_MULT; | |
| 595 | + rx2 = x2 + MDP_HALF_MULT; | |
| 596 | + ry1 = y1 + MDP_HALF_MULT; | |
| 597 | + ry2 = y2 + MDP_HALF_MULT; | |
| 598 | + } else { | |
| 599 | + /* Neither dx nor dy can be zero because of the check above */ | |
| 600 | + int dx = x2 - x1; | |
| 601 | + int dy = y2 - y1; | |
| 602 | + | |
| 603 | + /* Floor of x1, y1, x2, y2 */ | |
| 604 | + int fx1 = x1 & MDP_W_MASK; | |
| 605 | + int fy1 = y1 & MDP_W_MASK; | |
| 606 | + int fx2 = x2 & MDP_W_MASK; | |
| 607 | + int fy2 = y2 & MDP_W_MASK; | |
| 608 | + | |
| 609 | + /* Processing first endpoint */ | |
| 610 | + if (fx1 == x1 || fy1 == y1) { | |
| 611 | + /* Adding MDP_HALF_MULT to the [xy]1 if f[xy]1 == [xy]1 | |
| 612 | + * will not affect the result | |
| 613 | + */ | |
| 614 | + rx1 = x1 + MDP_HALF_MULT; | |
| 615 | + ry1 = y1 + MDP_HALF_MULT; | |
| 616 | + } else { | |
| 617 | + /* Boundary at the direction from (x1,y1) to (x2,y2) */ | |
| 618 | + int bx1 = (x1 < x2) ? fx1 + MDP_MULT : fx1; | |
| 619 | + int by1 = (y1 < y2) ? fy1 + MDP_MULT : fy1; | |
| 620 | + | |
| 621 | + /* intersection with column bx1 */ | |
| 622 | + int cross = y1 + ((bx1 - x1)*dy)/dx; | |
| 623 | + if (cross >= fy1 && cross <= fy1 + MDP_MULT) { | |
| 624 | + rx1 = bx1; | |
| 625 | + ry1 = cross + MDP_HALF_MULT; | |
| 626 | + } else { | |
| 627 | + /* intersection with row by1 */ | |
| 628 | + cross = x1 + ((by1 - y1)*dx)/dy; | |
| 629 | + rx1 = cross + MDP_HALF_MULT; | |
| 630 | + ry1 = by1; | |
| 631 | + } | |
| 632 | + } | |
| 633 | + | |
| 634 | + /* Processing second endpoint */ | |
| 635 | + if (fx2 == x2 || fy2 == y2) { | |
| 636 | + /* Adding MDP_HALF_MULT to the [xy]2 if f[xy]2 == [xy]2 | |
| 637 | + * will not affect the result | |
| 638 | + */ | |
| 639 | + rx2 = x2 + MDP_HALF_MULT; | |
| 640 | + ry2 = y2 + MDP_HALF_MULT; | |
| 641 | + } else { | |
| 642 | + /* Boundary at the direction from (x2,y2) to (x1,y1) */ | |
| 643 | + int bx2 = (x1 > x2) ? fx2 + MDP_MULT : fx2; | |
| 644 | + int by2 = (y1 > y2) ? fy2 + MDP_MULT : fy2; | |
| 645 | + | |
| 646 | + /* intersection with column bx2 */ | |
| 647 | + int cross = y2 + ((bx2 - x2)*dy)/dx; | |
| 648 | + if (cross >= fy2 && cross <= fy2 + MDP_MULT) { | |
| 649 | + rx2 = bx2; | |
| 650 | + ry2 = cross + MDP_HALF_MULT; | |
| 651 | + } else { | |
| 652 | + /* intersection with row by2 */ | |
| 653 | + cross = x2 + ((by2 - y2)*dx)/dy; | |
| 654 | + rx2 = cross + MDP_HALF_MULT; | |
| 655 | + ry2 = by2; | |
| 656 | + } | |
| 657 | + } | |
| 658 | + } | |
| 659 | + PROCESS_LINE(rx1, ry1, rx2, ry2, checkBounds, pixelInfo); | |
| 660 | + } | |
| 661 | + } | |
| 662 | + | |
| 663 | + /* Performing drawing of the monotonic in X and Y quadratic curves with | |
| 664 | + * sizes less than MAX_QUAD_SIZE by using forward differencing method of | |
| 665 | + * calculation. See comments to the DrawMonotonicQuad in the | |
| 666 | + * ProcessGeneralPath.c | |
| 667 | + */ | |
| 668 | + private static void DrawMonotonicQuad(ProcessHandler hnd, | |
| 669 | + float[] coords, | |
| 670 | + boolean checkBounds, | |
| 671 | + int[] pixelInfo) { | |
| 672 | + | |
| 673 | + int x0 = (int)(coords[0]*MDP_MULT); | |
| 674 | + int y0 = (int)(coords[1]*MDP_MULT); | |
| 675 | + | |
| 676 | + int xe = (int)(coords[4]*MDP_MULT); | |
| 677 | + int ye = (int)(coords[5]*MDP_MULT); | |
| 678 | + | |
| 679 | + /* Extracting fractional part of coordinates of first control point */ | |
| 680 | + int px = (x0 & (~MDP_W_MASK)) << DF_QUAD_SHIFT; | |
| 681 | + int py = (y0 & (~MDP_W_MASK)) << DF_QUAD_SHIFT; | |
| 682 | + | |
| 683 | + /* Setting default amount of steps */ | |
| 684 | + int count = DF_QUAD_COUNT; | |
| 685 | + | |
| 686 | + /* Setting default shift for preparing to the midpoint rounding */ | |
| 687 | + int shift = DF_QUAD_SHIFT; | |
| 688 | + | |
| 689 | + int ax = (int)((coords[0] - 2*coords[2] + | |
| 690 | + coords[4])*QUAD_A_MDP_MULT); | |
| 691 | + int ay = (int)((coords[1] - 2*coords[3] + | |
| 692 | + coords[5])*QUAD_A_MDP_MULT); | |
| 693 | + | |
| 694 | + int bx = (int)((-2*coords[0] + 2*coords[2])*QUAD_B_MDP_MULT); | |
| 695 | + int by = (int)((-2*coords[1] + 2*coords[3])*QUAD_B_MDP_MULT); | |
| 696 | + | |
| 697 | + int ddpx = 2*ax; | |
| 698 | + int ddpy = 2*ay; | |
| 699 | + | |
| 700 | + int dpx = ax + bx; | |
| 701 | + int dpy = ay + by; | |
| 702 | + | |
| 703 | + int x1, y1; | |
| 704 | + | |
| 705 | + int x2 = x0; | |
| 706 | + int y2 = y0; | |
| 707 | + | |
| 708 | + int maxDD = Math.max(Math.abs(ddpx),Math.abs(ddpy)); | |
| 709 | + | |
| 710 | + int dx = xe - x0; | |
| 711 | + int dy = ye - y0; | |
| 712 | + | |
| 713 | + int x0w = x0 & MDP_W_MASK; | |
| 714 | + int y0w = y0 & MDP_W_MASK; | |
| 715 | + | |
| 716 | + /* Perform decreasing step in 2 times if slope of the first forward | |
| 717 | + * difference changes too quickly (more than a pixel per step in X or Y | |
| 718 | + * direction). We can perform adjusting of the step size before the | |
| 719 | + * rendering loop because the curvature of the quad curve remains the | |
| 720 | + * same along all the curve | |
| 721 | + */ | |
| 722 | + while (maxDD > DF_QUAD_DEC_BND) { | |
| 723 | + dpx = (dpx<<1) - ax; | |
| 724 | + dpy = (dpy<<1) - ay; | |
| 725 | + count <<= 1; | |
| 726 | + maxDD >>= 2; | |
| 727 | + px <<=2; | |
| 728 | + py <<=2; | |
| 729 | + shift += 2; | |
| 730 | + } | |
| 731 | + | |
| 732 | + while(count-- > 1) { | |
| 733 | + px += dpx; | |
| 734 | + py += dpy; | |
| 735 | + | |
| 736 | + dpx += ddpx; | |
| 737 | + dpy += ddpy; | |
| 738 | + | |
| 739 | + x1 = x2; | |
| 740 | + y1 = y2; | |
| 741 | + | |
| 742 | + x2 = x0w + (px >> shift); | |
| 743 | + y2 = y0w + (py >> shift); | |
| 744 | + | |
| 745 | + /* Checking that we are not running out of the endpoint and bounding | |
| 746 | + * violating coordinate. The check is pretty simple because the | |
| 747 | + * curve passed to the DrawCubic already splitted into the | |
| 748 | + * monotonic in X and Y pieces | |
| 749 | + */ | |
| 750 | + | |
| 751 | + /* Bounding x2 by xe */ | |
| 752 | + if (((xe-x2)^dx) < 0) { | |
| 753 | + x2 = xe; | |
| 754 | + } | |
| 755 | + | |
| 756 | + /* Bounding y2 by ye */ | |
| 757 | + if (((ye-y2)^dy) < 0) { | |
| 758 | + y2 = ye; | |
| 759 | + } | |
| 760 | + | |
| 761 | + hnd.processFixedLine(x1, y1, x2, y2, pixelInfo, checkBounds, false); | |
| 762 | + } | |
| 763 | + | |
| 764 | + /* We are performing one step less than necessary and use actual | |
| 765 | + * (xe,ye) endpoint of the curve instead of calculated. This prevent us | |
| 766 | + * from running above the curve endpoint due to the accumulated errors | |
| 767 | + * during the iterations. | |
| 768 | + */ | |
| 769 | + | |
| 770 | + hnd.processFixedLine(x2, y2, xe, ye, pixelInfo, checkBounds, false); | |
| 771 | + } | |
| 772 | + | |
| 773 | + /* | |
| 774 | + * Checking size of the quad curves and split them if necessary. | |
| 775 | + * Calling DrawMonotonicQuad for the curves of the appropriate size. | |
| 776 | + * Note: coords array could be changed | |
| 777 | + */ | |
| 778 | + private static void ProcessMonotonicQuad(ProcessHandler hnd, | |
| 779 | + float[] coords, | |
| 780 | + int[] pixelInfo) { | |
| 781 | + | |
| 782 | + float[] coords1 = new float[6]; | |
| 783 | + float tx, ty; | |
| 784 | + float xMin, yMin, xMax, yMax; | |
| 785 | + | |
| 786 | + xMin = xMax = coords[0]; | |
| 787 | + yMin = yMax = coords[1]; | |
| 788 | + for (int i = 2; i < 6; i += 2) { | |
| 789 | + xMin = (xMin > coords[i])? coords[i] : xMin; | |
| 790 | + xMax = (xMax < coords[i])? coords[i] : xMax; | |
| 791 | + yMin = (yMin > coords[i + 1])? coords[i + 1] : yMin; | |
| 792 | + yMax = (yMax < coords[i + 1])? coords[i + 1] : yMax; | |
| 793 | + } | |
| 794 | + | |
| 795 | + if (hnd.clipMode == PH_MODE_DRAW_CLIP) { | |
| 796 | + | |
| 797 | + /* In case of drawing we could just skip curves which are | |
| 798 | + * completely out of bounds | |
| 799 | + */ | |
| 800 | + if (hnd.dhnd.xMaxf < xMin || hnd.dhnd.xMinf > xMax || | |
| 801 | + hnd.dhnd.yMaxf < yMin || hnd.dhnd.yMinf > yMax) { | |
| 802 | + return; | |
| 803 | + } | |
| 804 | + } else { | |
| 805 | + | |
| 806 | + /* In case of filling we could skip curves which are above, | |
| 807 | + * below and behind the right boundary of the visible area | |
| 808 | + */ | |
| 809 | + | |
| 810 | + if (hnd.dhnd.yMaxf < yMin || hnd.dhnd.yMinf > yMax || | |
| 811 | + hnd.dhnd.xMaxf < xMin) | |
| 812 | + { | |
| 813 | + return; | |
| 814 | + } | |
| 815 | + | |
| 816 | + /* We could clamp x coordinates to the corresponding boundary | |
| 817 | + * if the curve is completely behind the left one | |
| 818 | + */ | |
| 819 | + | |
| 820 | + if (hnd.dhnd.xMinf > xMax) { | |
| 821 | + coords[0] = coords[2] = coords[4] = hnd.dhnd.xMinf; | |
| 822 | + } | |
| 823 | + } | |
| 824 | + | |
| 825 | + if (xMax - xMin > MAX_QUAD_SIZE || yMax - yMin > MAX_QUAD_SIZE) { | |
| 826 | + coords1[4] = coords[4]; | |
| 827 | + coords1[5] = coords[5]; | |
| 828 | + coords1[2] = (coords[2] + coords[4])/2.0f; | |
| 829 | + coords1[3] = (coords[3] + coords[5])/2.0f; | |
| 830 | + coords[2] = (coords[0] + coords[2])/2.0f; | |
| 831 | + coords[3] = (coords[1] + coords[3])/2.0f; | |
| 832 | + coords[4] = coords1[0] = (coords[2] + coords1[2])/2.0f; | |
| 833 | + coords[5] = coords1[1] = (coords[3] + coords1[3])/2.0f; | |
| 834 | + | |
| 835 | + ProcessMonotonicQuad(hnd, coords, pixelInfo); | |
| 836 | + | |
| 837 | + ProcessMonotonicQuad(hnd, coords1, pixelInfo); | |
| 838 | + } else { | |
| 839 | + DrawMonotonicQuad(hnd, coords, | |
| 840 | + /* Set checkBounds parameter if curve intersects | |
| 841 | + * boundary of the visible area. We know that the | |
| 842 | + * curve is visible, so the check is pretty | |
| 843 | + * simple | |
| 844 | + */ | |
| 845 | + hnd.dhnd.xMinf >= xMin || | |
| 846 | + hnd.dhnd.xMaxf <= xMax || | |
| 847 | + hnd.dhnd.yMinf >= yMin || | |
| 848 | + hnd.dhnd.yMaxf <= yMax, | |
| 849 | + pixelInfo); | |
| 850 | + } | |
| 851 | + } | |
| 852 | + | |
| 853 | + /* | |
| 854 | + * Split quadratic curve into monotonic in X and Y parts. Calling | |
| 855 | + * ProcessMonotonicQuad for each monotonic piece of the curve. | |
| 856 | + * Note: coords array could be changed | |
| 857 | + */ | |
| 858 | + private static void ProcessQuad(ProcessHandler hnd, float[] coords, | |
| 859 | + int[] pixelInfo) { | |
| 860 | + /* Temporary array for holding parameters corresponding to the extreme | |
| 861 | + * in X and Y points | |
| 862 | + */ | |
| 863 | + double params[] = new double[2]; | |
| 864 | + int cnt = 0; | |
| 865 | + double param; | |
| 866 | + | |
| 867 | + /* Simple check for monotonicity in X before searching for the extreme | |
| 868 | + * points of the X(t) function. We first check if the curve is | |
| 869 | + * monotonic in X by seeing if all of the X coordinates are strongly | |
| 870 | + * ordered. | |
| 871 | + */ | |
| 872 | + if ((coords[0] > coords[2] || coords[2] > coords[4]) && | |
| 873 | + (coords[0] < coords[2] || coords[2] < coords[4])) | |
| 874 | + { | |
| 875 | + /* Searching for extreme points of the X(t) function by solving | |
| 876 | + * dX(t) | |
| 877 | + * ---- = 0 equation | |
| 878 | + * dt | |
| 879 | + */ | |
| 880 | + double ax = coords[0] - 2*coords[2] + coords[4]; | |
| 881 | + if (ax != 0) { | |
| 882 | + /* Calculating root of the following equation | |
| 883 | + * ax*t + bx = 0 | |
| 884 | + */ | |
| 885 | + double bx = coords[0] - coords[2]; | |
| 886 | + | |
| 887 | + param = bx/ax; | |
| 888 | + if (param < 1.0 && param > 0.0) { | |
| 889 | + params[cnt++] = param; | |
| 890 | + } | |
| 891 | + } | |
| 892 | + } | |
| 893 | + | |
| 894 | + /* Simple check for monotonicity in Y before searching for the extreme | |
| 895 | + * points of the Y(t) function. We first check if the curve is | |
| 896 | + * monotonic in Y by seeing if all of the Y coordinates are strongly | |
| 897 | + * ordered. | |
| 898 | + */ | |
| 899 | + if ((coords[1] > coords[3] || coords[3] > coords[5]) && | |
| 900 | + (coords[1] < coords[3] || coords[3] < coords[5])) | |
| 901 | + { | |
| 902 | + /* Searching for extreme points of the Y(t) function by solving | |
| 903 | + * dY(t) | |
| 904 | + * ----- = 0 equation | |
| 905 | + * dt | |
| 906 | + */ | |
| 907 | + double ay = coords[1] - 2*coords[3] + coords[5]; | |
| 908 | + | |
| 909 | + if (ay != 0) { | |
| 910 | + /* Calculating root of the following equation | |
| 911 | + * ay*t + by = 0 | |
| 912 | + */ | |
| 913 | + double by = coords[1] - coords[3]; | |
| 914 | + | |
| 915 | + param = by/ay; | |
| 916 | + if (param < 1.0 && param > 0.0) { | |
| 917 | + if (cnt > 0) { | |
| 918 | + /* Inserting parameter only if it differs from | |
| 919 | + * already stored | |
| 920 | + */ | |
| 921 | + if (params[0] > param) { | |
| 922 | + params[cnt++] = params[0]; | |
| 923 | + params[0] = param; | |
| 924 | + } else if (params[0] < param) { | |
| 925 | + params[cnt++] = param; | |
| 926 | + } | |
| 927 | + } else { | |
| 928 | + params[cnt++] = param; | |
| 929 | + } | |
| 930 | + } | |
| 931 | + } | |
| 932 | + } | |
| 933 | + | |
| 934 | + /* Processing obtained monotonic parts */ | |
| 935 | + switch(cnt) { | |
| 936 | + case 0: | |
| 937 | + break; | |
| 938 | + case 1: | |
| 939 | + ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo, | |
| 940 | + (float)params[0]); | |
| 941 | + break; | |
| 942 | + case 2: | |
| 943 | + ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo, | |
| 944 | + (float)params[0]); | |
| 945 | + param = params[1] - params[0]; | |
| 946 | + if (param > 0) { | |
| 947 | + ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo, | |
| 948 | + /* Scale parameter to match with | |
| 949 | + * rest of the curve | |
| 950 | + */ | |
| 951 | + (float)(param/(1.0 - params[0]))); | |
| 952 | + } | |
| 953 | + break; | |
| 954 | + } | |
| 955 | + | |
| 956 | + ProcessMonotonicQuad(hnd,coords,pixelInfo); | |
| 957 | + } | |
| 958 | + | |
| 959 | + /* | |
| 960 | + * Bite the piece of the quadratic curve from start point till the point | |
| 961 | + * corresponding to the specified parameter then call ProcessQuad for the | |
| 962 | + * bitten part. | |
| 963 | + * Note: coords array will be changed | |
| 964 | + */ | |
| 965 | + private static void ProcessFirstMonotonicPartOfQuad(ProcessHandler hnd, | |
| 966 | + float[] coords, | |
| 967 | + int[] pixelInfo, | |
| 968 | + float t) { | |
| 969 | + float[] coords1 = new float[6]; | |
| 970 | + | |
| 971 | + coords1[0] = coords[0]; | |
| 972 | + coords1[1] = coords[1]; | |
| 973 | + coords1[2] = coords[0] + t*(coords[2] - coords[0]); | |
| 974 | + coords1[3] = coords[1] + t*(coords[3] - coords[1]); | |
| 975 | + coords[2] = coords[2] + t*(coords[4] - coords[2]); | |
| 976 | + coords[3] = coords[3] + t*(coords[5] - coords[3]); | |
| 977 | + coords[0] = coords1[4] = coords1[2] + t*(coords[2] - coords1[2]); | |
| 978 | + coords[1] = coords1[5] = coords1[3] + t*(coords[3] - coords1[3]); | |
| 979 | + | |
| 980 | + ProcessMonotonicQuad(hnd, coords1, pixelInfo); | |
| 981 | + } | |
| 982 | + | |
| 983 | + /* Performing drawing of the monotonic in X and Y cubic curves with sizes | |
| 984 | + * less than MAX_CUB_SIZE by using forward differencing method of | |
| 985 | + * calculation. See comments to the DrawMonotonicCubic in the | |
| 986 | + * ProcessGeneralPath.c | |
| 987 | + */ | |
| 988 | + private static void DrawMonotonicCubic(ProcessHandler hnd, | |
| 989 | + float[] coords, | |
| 990 | + boolean checkBounds, | |
| 991 | + int[] pixelInfo) { | |
| 992 | + int x0 = (int)(coords[0]*MDP_MULT); | |
| 993 | + int y0 = (int)(coords[1]*MDP_MULT); | |
| 994 | + | |
| 995 | + int xe = (int)(coords[6]*MDP_MULT); | |
| 996 | + int ye = (int)(coords[7]*MDP_MULT); | |
| 997 | + | |
| 998 | + /* Extracting fractional part of coordinates of first control point */ | |
| 999 | + int px = (x0 & (~MDP_W_MASK)) << DF_CUB_SHIFT; | |
| 1000 | + int py = (y0 & (~MDP_W_MASK)) << DF_CUB_SHIFT; | |
| 1001 | + | |
| 1002 | + /* Setting default boundary values for checking first and second forward | |
| 1003 | + * difference for the necessity of the restepping. See comments to the | |
| 1004 | + * boundary values in ProcessQuad for more info. | |
| 1005 | + */ | |
| 1006 | + int incStepBnd = DF_CUB_INC_BND; | |
| 1007 | + int decStepBnd = DF_CUB_DEC_BND; | |
| 1008 | + | |
| 1009 | + /* Setting default amount of steps */ | |
| 1010 | + int count = DF_CUB_COUNT; | |
| 1011 | + | |
| 1012 | + /* Setting default shift for preparing to the midpoint rounding */ | |
| 1013 | + int shift = DF_CUB_SHIFT; | |
| 1014 | + | |
| 1015 | + int ax = (int)((-coords[0] + 3*coords[2] - 3*coords[4] + | |
| 1016 | + coords[6])*CUB_A_MDP_MULT); | |
| 1017 | + int ay = (int)((-coords[1] + 3*coords[3] - 3*coords[5] + | |
| 1018 | + coords[7])*CUB_A_MDP_MULT); | |
| 1019 | + | |
| 1020 | + int bx = (int)((3*coords[0] - 6*coords[2] + | |
| 1021 | + 3*coords[4])*CUB_B_MDP_MULT); | |
| 1022 | + int by = (int)((3*coords[1] - 6*coords[3] + | |
| 1023 | + 3*coords[5])*CUB_B_MDP_MULT); | |
| 1024 | + | |
| 1025 | + int cx = (int)((-3*coords[0] + 3*coords[2])*(CUB_C_MDP_MULT)); | |
| 1026 | + int cy = (int)((-3*coords[1] + 3*coords[3])*(CUB_C_MDP_MULT)); | |
| 1027 | + | |
| 1028 | + int dddpx = 6*ax; | |
| 1029 | + int dddpy = 6*ay; | |
| 1030 | + | |
| 1031 | + int ddpx = dddpx + bx; | |
| 1032 | + int ddpy = dddpy + by; | |
| 1033 | + | |
| 1034 | + int dpx = ax + (bx>>1) + cx; | |
| 1035 | + int dpy = ay + (by>>1) + cy; | |
| 1036 | + | |
| 1037 | + int x1, y1; | |
| 1038 | + | |
| 1039 | + int x2 = x0; | |
| 1040 | + int y2 = y0; | |
| 1041 | + | |
| 1042 | + /* Calculating whole part of the first point of the curve */ | |
| 1043 | + int x0w = x0 & MDP_W_MASK; | |
| 1044 | + int y0w = y0 & MDP_W_MASK; | |
| 1045 | + | |
| 1046 | + int dx = xe - x0; | |
| 1047 | + int dy = ye - y0; | |
| 1048 | + | |
| 1049 | + while (count > 0) { | |
| 1050 | + /* Perform decreasing step in 2 times if necessary */ | |
| 1051 | + while (Math.abs(ddpx) > decStepBnd || | |
| 1052 | + Math.abs(ddpy) > decStepBnd) { | |
| 1053 | + ddpx = (ddpx<<1) - dddpx; | |
| 1054 | + ddpy = (ddpy<<1) - dddpy; | |
| 1055 | + dpx = (dpx<<2) - (ddpx>>1); | |
| 1056 | + dpy = (dpy<<2) - (ddpy>>1); | |
| 1057 | + count <<=1; | |
| 1058 | + decStepBnd <<=3; | |
| 1059 | + incStepBnd <<=3; | |
| 1060 | + px <<=3; | |
| 1061 | + py <<=3; | |
| 1062 | + shift += 3; | |
| 1063 | + } | |
| 1064 | + | |
| 1065 | + /* Perform increasing step in 2 times if necessary. | |
| 1066 | + * Note: we could do it only in even steps | |
| 1067 | + */ | |
| 1068 | + | |
| 1069 | + while ((count & 1) == 0 && shift > DF_CUB_SHIFT && | |
| 1070 | + Math.abs(dpx) <= incStepBnd && | |
| 1071 | + Math.abs(dpy) <= incStepBnd) { | |
| 1072 | + dpx = (dpx>>2) + (ddpx>>3); | |
| 1073 | + dpy = (dpy>>2) + (ddpy>>3); | |
| 1074 | + ddpx = (ddpx + dddpx)>>1; | |
| 1075 | + ddpy = (ddpy + dddpy)>>1; | |
| 1076 | + count >>=1; | |
| 1077 | + decStepBnd >>=3; | |
| 1078 | + incStepBnd >>=3; | |
| 1079 | + px >>=3; | |
| 1080 | + py >>=3; | |
| 1081 | + shift -= 3; | |
| 1082 | + } | |
| 1083 | + | |
| 1084 | + count--; | |
| 1085 | + | |
| 1086 | + /* Performing one step less than necessary and use actual (xe,ye) | |
| 1087 | + * curve's endpoint instead of calculated. This prevent us from | |
| 1088 | + * running above the curve endpoint due to the accumulated errors | |
| 1089 | + * during the iterations. | |
| 1090 | + */ | |
| 1091 | + if (count > 0) { | |
| 1092 | + px += dpx; | |
| 1093 | + py += dpy; | |
| 1094 | + | |
| 1095 | + dpx += ddpx; | |
| 1096 | + dpy += ddpy; | |
| 1097 | + ddpx += dddpx; | |
| 1098 | + ddpy += dddpy; | |
| 1099 | + | |
| 1100 | + x1 = x2; | |
| 1101 | + y1 = y2; | |
| 1102 | + | |
| 1103 | + x2 = x0w + (px >> shift); | |
| 1104 | + y2 = y0w + (py >> shift); | |
| 1105 | + | |
| 1106 | + /* Checking that we are not running out of the endpoint and | |
| 1107 | + * bounding violating coordinate. The check is pretty simple | |
| 1108 | + * because the curve passed to the DrawCubic already splitted | |
| 1109 | + * into the monotonic in X and Y pieces | |
| 1110 | + */ | |
| 1111 | + | |
| 1112 | + /* Bounding x2 by xe */ | |
| 1113 | + if (((xe-x2)^dx) < 0) { | |
| 1114 | + x2 = xe; | |
| 1115 | + } | |
| 1116 | + | |
| 1117 | + /* Bounding y2 by ye */ | |
| 1118 | + if (((ye-y2)^dy) < 0) { | |
| 1119 | + y2 = ye; | |
| 1120 | + } | |
| 1121 | + | |
| 1122 | + hnd.processFixedLine(x1, y1, x2, y2, pixelInfo, checkBounds, | |
| 1123 | + false); | |
| 1124 | + } else { | |
| 1125 | + hnd.processFixedLine(x2, y2, xe, ye, pixelInfo, checkBounds, | |
| 1126 | + false); | |
| 1127 | + } | |
| 1128 | + } | |
| 1129 | + } | |
| 1130 | + | |
| 1131 | + /* | |
| 1132 | + * Checking size of the cubic curves and split them if necessary. | |
| 1133 | + * Calling DrawMonotonicCubic for the curves of the appropriate size. | |
| 1134 | + * Note: coords array could be changed | |
| 1135 | + */ | |
| 1136 | + private static void ProcessMonotonicCubic(ProcessHandler hnd, | |
| 1137 | + float[] coords, | |
| 1138 | + int[] pixelInfo) { | |
| 1139 | + | |
| 1140 | + float[] coords1 = new float[8]; | |
| 1141 | + float tx, ty; | |
| 1142 | + float xMin, xMax; | |
| 1143 | + float yMin, yMax; | |
| 1144 | + | |
| 1145 | + xMin = xMax = coords[0]; | |
| 1146 | + yMin = yMax = coords[1]; | |
| 1147 | + | |
| 1148 | + for (int i = 2; i < 8; i += 2) { | |
| 1149 | + xMin = (xMin > coords[i])? coords[i] : xMin; | |
| 1150 | + xMax = (xMax < coords[i])? coords[i] : xMax; | |
| 1151 | + yMin = (yMin > coords[i + 1])? coords[i + 1] : yMin; | |
| 1152 | + yMax = (yMax < coords[i + 1])? coords[i + 1] : yMax; | |
| 1153 | + } | |
| 1154 | + | |
| 1155 | + if (hnd.clipMode == PH_MODE_DRAW_CLIP) { | |
| 1156 | + /* In case of drawing we could just skip curves which are | |
| 1157 | + * completely out of bounds | |
| 1158 | + */ | |
| 1159 | + if (hnd.dhnd.xMaxf < xMin || hnd.dhnd.xMinf > xMax || | |
| 1160 | + hnd.dhnd.yMaxf < yMin || hnd.dhnd.yMinf > yMax) { | |
| 1161 | + return; | |
| 1162 | + } | |
| 1163 | + } else { | |
| 1164 | + | |
| 1165 | + /* In case of filling we could skip curves which are above, | |
| 1166 | + * below and behind the right boundary of the visible area | |
| 1167 | + */ | |
| 1168 | + | |
| 1169 | + if (hnd.dhnd.yMaxf < yMin || hnd.dhnd.yMinf > yMax || | |
| 1170 | + hnd.dhnd.xMaxf < xMin) | |
| 1171 | + { | |
| 1172 | + return; | |
| 1173 | + } | |
| 1174 | + | |
| 1175 | + /* We could clamp x coordinates to the corresponding boundary | |
| 1176 | + * if the curve is completely behind the left one | |
| 1177 | + */ | |
| 1178 | + | |
| 1179 | + if (hnd.dhnd.xMinf > xMax) { | |
| 1180 | + coords[0] = coords[2] = coords[4] = coords[6] = | |
| 1181 | + hnd.dhnd.xMinf; | |
| 1182 | + } | |
| 1183 | + } | |
| 1184 | + | |
| 1185 | + if (xMax - xMin > MAX_CUB_SIZE || yMax - yMin > MAX_CUB_SIZE) { | |
| 1186 | + coords1[6] = coords[6]; | |
| 1187 | + coords1[7] = coords[7]; | |
| 1188 | + coords1[4] = (coords[4] + coords[6])/2.0f; | |
| 1189 | + coords1[5] = (coords[5] + coords[7])/2.0f; | |
| 1190 | + tx = (coords[2] + coords[4])/2.0f; | |
| 1191 | + ty = (coords[3] + coords[5])/2.0f; | |
| 1192 | + coords1[2] = (tx + coords1[4])/2.0f; | |
| 1193 | + coords1[3] = (ty + coords1[5])/2.0f; | |
| 1194 | + coords[2] = (coords[0] + coords[2])/2.0f; | |
| 1195 | + coords[3] = (coords[1] + coords[3])/2.0f; | |
| 1196 | + coords[4] = (coords[2] + tx)/2.0f; | |
| 1197 | + coords[5] = (coords[3] + ty)/2.0f; | |
| 1198 | + coords[6]=coords1[0]=(coords[4] + coords1[2])/2.0f; | |
| 1199 | + coords[7]=coords1[1]=(coords[5] + coords1[3])/2.0f; | |
| 1200 | + | |
| 1201 | + ProcessMonotonicCubic(hnd, coords, pixelInfo); | |
| 1202 | + | |
| 1203 | + ProcessMonotonicCubic(hnd, coords1, pixelInfo); | |
| 1204 | + } else { | |
| 1205 | + DrawMonotonicCubic(hnd, coords, | |
| 1206 | + /* Set checkBounds parameter if curve intersects | |
| 1207 | + * boundary of the visible area. We know that | |
| 1208 | + * the curve is visible, so the check is pretty | |
| 1209 | + * simple | |
| 1210 | + */ | |
| 1211 | + hnd.dhnd.xMinf > xMin || | |
| 1212 | + hnd.dhnd.xMaxf < xMax || | |
| 1213 | + hnd.dhnd.yMinf > yMin || | |
| 1214 | + hnd.dhnd.yMaxf < yMax, | |
| 1215 | + pixelInfo); | |
| 1216 | + } | |
| 1217 | + } | |
| 1218 | + | |
| 1219 | + /* | |
| 1220 | + * Split cubic curve into monotonic in X and Y parts. Calling | |
| 1221 | + * ProcessMonotonicCubic for each monotonic piece of the curve. | |
| 1222 | + * | |
| 1223 | + * Note: coords array could be changed | |
| 1224 | + */ | |
| 1225 | + private static void ProcessCubic(ProcessHandler hnd, | |
| 1226 | + float[] coords, | |
| 1227 | + int[] pixelInfo) { | |
| 1228 | + /* Temporary array for holding parameters corresponding to the extreme | |
| 1229 | + * in X and Y points | |
| 1230 | + */ | |
| 1231 | + double params[] = new double[4]; | |
| 1232 | + double eqn[] = new double[3]; | |
| 1233 | + double res[] = new double[2]; | |
| 1234 | + int cnt = 0; | |
| 1235 | + | |
| 1236 | + /* Simple check for monotonicity in X before searching for the extreme | |
| 1237 | + * points of the X(t) function. We first check if the curve is | |
| 1238 | + * monotonic in X by seeing if all of the X coordinates are strongly | |
| 1239 | + * ordered. | |
| 1240 | + */ | |
| 1241 | + if ((coords[0] > coords[2] || coords[2] > coords[4] || | |
| 1242 | + coords[4] > coords[6]) && | |
| 1243 | + (coords[0] < coords[2] || coords[2] < coords[4] || | |
| 1244 | + coords[4] < coords[6])) | |
| 1245 | + { | |
| 1246 | + /* Searching for extreme points of the X(t) function by solving | |
| 1247 | + * dX(t) | |
| 1248 | + * ---- = 0 equation | |
| 1249 | + * dt | |
| 1250 | + */ | |
| 1251 | + eqn[2] = -coords[0] + 3*coords[2] - 3*coords[4] + coords[6]; | |
| 1252 | + eqn[1] = 2*(coords[0] - 2*coords[2] + coords[4]); | |
| 1253 | + eqn[0] = -coords[0] + coords[2]; | |
| 1254 | + | |
| 1255 | + int nr = QuadCurve2D.solveQuadratic(eqn, res); | |
| 1256 | + | |
| 1257 | + /* Following code also correctly works in degenerate case of | |
| 1258 | + * the quadratic equation (nr = -1) because we do not need | |
| 1259 | + * splitting in this case. | |
| 1260 | + */ | |
| 1261 | + for (int i = 0; i < nr; i++) { | |
| 1262 | + if (res[i] > 0 && res[i] < 1) { | |
| 1263 | + params[cnt++] = res[i]; | |
| 1264 | + } | |
| 1265 | + } | |
| 1266 | + } | |
| 1267 | + | |
| 1268 | + /* Simple check for monotonicity in Y before searching for the extreme | |
| 1269 | + * points of the Y(t) function. We first check if the curve is | |
| 1270 | + * monotonic in Y by seeing if all of the Y coordinates are strongly | |
| 1271 | + * ordered. | |
| 1272 | + */ | |
| 1273 | + if ((coords[1] > coords[3] || coords[3] > coords[5] || | |
| 1274 | + coords[5] > coords[7]) && | |
| 1275 | + (coords[1] < coords[3] || coords[3] < coords[5] || | |
| 1276 | + coords[5] < coords[7])) | |
| 1277 | + { | |
| 1278 | + /* Searching for extreme points of the Y(t) function by solving | |
| 1279 | + * dY(t) | |
| 1280 | + * ----- = 0 equation | |
| 1281 | + * dt | |
| 1282 | + */ | |
| 1283 | + eqn[2] = -coords[1] + 3*coords[3] - 3*coords[5] + coords[7]; | |
| 1284 | + eqn[1] = 2*(coords[1] - 2*coords[3] + coords[5]); | |
| 1285 | + eqn[0] = -coords[1] + coords[3]; | |
| 1286 | + | |
| 1287 | + int nr = QuadCurve2D.solveQuadratic(eqn, res); | |
| 1288 | + | |
| 1289 | + /* Following code also correctly works in degenerate case of | |
| 1290 | + * the quadratic equation (nr = -1) because we do not need | |
| 1291 | + * splitting in this case. | |
| 1292 | + */ | |
| 1293 | + for (int i = 0; i < nr; i++) { | |
| 1294 | + if (res[i] > 0 && res[i] < 1) { | |
| 1295 | + params[cnt++] = res[i]; | |
| 1296 | + } | |
| 1297 | + } | |
| 1298 | + } | |
| 1299 | + | |
| 1300 | + if (cnt > 0) { | |
| 1301 | + /* Sorting parameter values corresponding to the extreme points | |
| 1302 | + * of the curve | |
| 1303 | + */ | |
| 1304 | + Arrays.sort(params, 0, cnt); | |
| 1305 | + | |
| 1306 | + /* Processing obtained monotonic parts */ | |
| 1307 | + ProcessFirstMonotonicPartOfCubic(hnd, coords, pixelInfo, | |
| 1308 | + (float)params[0]); | |
| 1309 | + for (int i = 1; i < cnt; i++) { | |
| 1310 | + double param = params[i] - params[i-1]; | |
| 1311 | + if (param > 0) { | |
| 1312 | + ProcessFirstMonotonicPartOfCubic(hnd, coords, pixelInfo, | |
| 1313 | + /* Scale parameter to match with rest of the curve */ | |
| 1314 | + (float)(param/(1.0 - params[i - 1]))); | |
| 1315 | + } | |
| 1316 | + } | |
| 1317 | + } | |
| 1318 | + | |
| 1319 | + ProcessMonotonicCubic(hnd,coords,pixelInfo); | |
| 1320 | + } | |
| 1321 | + | |
| 1322 | + /* | |
| 1323 | + * Bite the piece of the cubic curve from start point till the point | |
| 1324 | + * corresponding to the specified parameter then call ProcessCubic for the | |
| 1325 | + * bitten part. | |
| 1326 | + * Note: coords array will be changed | |
| 1327 | + */ | |
| 1328 | + private static void ProcessFirstMonotonicPartOfCubic(ProcessHandler hnd, | |
| 1329 | + float[] coords, | |
| 1330 | + int[] pixelInfo, | |
| 1331 | + float t) | |
| 1332 | + { | |
| 1333 | + float[] coords1 = new float[8]; | |
| 1334 | + float tx, ty; | |
| 1335 | + | |
| 1336 | + coords1[0] = coords[0]; | |
| 1337 | + coords1[1] = coords[1]; | |
| 1338 | + tx = coords[2] + t*(coords[4] - coords[2]); | |
| 1339 | + ty = coords[3] + t*(coords[5] - coords[3]); | |
| 1340 | + coords1[2] = coords[0] + t*(coords[2] - coords[0]); | |
| 1341 | + coords1[3] = coords[1] + t*(coords[3] - coords[1]); | |
| 1342 | + coords1[4] = coords1[2] + t*(tx - coords1[2]); | |
| 1343 | + coords1[5] = coords1[3] + t*(ty - coords1[3]); | |
| 1344 | + coords[4] = coords[4] + t*(coords[6] - coords[4]); | |
| 1345 | + coords[5] = coords[5] + t*(coords[7] - coords[5]); | |
| 1346 | + coords[2] = tx + t*(coords[4] - tx); | |
| 1347 | + coords[3] = ty + t*(coords[5] - ty); | |
| 1348 | + coords[0]=coords1[6]=coords1[4] + t*(coords[2] - coords1[4]); | |
| 1349 | + coords[1]=coords1[7]=coords1[5] + t*(coords[3] - coords1[5]); | |
| 1350 | + | |
| 1351 | + ProcessMonotonicCubic(hnd, coords1, pixelInfo); | |
| 1352 | + } | |
| 1353 | + | |
| 1354 | + /* Note: | |
| 1355 | + * For more easy reading of the code below each java version of the macros | |
| 1356 | + * from the ProcessPath.c preceded by the commented origin call | |
| 1357 | + * containing verbose names of the parameters | |
| 1358 | + */ | |
| 1359 | + private static void ProcessLine(ProcessHandler hnd, float x1, float y1, | |
| 1360 | + float x2, float y2, int[] pixelInfo) { | |
| 1361 | + float xMin, yMin, xMax, yMax; | |
| 1362 | + int X1, Y1, X2, Y2, X3, Y3, res; | |
| 1363 | + boolean clipped = false; | |
| 1364 | + float x3,y3; | |
| 1365 | + float c[] = new float[]{x1, y1, x2, y2, 0, 0}; | |
| 1366 | + | |
| 1367 | + boolean lastClipped; | |
| 1368 | + | |
| 1369 | + xMin = hnd.dhnd.xMinf; | |
| 1370 | + yMin = hnd.dhnd.yMinf; | |
| 1371 | + xMax = hnd.dhnd.xMaxf; | |
| 1372 | + yMax = hnd.dhnd.yMaxf; | |
| 1373 | + | |
| 1374 | + // | |
| 1375 | + // TESTANDCLIP(yMin, yMax, y1, x1, y2, x2, res); | |
| 1376 | + // | |
| 1377 | + res = TESTANDCLIP(yMin, yMax, c, 1, 0, 3, 2); | |
| 1378 | + if (res == CRES_INVISIBLE) return; | |
| 1379 | + clipped = IS_CLIPPED(res); | |
| 1380 | + // | |
| 1381 | + // TESTANDCLIP(yMin, yMax, y2, x2, y1, x1, res); | |
| 1382 | + // | |
| 1383 | + res = TESTANDCLIP(yMin, yMax, c, 3, 2, 1, 0); | |
| 1384 | + if (res == CRES_INVISIBLE) return; | |
| 1385 | + lastClipped = IS_CLIPPED(res); | |
| 1386 | + clipped = clipped || lastClipped; | |
| 1387 | + | |
| 1388 | + if (hnd.clipMode == PH_MODE_DRAW_CLIP) { | |
| 1389 | + // | |
| 1390 | + // TESTANDCLIP(xMin, xMax, x1, y1, x2, y2, res); | |
| 1391 | + // | |
| 1392 | + res = TESTANDCLIP(xMin, xMax, c, 0, 1, 2, 3); | |
| 1393 | + if (res == CRES_INVISIBLE) return; | |
| 1394 | + clipped = clipped || IS_CLIPPED(res); | |
| 1395 | + // | |
| 1396 | + // TESTANDCLIP(xMin, xMax, x2, y2, x1, y1, res); | |
| 1397 | + // | |
| 1398 | + res = TESTANDCLIP(xMin, xMax, c, 2, 3, 0, 1); | |
| 1399 | + if (res == CRES_INVISIBLE) return; | |
| 1400 | + lastClipped = lastClipped || IS_CLIPPED(res); | |
| 1401 | + clipped = clipped || lastClipped; | |
| 1402 | + X1 = (int)(c[0]*MDP_MULT); | |
| 1403 | + Y1 = (int)(c[1]*MDP_MULT); | |
| 1404 | + X2 = (int)(c[2]*MDP_MULT); | |
| 1405 | + Y2 = (int)(c[3]*MDP_MULT); | |
| 1406 | + | |
| 1407 | + hnd.processFixedLine(X1, Y1, X2, Y2, pixelInfo, | |
| 1408 | + clipped, /* enable boundary checking in | |
| 1409 | + case of clipping to avoid | |
| 1410 | + entering out of bounds which | |
| 1411 | + could happens during rounding | |
| 1412 | + */ | |
| 1413 | + lastClipped /* Notify pProcessFixedLine | |
| 1414 | + that | |
| 1415 | + this is the end of the | |
| 1416 | + subpath (because of exiting | |
| 1417 | + out of boundaries) | |
| 1418 | + */ | |
| 1419 | + ); | |
| 1420 | + } else { | |
| 1421 | + /* Clamping starting from first vertex of the the processed | |
| 1422 | + * segment | |
| 1423 | + * | |
| 1424 | + * CLIPCLAMP(xMin, xMax, x1, y1, x2, y2, x3, y3, res); | |
| 1425 | + */ | |
| 1426 | + res = CLIPCLAMP(xMin, xMax, c, 0, 1, 2, 3, 4, 5); | |
| 1427 | + X1 = (int)(c[0]*MDP_MULT); | |
| 1428 | + Y1 = (int)(c[1]*MDP_MULT); | |
| 1429 | + | |
| 1430 | + /* Clamping only by left boundary */ | |
| 1431 | + if (res == CRES_MIN_CLIPPED) { | |
| 1432 | + X3 = (int)(c[4]*MDP_MULT); | |
| 1433 | + Y3 = (int)(c[5]*MDP_MULT); | |
| 1434 | + hnd.processFixedLine(X3, Y3, X1, Y1, pixelInfo, | |
| 1435 | + false, lastClipped); | |
| 1436 | + | |
| 1437 | + } else if (res == CRES_INVISIBLE) { | |
| 1438 | + return; | |
| 1439 | + } | |
| 1440 | + | |
| 1441 | + /* Clamping starting from last vertex of the the processed | |
| 1442 | + * segment | |
| 1443 | + * | |
| 1444 | + * CLIPCLAMP(xMin, xMax, x2, y2, x1, y1, x3, y3, res); | |
| 1445 | + */ | |
| 1446 | + res = CLIPCLAMP(xMin, xMax, c, 2, 3, 0, 1, 4, 5); | |
| 1447 | + | |
| 1448 | + /* Checking if there was a clip by right boundary */ | |
| 1449 | + lastClipped = lastClipped || (res == CRES_MAX_CLIPPED); | |
| 1450 | + | |
| 1451 | + X2 = (int)(c[2]*MDP_MULT); | |
| 1452 | + Y2 = (int)(c[3]*MDP_MULT); | |
| 1453 | + hnd.processFixedLine(X1, Y1, X2, Y2, pixelInfo, | |
| 1454 | + false, lastClipped); | |
| 1455 | + | |
| 1456 | + /* Clamping only by left boundary */ | |
| 1457 | + if (res == CRES_MIN_CLIPPED) { | |
| 1458 | + X3 = (int)(c[4]*MDP_MULT); | |
| 1459 | + Y3 = (int)(c[5]*MDP_MULT); | |
| 1460 | + hnd.processFixedLine(X2, Y2, X3, Y3, pixelInfo, | |
| 1461 | + false, lastClipped); | |
| 1462 | + } | |
| 1463 | + } | |
| 1464 | + } | |
| 1465 | + | |
| 1466 | + private static boolean doProcessPath(ProcessHandler hnd, | |
| 1467 | + Path2D.Float p2df, | |
| 1468 | + float transXf, float transYf) { | |
| 1469 | + float coords[] = new float[8]; | |
| 1470 | + float tCoords[] = new float[8]; | |
| 1471 | + float closeCoord[] = new float[] {0.0f, 0.0f}; | |
| 1472 | + float firstCoord[] = new float[2]; | |
| 1473 | + int pixelInfo[] = new int[5]; | |
| 1474 | + boolean subpathStarted = false; | |
| 1475 | + boolean skip = false; | |
| 1476 | + float lastX, lastY; | |
| 1477 | + pixelInfo[0] = 0; | |
| 1478 | + | |
| 1479 | + /* Adjusting boundaries to the capabilities of the | |
| 1480 | + * ProcessPath code | |
| 1481 | + */ | |
| 1482 | + hnd.dhnd.adjustBounds(LOWER_OUT_BND, LOWER_OUT_BND, | |
| 1483 | + UPPER_OUT_BND, UPPER_OUT_BND); | |
| 1484 | + | |
| 1485 | + /* Adding support of the KEY_STROKE_CONTROL rendering hint. | |
| 1486 | + * Now we are supporting two modes: "pixels at centers" and | |
| 1487 | + * "pixels at corners". | |
| 1488 | + * First one is disabled by default but could be enabled by setting | |
| 1489 | + * VALUE_STROKE_PURE to the rendering hint. It means that pixel at the | |
| 1490 | + * screen (x,y) has (x + 0.5, y + 0.5) float coordinates. | |
| 1491 | + * | |
| 1492 | + * Second one is enabled by default and means straightforward mapping | |
| 1493 | + * (x,y) --> (x,y) | |
| 1494 | + */ | |
| 1495 | + if (hnd.dhnd.strokeControl == SunHints.INTVAL_STROKE_PURE) { | |
| 1496 | + closeCoord[0] = -0.5f; | |
| 1497 | + closeCoord[1] = -0.5f; | |
| 1498 | + transXf -= 0.5; | |
| 1499 | + transYf -= 0.5; | |
| 1500 | + } | |
| 1501 | + | |
| 1502 | + PathIterator pi = p2df.getPathIterator(null); | |
| 1503 | + | |
| 1504 | + while (!pi.isDone()) { | |
| 1505 | + switch (pi.currentSegment(coords)) { | |
| 1506 | + case PathIterator.SEG_MOVETO: | |
| 1507 | + /* Performing closing of the unclosed segments */ | |
| 1508 | + if (subpathStarted && !skip) { | |
| 1509 | + if (hnd.clipMode == PH_MODE_FILL_CLIP) { | |
| 1510 | + if (tCoords[0] != closeCoord[0] || | |
| 1511 | + tCoords[1] != closeCoord[1]) | |
| 1512 | + { | |
| 1513 | + ProcessLine(hnd, tCoords[0], tCoords[1], | |
| 1514 | + closeCoord[0], closeCoord[1], | |
| 1515 | + pixelInfo); | |
| 1516 | + } | |
| 1517 | + } | |
| 1518 | + hnd.processEndSubPath(); | |
| 1519 | + } | |
| 1520 | + | |
| 1521 | + tCoords[0] = coords[0] + transXf; | |
| 1522 | + tCoords[1] = coords[1] + transYf; | |
| 1523 | + | |
| 1524 | + /* Checking SEG_MOVETO coordinates if they are out of the | |
| 1525 | + * [LOWER_BND, UPPER_BND] range. This check also handles | |
| 1526 | + * NaN and Infinity values. Skipping next path segment in | |
| 1527 | + * case of invalid data. | |
| 1528 | + */ | |
| 1529 | + | |
| 1530 | + if (tCoords[0] < UPPER_BND && | |
| 1531 | + tCoords[0] > LOWER_BND && | |
| 1532 | + tCoords[1] < UPPER_BND && | |
| 1533 | + tCoords[1] > LOWER_BND) | |
| 1534 | + { | |
| 1535 | + subpathStarted = true; | |
| 1536 | + skip = false; | |
| 1537 | + closeCoord[0] = tCoords[0]; | |
| 1538 | + closeCoord[1] = tCoords[1]; | |
| 1539 | + } else { | |
| 1540 | + skip = true; | |
| 1541 | + } | |
| 1542 | + pixelInfo[0] = 0; | |
| 1543 | + break; | |
| 1544 | + case PathIterator.SEG_LINETO: | |
| 1545 | + lastX = tCoords[2] = coords[0] + transXf; | |
| 1546 | + lastY = tCoords[3] = coords[1] + transYf; | |
| 1547 | + | |
| 1548 | + /* Checking SEG_LINETO coordinates if they are out of the | |
| 1549 | + * [LOWER_BND, UPPER_BND] range. This check also handles | |
| 1550 | + * NaN and Infinity values. Ignoring current path segment | |
| 1551 | + * in case of invalid data. If segment is skipped its | |
| 1552 | + * endpoint (if valid) is used to begin new subpath. | |
| 1553 | + */ | |
| 1554 | + | |
| 1555 | + if (lastX < UPPER_BND && | |
| 1556 | + lastX > LOWER_BND && | |
| 1557 | + lastY < UPPER_BND && | |
| 1558 | + lastY > LOWER_BND) | |
| 1559 | + { | |
| 1560 | + if (skip) { | |
| 1561 | + tCoords[0] = closeCoord[0] = lastX; | |
| 1562 | + tCoords[1] = closeCoord[1] = lastY; | |
| 1563 | + subpathStarted = true; | |
| 1564 | + skip = false; | |
| 1565 | + } else { | |
| 1566 | + ProcessLine(hnd, tCoords[0], tCoords[1], | |
| 1567 | + tCoords[2], tCoords[3], pixelInfo); | |
| 1568 | + tCoords[0] = lastX; | |
| 1569 | + tCoords[1] = lastY; | |
| 1570 | + } | |
| 1571 | + } | |
| 1572 | + break; | |
| 1573 | + case PathIterator.SEG_QUADTO: | |
| 1574 | + tCoords[2] = coords[0] + transXf; | |
| 1575 | + tCoords[3] = coords[1] + transYf; | |
| 1576 | + lastX = tCoords[4] = coords[2] + transXf; | |
| 1577 | + lastY = tCoords[5] = coords[3] + transYf; | |
| 1578 | + | |
| 1579 | + /* Checking SEG_QUADTO coordinates if they are out of the | |
| 1580 | + * [LOWER_BND, UPPER_BND] range. This check also handles | |
| 1581 | + * NaN and Infinity values. Ignoring current path segment | |
| 1582 | + * in case of invalid endpoints's data. Equivalent to | |
| 1583 | + * the SEG_LINETO if endpoint coordinates are valid but | |
| 1584 | + * there are invalid data among other coordinates | |
| 1585 | + */ | |
| 1586 | + | |
| 1587 | + if (lastX < UPPER_BND && | |
| 1588 | + lastX > LOWER_BND && | |
| 1589 | + lastY < UPPER_BND && | |
| 1590 | + lastY > LOWER_BND) | |
| 1591 | + { | |
| 1592 | + if (skip) { | |
| 1593 | + tCoords[0] = closeCoord[0] = lastX; | |
| 1594 | + tCoords[1] = closeCoord[1] = lastY; | |
| 1595 | + subpathStarted = true; | |
| 1596 | + skip = false; | |
| 1597 | + } else { | |
| 1598 | + if (tCoords[2] < UPPER_BND && | |
| 1599 | + tCoords[2] > LOWER_BND && | |
| 1600 | + tCoords[3] < UPPER_BND && | |
| 1601 | + tCoords[3] > LOWER_BND) | |
| 1602 | + { | |
| 1603 | + ProcessQuad(hnd, tCoords, pixelInfo); | |
| 1604 | + } else { | |
| 1605 | + ProcessLine(hnd, tCoords[0], tCoords[1], | |
| 1606 | + tCoords[4], tCoords[5], | |
| 1607 | + pixelInfo); | |
| 1608 | + } | |
| 1609 | + tCoords[0] = lastX; | |
| 1610 | + tCoords[1] = lastY; | |
| 1611 | + } | |
| 1612 | + } | |
| 1613 | + break; | |
| 1614 | + case PathIterator.SEG_CUBICTO: | |
| 1615 | + tCoords[2] = coords[0] + transXf; | |
| 1616 | + tCoords[3] = coords[1] + transYf; | |
| 1617 | + tCoords[4] = coords[2] + transXf; | |
| 1618 | + tCoords[5] = coords[3] + transYf; | |
| 1619 | + lastX = tCoords[6] = coords[4] + transXf; | |
| 1620 | + lastY = tCoords[7] = coords[5] + transYf; | |
| 1621 | + | |
| 1622 | + /* Checking SEG_CUBICTO coordinates if they are out of the | |
| 1623 | + * [LOWER_BND, UPPER_BND] range. This check also handles | |
| 1624 | + * NaN and Infinity values. Ignoring current path segment | |
| 1625 | + * in case of invalid endpoints's data. Equivalent to | |
| 1626 | + * the SEG_LINETO if endpoint coordinates are valid but | |
| 1627 | + * there are invalid data among other coordinates | |
| 1628 | + */ | |
| 1629 | + | |
| 1630 | + if (lastX < UPPER_BND && | |
| 1631 | + lastX > LOWER_BND && | |
| 1632 | + lastY < UPPER_BND && | |
| 1633 | + lastY > LOWER_BND) | |
| 1634 | + { | |
| 1635 | + if (skip) { | |
| 1636 | + tCoords[0] = closeCoord[0] = tCoords[6]; | |
| 1637 | + tCoords[1] = closeCoord[1] = tCoords[7]; | |
| 1638 | + subpathStarted = true; | |
| 1639 | + skip = false; | |
| 1640 | + } else { | |
| 1641 | + if (tCoords[2] < UPPER_BND && | |
| 1642 | + tCoords[2] > LOWER_BND && | |
| 1643 | + tCoords[3] < UPPER_BND && | |
| 1644 | + tCoords[3] > LOWER_BND && | |
| 1645 | + tCoords[4] < UPPER_BND && | |
| 1646 | + tCoords[4] > LOWER_BND && | |
| 1647 | + tCoords[5] < UPPER_BND && | |
| 1648 | + tCoords[5] > LOWER_BND) | |
| 1649 | + { | |
| 1650 | + ProcessCubic(hnd, tCoords, pixelInfo); | |
| 1651 | + } else { | |
| 1652 | + ProcessLine(hnd, tCoords[0], tCoords[1], | |
| 1653 | + tCoords[6], tCoords[7], | |
| 1654 | + pixelInfo); | |
| 1655 | + } | |
| 1656 | + tCoords[0] = lastX; | |
| 1657 | + tCoords[1] = lastY; | |
| 1658 | + } | |
| 1659 | + } | |
| 1660 | + break; | |
| 1661 | + case PathIterator.SEG_CLOSE: | |
| 1662 | + if (subpathStarted && !skip) { | |
| 1663 | + skip = false; | |
| 1664 | + if (tCoords[0] != closeCoord[0] || | |
| 1665 | + tCoords[1] != closeCoord[1]) | |
| 1666 | + { | |
| 1667 | + ProcessLine(hnd, tCoords[0], tCoords[1], | |
| 1668 | + closeCoord[0], closeCoord[1], | |
| 1669 | + pixelInfo); | |
| 1670 | + | |
| 1671 | + /* Storing last path's point for using in following | |
| 1672 | + * segments without initial moveTo | |
| 1673 | + */ | |
| 1674 | + tCoords[0] = closeCoord[0]; | |
| 1675 | + tCoords[1] = closeCoord[1]; | |
| 1676 | + } | |
| 1677 | + hnd.processEndSubPath(); | |
| 1678 | + } | |
| 1679 | + break; | |
| 1680 | + } | |
| 1681 | + pi.next(); | |
| 1682 | + } | |
| 1683 | + | |
| 1684 | + /* Performing closing of the unclosed segments */ | |
| 1685 | + if (subpathStarted & !skip) { | |
| 1686 | + if (hnd.clipMode == PH_MODE_FILL_CLIP) { | |
| 1687 | + if (tCoords[0] != closeCoord[0] || | |
| 1688 | + tCoords[1] != closeCoord[1]) | |
| 1689 | + { | |
| 1690 | + ProcessLine(hnd, tCoords[0], tCoords[1], | |
| 1691 | + closeCoord[0], closeCoord[1], | |
| 1692 | + pixelInfo); | |
| 1693 | + } | |
| 1694 | + } | |
| 1695 | + hnd.processEndSubPath(); | |
| 1696 | + } | |
| 1697 | + return true; | |
| 1698 | + } | |
| 1699 | + | |
| 1700 | + private static class Point { | |
| 1701 | + public int x; | |
| 1702 | + public int y; | |
| 1703 | + public boolean lastPoint; | |
| 1704 | + public Point prev; | |
| 1705 | + public Point next; | |
| 1706 | + public Point nextByY; | |
| 1707 | + public Edge edge; | |
| 1708 | + public Point(int x, int y, boolean lastPoint) { | |
| 1709 | + this.x = x; | |
| 1710 | + this.y = y; | |
| 1711 | + this.lastPoint = lastPoint; | |
| 1712 | + } | |
| 1713 | + }; | |
| 1714 | + | |
| 1715 | + private static class Edge { | |
| 1716 | + int x; | |
| 1717 | + int dx; | |
| 1718 | + Point p; | |
| 1719 | + int dir; | |
| 1720 | + Edge prev; | |
| 1721 | + Edge next; | |
| 1722 | + | |
| 1723 | + public Edge(Point p, int x, int dx, int dir) { | |
| 1724 | + this.p = p; | |
| 1725 | + this.x = x; | |
| 1726 | + this.dx = dx; | |
| 1727 | + this.dir = dir; | |
| 1728 | + } | |
| 1729 | + }; | |
| 1730 | + | |
| 1731 | + /* Size of the default buffer in the FillData structure. This buffer is | |
| 1732 | + * replaced with heap allocated in case of large paths. | |
| 1733 | + */ | |
| 1734 | + private static final int DF_MAX_POINT = 256; | |
| 1735 | + | |
| 1736 | + /* Following class accumulates points of the non-continuous flattened | |
| 1737 | + * general path during iteration through the origin path's segments . The | |
| 1738 | + * end of the each subpath is marked as lastPoint flag set at the last | |
| 1739 | + * point | |
| 1740 | + */ | |
| 1741 | + private static class FillData { | |
| 1742 | + List<Point> plgPnts; | |
| 1743 | + public int plgYMin; | |
| 1744 | + public int plgYMax; | |
| 1745 | + | |
| 1746 | + public FillData() { | |
| 1747 | + plgPnts = new Vector<Point>(DF_MAX_POINT); | |
| 1748 | + } | |
| 1749 | + | |
| 1750 | + public void addPoint(int x, int y, boolean lastPoint) { | |
| 1751 | + if (plgPnts.size() == 0) { | |
| 1752 | + plgYMin = plgYMax = y; | |
| 1753 | + } else { | |
| 1754 | + plgYMin = (plgYMin > y)?y:plgYMin; | |
| 1755 | + plgYMax = (plgYMax < y)?y:plgYMax; | |
| 1756 | + } | |
| 1757 | + | |
| 1758 | + plgPnts.add(new Point(x, y, lastPoint)); | |
| 1759 | + } | |
| 1760 | + | |
| 1761 | + public boolean isEmpty() { | |
| 1762 | + return plgPnts.size() == 0; | |
| 1763 | + } | |
| 1764 | + | |
| 1765 | + public boolean isEnded() { | |
| 1766 | + return plgPnts.get(plgPnts.size() - 1).lastPoint; | |
| 1767 | + } | |
| 1768 | + | |
| 1769 | + public boolean setEnded() { | |
| 1770 | + return plgPnts.get(plgPnts.size() - 1).lastPoint = true; | |
| 1771 | + } | |
| 1772 | + } | |
| 1773 | + | |
| 1774 | + private static class ActiveEdgeList { | |
| 1775 | + Edge head; | |
| 1776 | + | |
| 1777 | + public boolean isEmpty() { | |
| 1778 | + return (head == null); | |
| 1779 | + } | |
| 1780 | + | |
| 1781 | + public void insert(Point pnt, int cy) { | |
| 1782 | + Point np = pnt.next; | |
| 1783 | + int X1 = pnt.x, Y1 = pnt.y; | |
| 1784 | + int X2 = np.x, Y2 = np.y; | |
| 1785 | + Edge ne; | |
| 1786 | + if (Y1 == Y2) { | |
| 1787 | + /* Skipping horizontal segments */ | |
| 1788 | + return; | |
| 1789 | + } else { | |
| 1790 | + int dX = X2 - X1; | |
| 1791 | + int dY = Y2 - Y1; | |
| 1792 | + int stepx, x0, dy, dir; | |
| 1793 | + | |
| 1794 | + if (Y1 < Y2) { | |
| 1795 | + x0 = X1; | |
| 1796 | + dy = cy - Y1; | |
| 1797 | + dir = -1; | |
| 1798 | + } else { // (Y1 > Y2) | |
| 1799 | + x0 = X2; | |
| 1800 | + dy = cy - Y2; | |
| 1801 | + dir = 1; | |
| 1802 | + } | |
| 1803 | + | |
| 1804 | + /* We need to worry only about dX because dY is in denominator | |
| 1805 | + * and abs(dy) < MDP_MULT (cy is a first scanline of the scan | |
| 1806 | + * converted segment and we subtract y coordinate of the | |
| 1807 | + * nearest segment's end from it to obtain dy) | |
| 1808 | + */ | |
| 1809 | + if (dX > CALC_UBND || dX < CALC_LBND) { | |
| 1810 | + stepx = (int)((((double)dX)*MDP_MULT)/dY); | |
| 1811 | + x0 = x0 + (int)((((double)dX)*dy)/dY); | |
| 1812 | + } else { | |
| 1813 | + stepx = (dX<<MDP_PREC)/dY; | |
| 1814 | + x0 += (dX*dy)/dY; | |
| 1815 | + } | |
| 1816 | + | |
| 1817 | + ne = new Edge(pnt, x0, stepx, dir); | |
| 1818 | + } | |
| 1819 | + | |
| 1820 | + ne.next = head; | |
| 1821 | + ne.prev = null; | |
| 1822 | + if (head != null) { | |
| 1823 | + head.prev = ne; | |
| 1824 | + } | |
| 1825 | + head = pnt.edge = ne; | |
| 1826 | + } | |
| 1827 | + | |
| 1828 | + public void delete(Edge e) { | |
| 1829 | + Edge prevp = e.prev; | |
| 1830 | + Edge nextp = e.next; | |
| 1831 | + if (prevp != null) { | |
| 1832 | + prevp.next = nextp; | |
| 1833 | + } else { | |
| 1834 | + head = nextp; | |
| 1835 | + } | |
| 1836 | + if (nextp != null) { | |
| 1837 | + nextp.prev = prevp; | |
| 1838 | + } | |
| 1839 | + } | |
| 1840 | + | |
| 1841 | + /** | |
| 1842 | + * Bubble sorting in the ascending order of the linked list. This | |
| 1843 | + * implementation stops processing the list if there were no changes | |
| 1844 | + * during the previous pass. | |
| 1845 | + * | |
| 1846 | + * We could not use O(N) Radix sort here because in most cases list of | |
| 1847 | + * edges almost sorted. So, bubble sort (O(N^2)) is working much | |
| 1848 | + * better. Note, in case of array of edges Shell sort is more | |
| 1849 | + * efficient. | |
| 1850 | + */ | |
| 1851 | + public void sort() { | |
| 1852 | + Edge p, q, r, s = null, temp; | |
| 1853 | + boolean wasSwap = true; | |
| 1854 | + | |
| 1855 | + // r precedes p and s points to the node up to which | |
| 1856 | + // comparisons are to be made | |
| 1857 | + while (s != head.next && wasSwap) { | |
| 1858 | + r = p = head; | |
| 1859 | + q = p.next; | |
| 1860 | + wasSwap = false; | |
| 1861 | + while (p != s) { | |
| 1862 | + if (p.x >= q.x) { | |
| 1863 | + wasSwap = true; | |
| 1864 | + if (p == head) { | |
| 1865 | + temp = q.next; | |
| 1866 | + q.next = p; | |
| 1867 | + p.next = temp; | |
| 1868 | + head = q; | |
| 1869 | + r = q; | |
| 1870 | + } else { | |
| 1871 | + temp = q.next; | |
| 1872 | + q.next = p; | |
| 1873 | + p.next = temp; | |
| 1874 | + r.next = q; | |
| 1875 | + r = q; | |
| 1876 | + } | |
| 1877 | + } else { | |
| 1878 | + r = p; | |
| 1879 | + p = p.next; | |
| 1880 | + } | |
| 1881 | + q = p.next; | |
| 1882 | + if (q == s) s = p; | |
| 1883 | + } | |
| 1884 | + } | |
| 1885 | + | |
| 1886 | + // correction of the back links in the double linked edge list | |
| 1887 | + p = head; | |
| 1888 | + q = null; | |
| 1889 | + while (p != null) { | |
| 1890 | + p.prev = q; | |
| 1891 | + q = p; | |
| 1892 | + p = p.next; | |
| 1893 | + } | |
| 1894 | + } | |
| 1895 | + } | |
| 1896 | + | |
| 1897 | + private static void FillPolygon(FillProcessHandler hnd, | |
| 1898 | + int fillRule) { | |
| 1899 | + int k, y, n; | |
| 1900 | + boolean drawing; | |
| 1901 | + Edge active; | |
| 1902 | + int rightBnd = hnd.dhnd.xMax - 1; | |
| 1903 | + FillData fd = hnd.fd; | |
| 1904 | + int yMin = fd.plgYMin; | |
| 1905 | + int yMax = fd.plgYMax; | |
| 1906 | + int hashSize = ((yMax - yMin)>>MDP_PREC) + 4; | |
| 1907 | + | |
| 1908 | + /* Because of support of the KEY_STROKE_CONTROL hint we are performing | |
| 1909 | + * shift of the coordinates at the higher level | |
| 1910 | + */ | |
| 1911 | + int hashOffset = ((yMin - 1) & MDP_W_MASK); | |
| 1912 | + | |
| 1913 | + /* Winding counter */ | |
| 1914 | + int counter; | |
| 1915 | + | |
| 1916 | + /* Calculating mask to be applied to the winding counter */ | |
| 1917 | + int counterMask = | |
| 1918 | + (fillRule == PathIterator.WIND_NON_ZERO)? -1:1; | |
| 1919 | + | |
| 1920 | + int pntOffset; | |
| 1921 | + List<Point> pnts = fd.plgPnts; | |
| 1922 | + n = pnts.size(); | |
| 1923 | + | |
| 1924 | + if (n <=1) return; | |
| 1925 | + | |
| 1926 | + Point[] yHash = new Point[hashSize]; | |
| 1927 | + | |
| 1928 | + /* Creating double linked list (prev, next links) describing path order | |
| 1929 | + * and hash table with points which fall between scanlines. nextByY | |
| 1930 | + * link is used for the points which are between same scanlines. | |
| 1931 | + * Scanlines are passed through the centers of the pixels. | |
| 1932 | + */ | |
| 1933 | + Point curpt = pnts.get(0); | |
| 1934 | + curpt.prev = null; | |
| 1935 | + for (int i = 0; i < n - 1; i++) { | |
| 1936 | + curpt = pnts.get(i); | |
| 1937 | + Point nextpt = pnts.get(i + 1); | |
| 1938 | + int curHashInd = (curpt.y - hashOffset - 1) >> MDP_PREC; | |
| 1939 | + curpt.nextByY = yHash[curHashInd]; | |
| 1940 | + yHash[curHashInd] = curpt; | |
| 1941 | + curpt.next = nextpt; | |
| 1942 | + nextpt.prev = curpt; | |
| 1943 | + } | |
| 1944 | + | |
| 1945 | + Point ept = pnts.get(n - 1); | |
| 1946 | + int curHashInd = (ept.y - hashOffset - 1) >> MDP_PREC; | |
| 1947 | + ept.nextByY = yHash[curHashInd]; | |
| 1948 | + yHash[curHashInd] = ept; | |
| 1949 | + | |
| 1950 | + ActiveEdgeList activeList = new ActiveEdgeList(); | |
| 1951 | + | |
| 1952 | + for (y=hashOffset + MDP_MULT,k = 0; | |
| 1953 | + y<=yMax && k < hashSize; y += MDP_MULT, k++) | |
| 1954 | + { | |
| 1955 | + for(Point pt = yHash[k];pt != null; pt=pt.nextByY) { | |
| 1956 | + /* pt.y should be inside hashed interval | |
| 1957 | + * assert(y-MDP_MULT <= pt.y && pt.y < y); | |
| 1958 | + */ | |
| 1959 | + if (pt.prev != null && !pt.prev.lastPoint) { | |
| 1960 | + if (pt.prev.edge != null && pt.prev.y <= y) { | |
| 1961 | + activeList.delete(pt.prev.edge); | |
| 1962 | + pt.prev.edge = null; | |
| 1963 | + } else if (pt.prev.y > y) { | |
| 1964 | + activeList.insert(pt.prev, y); | |
| 1965 | + } | |
| 1966 | + } | |
| 1967 | + | |
| 1968 | + if (!pt.lastPoint && pt.next != null) { | |
| 1969 | + if (pt.edge != null && pt.next.y <= y) { | |
| 1970 | + activeList.delete(pt.edge); | |
| 1971 | + pt.edge = null; | |
| 1972 | + } else if (pt.next.y > y) { | |
| 1973 | + activeList.insert(pt, y); | |
| 1974 | + } | |
| 1975 | + } | |
| 1976 | + } | |
| 1977 | + | |
| 1978 | + if (activeList.isEmpty()) continue; | |
| 1979 | + | |
| 1980 | + activeList.sort(); | |
| 1981 | + | |
| 1982 | + counter = 0; | |
| 1983 | + drawing = false; | |
| 1984 | + int xl, xr; | |
| 1985 | + xl = xr = hnd.dhnd.xMin; | |
| 1986 | + Edge curEdge = activeList.head; | |
| 1987 | + while (curEdge != null) { | |
| 1988 | + counter += curEdge.dir; | |
| 1989 | + if ((counter & counterMask) != 0 && !drawing) { | |
| 1990 | + xl = (curEdge.x + MDP_MULT - 1)>>MDP_PREC; | |
| 1991 | + drawing = true; | |
| 1992 | + } | |
| 1993 | + | |
| 1994 | + if ((counter & counterMask) == 0 && drawing) { | |
| 1995 | + xr = (curEdge.x - 1) >> MDP_PREC; | |
| 1996 | + if (xl <= xr) { | |
| 1997 | + hnd.dhnd.drawScanline(xl, xr, y >> MDP_PREC); | |
| 1998 | + } | |
| 1999 | + drawing = false; | |
| 2000 | + } | |
| 2001 | + | |
| 2002 | + curEdge.x += curEdge.dx; | |
| 2003 | + curEdge = curEdge.next; | |
| 2004 | + } | |
| 2005 | + | |
| 2006 | + /* Performing drawing till the right boundary (for correct | |
| 2007 | + * rendering shapes clipped at the right side) | |
| 2008 | + */ | |
| 2009 | + if (drawing && xl <= rightBnd) { | |
| 2010 | + | |
| 2011 | + /* Support of the strokeHint was added into the | |
| 2012 | + * draw and fill methods of the sun.java2d.pipe.LoopPipe | |
| 2013 | + */ | |
| 2014 | + hnd.dhnd.drawScanline(xl, rightBnd, y >> MDP_PREC); | |
| 2015 | + } | |
| 2016 | + } | |
| 2017 | + } | |
| 2018 | + | |
| 2019 | + private static class FillProcessHandler extends ProcessHandler { | |
| 2020 | + | |
| 2021 | + FillData fd; | |
| 2022 | + | |
| 2023 | + /* Note: For more easy reading of the code below each java version of | |
| 2024 | + * the macros from the ProcessPath.c preceded by the commented | |
| 2025 | + * origin call containing verbose names of the parameters | |
| 2026 | + */ | |
| 2027 | + public void processFixedLine(int x1, int y1, int x2, int y2, | |
| 2028 | + int[] pixelInfo, boolean checkBounds, | |
| 2029 | + boolean endSubPath) | |
| 2030 | + { | |
| 2031 | + int outXMin, outXMax, outYMin, outYMax; | |
| 2032 | + int res; | |
| 2033 | + | |
| 2034 | + /* There is no need to round line coordinates to the forward | |
| 2035 | + * differencing precision anymore. Such a rounding was used for | |
| 2036 | + * preventing the curve go out the endpoint (this sometimes does | |
| 2037 | + * not help). The problem was fixed in the forward differencing | |
| 2038 | + * loops. | |
| 2039 | + */ | |
| 2040 | + if (checkBounds) { | |
| 2041 | + boolean lastClipped; | |
| 2042 | + | |
| 2043 | + /* This function is used only for filling shapes, so there is no | |
| 2044 | + * check for the type of clipping | |
| 2045 | + */ | |
| 2046 | + int c[] = new int[]{x1, y1, x2, y2, 0, 0}; | |
| 2047 | + outXMin = (int)(dhnd.xMinf * MDP_MULT); | |
| 2048 | + outXMax = (int)(dhnd.xMaxf * MDP_MULT); | |
| 2049 | + outYMin = (int)(dhnd.yMinf * MDP_MULT); | |
| 2050 | + outYMax = (int)(dhnd.yMaxf * MDP_MULT); | |
| 2051 | + | |
| 2052 | + /* | |
| 2053 | + * TESTANDCLIP(outYMin, outYMax, y1, x1, y2, x2, res); | |
| 2054 | + */ | |
| 2055 | + res = TESTANDCLIP(outYMin, outYMax, c, 1, 0, 3, 2); | |
| 2056 | + if (res == CRES_INVISIBLE) return; | |
| 2057 | + | |
| 2058 | + /* | |
| 2059 | + * TESTANDCLIP(outYMin, outYMax, y2, x2, y1, x1, res); | |
| 2060 | + */ | |
| 2061 | + res = TESTANDCLIP(outYMin, outYMax, c, 3, 2, 1, 0); | |
| 2062 | + if (res == CRES_INVISIBLE) return; | |
| 2063 | + lastClipped = IS_CLIPPED(res); | |
| 2064 | + | |
| 2065 | + /* Clamping starting from first vertex of the the processed | |
| 2066 | + * segment | |
| 2067 | + * | |
| 2068 | + * CLIPCLAMP(outXMin, outXMax, x1, y1, x2, y2, x3, y3, res); | |
| 2069 | + */ | |
| 2070 | + res = CLIPCLAMP(outXMin, outXMax, c, 0, 1, 2, 3, 4, 5); | |
| 2071 | + | |
| 2072 | + /* Clamping only by left boundary */ | |
| 2073 | + if (res == CRES_MIN_CLIPPED) { | |
| 2074 | + processFixedLine(c[4], c[5], c[0], c[1], pixelInfo, | |
| 2075 | + false, lastClipped); | |
| 2076 | + | |
| 2077 | + } else if (res == CRES_INVISIBLE) { | |
| 2078 | + return; | |
| 2079 | + } | |
| 2080 | + | |
| 2081 | + /* Clamping starting from last vertex of the the processed | |
| 2082 | + * segment | |
| 2083 | + * | |
| 2084 | + * CLIPCLAMP(outXMin, outXMax, x2, y2, x1, y1, x3, y3, res); | |
| 2085 | + */ | |
| 2086 | + res = CLIPCLAMP(outXMin, outXMax, c, 2, 3, 0, 1, 4, 5); | |
| 2087 | + | |
| 2088 | + /* Checking if there was a clip by right boundary */ | |
| 2089 | + lastClipped = lastClipped || (res == CRES_MAX_CLIPPED); | |
| 2090 | + | |
| 2091 | + processFixedLine(c[0], c[1], c[2], c[3], pixelInfo, | |
| 2092 | + false, lastClipped); | |
| 2093 | + | |
| 2094 | + /* Clamping only by left boundary */ | |
| 2095 | + if (res == CRES_MIN_CLIPPED) { | |
| 2096 | + processFixedLine(c[2], c[3], c[4], c[5], pixelInfo, | |
| 2097 | + false, lastClipped); | |
| 2098 | + } | |
| 2099 | + | |
| 2100 | + return; | |
| 2101 | + } | |
| 2102 | + | |
| 2103 | + /* Adding first point of the line only in case of empty or just | |
| 2104 | + * finished path | |
| 2105 | + */ | |
| 2106 | + if (fd.isEmpty() || fd.isEnded()) { | |
| 2107 | + fd.addPoint(x1, y1, false); | |
| 2108 | + } | |
| 2109 | + | |
| 2110 | + fd.addPoint(x2, y2, false); | |
| 2111 | + | |
| 2112 | + if (endSubPath) { | |
| 2113 | + fd.setEnded(); | |
| 2114 | + } | |
| 2115 | + } | |
| 2116 | + | |
| 2117 | + FillProcessHandler(DrawHandler dhnd) { | |
| 2118 | + super(dhnd, PH_MODE_FILL_CLIP); | |
| 2119 | + this.fd = new FillData(); | |
| 2120 | + } | |
| 2121 | + | |
| 2122 | + public void processEndSubPath() { | |
| 2123 | + if (!fd.isEmpty()) { | |
| 2124 | + fd.setEnded(); | |
| 2125 | + } | |
| 2126 | + } | |
| 2127 | + } | |
| 2128 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,103 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.loops; | |
| 27 | + | |
| 28 | +public final class RenderCache { | |
| 29 | + final class Entry { | |
| 30 | + private SurfaceType src; | |
| 31 | + private CompositeType comp; | |
| 32 | + private SurfaceType dst; | |
| 33 | + private Object value; | |
| 34 | + | |
| 35 | + public Entry(SurfaceType src, | |
| 36 | + CompositeType comp, | |
| 37 | + SurfaceType dst, | |
| 38 | + Object value) | |
| 39 | + { | |
| 40 | + this.src = src; | |
| 41 | + this.comp = comp; | |
| 42 | + this.dst = dst; | |
| 43 | + this.value = value; | |
| 44 | + } | |
| 45 | + | |
| 46 | + public boolean matches(SurfaceType src, | |
| 47 | + CompositeType comp, | |
| 48 | + SurfaceType dst) | |
| 49 | + { | |
| 50 | + // bug 4725045: using equals() causes different SurfaceType | |
| 51 | + // objects with the same strings to match in the cache, which is | |
| 52 | + // not the behavior we want. Constrain the match to succeed only | |
| 53 | + // on object matches instead. | |
| 54 | + return ((this.src == src) && | |
| 55 | + (this.comp == comp) && | |
| 56 | + (this.dst == dst)); | |
| 57 | + } | |
| 58 | + | |
| 59 | + public Object getValue() { | |
| 60 | + return value; | |
| 61 | + } | |
| 62 | + } | |
| 63 | + | |
| 64 | + private Entry entries[]; | |
| 65 | + | |
| 66 | + public RenderCache(int size) { | |
| 67 | + entries = new Entry[size]; | |
| 68 | + } | |
| 69 | + | |
| 70 | + public synchronized Object get(SurfaceType src, | |
| 71 | + CompositeType comp, | |
| 72 | + SurfaceType dst) | |
| 73 | + { | |
| 74 | + int max = entries.length - 1; | |
| 75 | + for (int i = max; i >= 0; i--) { | |
| 76 | + Entry e = entries[i]; | |
| 77 | + if (e == null) { | |
| 78 | + break; | |
| 79 | + } | |
| 80 | + if (e.matches(src, comp, dst)) { | |
| 81 | + if (i < max - 4) { | |
| 82 | + System.arraycopy(entries, i+1, entries, i, max - i); | |
| 83 | + entries[max] = e; | |
| 84 | + } | |
| 85 | + return e.getValue(); | |
| 86 | + } | |
| 87 | + } | |
| 88 | + | |
| 89 | + return null; | |
| 90 | + } | |
| 91 | + | |
| 92 | + public synchronized void put(SurfaceType src, | |
| 93 | + CompositeType comp, | |
| 94 | + SurfaceType dst, | |
| 95 | + Object value) | |
| 96 | + { | |
| 97 | + Entry e = new Entry(src, comp, dst, value); | |
| 98 | + | |
| 99 | + int num = entries.length; | |
| 100 | + System.arraycopy(entries, 1, entries, 0, num - 1); | |
| 101 | + entries[num - 1] = e; | |
| 102 | + } | |
| 103 | +} | |
Binary file not shown.
| @@ -0,0 +1,55 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.loops; | |
| 27 | + | |
| 28 | +/* | |
| 29 | + * This class stores the various loops that are used by the | |
| 30 | + * standard rendering pipelines. The loops for a given instance | |
| 31 | + * of this class will all share the same destination type and the | |
| 32 | + * same supported paint and composite operation. | |
| 33 | + * Each instance of this class should be shared by all graphics | |
| 34 | + * objects that render onto the same type of destination with the | |
| 35 | + * same paint and composite combination to reduce the amount of | |
| 36 | + * time spent looking up loops appropriate for the current fill | |
| 37 | + * technique. | |
| 38 | + */ | |
| 39 | +public class RenderLoops { | |
| 40 | + | |
| 41 | + public static final int primTypeID = GraphicsPrimitive.makePrimTypeID(); | |
| 42 | + | |
| 43 | + public DrawLine drawLineLoop; | |
| 44 | + public FillRect fillRectLoop; | |
| 45 | + public DrawRect drawRectLoop; | |
| 46 | + public DrawPolygons drawPolygonsLoop; | |
| 47 | + public DrawPath drawPathLoop; | |
| 48 | + public FillPath fillPathLoop; | |
| 49 | + public FillSpans fillSpansLoop; | |
| 50 | + public FillParallelogram fillParallelogramLoop; | |
| 51 | + public DrawParallelogram drawParallelogramLoop; | |
| 52 | + public DrawGlyphList drawGlyphListLoop; | |
| 53 | + public DrawGlyphListAA drawGlyphListAALoop; | |
| 54 | + public DrawGlyphListLCD drawGlyphListLCDLoop; | |
| 55 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,156 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.loops; | |
| 27 | + | |
| 28 | +import java.awt.Composite; | |
| 29 | +import java.lang.ref.WeakReference; | |
| 30 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 31 | +import sun.java2d.SurfaceData; | |
| 32 | +import sun.java2d.pipe.Region; | |
| 33 | + | |
| 34 | +/** | |
| 35 | + * ScaledBlit | |
| 36 | + * 1) copies rectangle of pixels from one surface to another | |
| 37 | + * while scaling the pixels to meet the sizes specified | |
| 38 | + * 2) performs compositing of colors based upon a Composite | |
| 39 | + * parameter | |
| 40 | + * | |
| 41 | + * precise behavior is undefined if the source surface | |
| 42 | + * and the destination surface are the same surface | |
| 43 | + * with overlapping regions of pixels | |
| 44 | + */ | |
| 45 | + | |
| 46 | +public class ScaledBlit extends GraphicsPrimitive | |
| 47 | +{ | |
| 48 | + public static final String methodSignature = "ScaledBlit(...)".toString(); | |
| 49 | + | |
| 50 | + public static final int primTypeID = makePrimTypeID(); | |
| 51 | + | |
| 52 | + private static RenderCache blitcache = new RenderCache(20); | |
| 53 | + | |
| 54 | + public static ScaledBlit locate(SurfaceType srctype, | |
| 55 | + CompositeType comptype, | |
| 56 | + SurfaceType dsttype) | |
| 57 | + { | |
| 58 | + return (ScaledBlit) | |
| 59 | + GraphicsPrimitiveMgr.locate(primTypeID, | |
| 60 | + srctype, comptype, dsttype); | |
| 61 | + } | |
| 62 | + | |
| 63 | + public static ScaledBlit getFromCache(SurfaceType src, | |
| 64 | + CompositeType comp, | |
| 65 | + SurfaceType dst) | |
| 66 | + { | |
| 67 | + Object o = blitcache.get(src, comp, dst); | |
| 68 | + if (o != null) { | |
| 69 | + return (ScaledBlit) o; | |
| 70 | + } | |
| 71 | + ScaledBlit blit = locate(src, comp, dst); | |
| 72 | + if (blit == null) { | |
| 73 | + /* | |
| 74 | + System.out.println("blit loop not found for:"); | |
| 75 | + System.out.println("src: "+src); | |
| 76 | + System.out.println("comp: "+comp); | |
| 77 | + System.out.println("dst: "+dst); | |
| 78 | + */ | |
| 79 | + } else { | |
| 80 | + blitcache.put(src, comp, dst, blit); | |
| 81 | + } | |
| 82 | + return blit; | |
| 83 | + } | |
| 84 | + | |
| 85 | + protected ScaledBlit(SurfaceType srctype, | |
| 86 | + CompositeType comptype, | |
| 87 | + SurfaceType dsttype) | |
| 88 | + { | |
| 89 | + super(methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 90 | + } | |
| 91 | + | |
| 92 | + public ScaledBlit(long pNativePrim, | |
| 93 | + SurfaceType srctype, | |
| 94 | + CompositeType comptype, | |
| 95 | + SurfaceType dsttype) | |
| 96 | + { | |
| 97 | + super(pNativePrim, methodSignature, primTypeID, | |
| 98 | + srctype, comptype, dsttype); | |
| 99 | + } | |
| 100 | + | |
| 101 | + public native void Scale(SurfaceData src, SurfaceData dst, | |
| 102 | + Composite comp, Region clip, | |
| 103 | + int sx1, int sy1, | |
| 104 | + int sx2, int sy2, | |
| 105 | + double dx1, double dy1, | |
| 106 | + double dx2, double dy2); | |
| 107 | + | |
| 108 | + static { | |
| 109 | + GraphicsPrimitiveMgr.registerGeneral(new ScaledBlit(null, null, null)); | |
| 110 | + } | |
| 111 | + | |
| 112 | + public GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 113 | + CompositeType comptype, | |
| 114 | + SurfaceType dsttype) | |
| 115 | + { | |
| 116 | + /* | |
| 117 | + System.out.println("Constructing general blit for:"); | |
| 118 | + System.out.println("src: "+srctype); | |
| 119 | + System.out.println("comp: "+comptype); | |
| 120 | + System.out.println("dst: "+dsttype); | |
| 121 | + */ | |
| 122 | + return null; | |
| 123 | + } | |
| 124 | + | |
| 125 | + public GraphicsPrimitive traceWrap() { | |
| 126 | + return new TraceScaledBlit(this); | |
| 127 | + } | |
| 128 | + | |
| 129 | + private static class TraceScaledBlit extends ScaledBlit { | |
| 130 | + ScaledBlit target; | |
| 131 | + | |
| 132 | + public TraceScaledBlit(ScaledBlit target) { | |
| 133 | + super(target.getSourceType(), | |
| 134 | + target.getCompositeType(), | |
| 135 | + target.getDestType()); | |
| 136 | + this.target = target; | |
| 137 | + } | |
| 138 | + | |
| 139 | + public GraphicsPrimitive traceWrap() { | |
| 140 | + return this; | |
| 141 | + } | |
| 142 | + | |
| 143 | + public void Scale(SurfaceData src, SurfaceData dst, | |
| 144 | + Composite comp, Region clip, | |
| 145 | + int sx1, int sy1, | |
| 146 | + int sx2, int sy2, | |
| 147 | + double dx1, double dy1, | |
| 148 | + double dx2, double dy2) | |
| 149 | + { | |
| 150 | + tracePrimitive(target); | |
| 151 | + target.Scale(src, dst, comp, clip, | |
| 152 | + sx1, sy1, sx2, sy2, | |
| 153 | + dx1, dy1, dx2, dy2); | |
| 154 | + } | |
| 155 | + } | |
| 156 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,460 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.loops; | |
| 27 | + | |
| 28 | +import java.awt.image.BufferedImage; | |
| 29 | +import java.awt.image.ColorModel; | |
| 30 | +import sun.awt.image.PixelConverter; | |
| 31 | +import java.util.HashMap; | |
| 32 | + | |
| 33 | +/** | |
| 34 | + * A SurfaceType object provides a chained description of a type of | |
| 35 | + * drawing surface. The object will provide a single String constant | |
| 36 | + * descriptor which is one way of viewing or accessing a particular | |
| 37 | + * drawing surface as well as a pointer to another SurfaceType which | |
| 38 | + * describes the same drawing surface in a different (typically more | |
| 39 | + * generalized) way. | |
| 40 | + * <p> | |
| 41 | + * A more specific description of a surface is considered a "subtype" | |
| 42 | + * and a more general description is considered a "supertype". Thus, | |
| 43 | + * the deriveSubType method provides a way to create a new SurfaceType | |
| 44 | + * that is related to but more specific than an existing SurfaceType and | |
| 45 | + * the getSuperType method provides a way to ask a given SurfaceType | |
| 46 | + * for a more general way to describe the same surface. | |
| 47 | + * <p> | |
| 48 | + * Note that you cannot construct a brand new root for a chain since | |
| 49 | + * the constructor is private. Every chain of types must at some point | |
| 50 | + * derive from the Any node provided here using the deriveSubType() | |
| 51 | + * method. The presence of this common Any node on every chain | |
| 52 | + * ensures that all chains end with the DESC_ANY descriptor so that | |
| 53 | + * a suitable General GraphicsPrimitive object can be obtained for | |
| 54 | + * the indicated surface if all of the more specific searches fail. | |
| 55 | + */ | |
| 56 | +public final class SurfaceType { | |
| 57 | + | |
| 58 | + private static int unusedUID = 1; | |
| 59 | + private static HashMap surfaceUIDMap = new HashMap(100); | |
| 60 | + | |
| 61 | + /* | |
| 62 | + * CONSTANTS USED BY ALL PRIMITIVES TO DESCRIBE THE SURFACES | |
| 63 | + * THEY CAN OPERATE ON | |
| 64 | + */ | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * surface is unknown color model or sample model. | |
| 68 | + */ | |
| 69 | + public static final String | |
| 70 | + DESC_ANY = "Any Surface"; | |
| 71 | + | |
| 72 | + /** | |
| 73 | + * common surface formats defined in BufferedImage | |
| 74 | + */ | |
| 75 | + public static final String | |
| 76 | + DESC_INT_RGB = "Integer RGB"; | |
| 77 | + public static final String | |
| 78 | + DESC_INT_ARGB = "Integer ARGB"; | |
| 79 | + public static final String | |
| 80 | + DESC_INT_ARGB_PRE = "Integer ARGB Premultiplied"; | |
| 81 | + public static final String | |
| 82 | + DESC_INT_BGR = "Integer BGR"; | |
| 83 | + public static final String | |
| 84 | + DESC_3BYTE_BGR = "3 Byte BGR"; | |
| 85 | + public static final String | |
| 86 | + DESC_4BYTE_ABGR = "4 Byte ABGR"; | |
| 87 | + public static final String | |
| 88 | + DESC_4BYTE_ABGR_PRE = "4 Byte ABGR Premultiplied"; | |
| 89 | + public static final String | |
| 90 | + DESC_USHORT_565_RGB = "Short 565 RGB"; | |
| 91 | + public static final String | |
| 92 | + DESC_USHORT_555_RGB = "Short 555 RGB"; | |
| 93 | + public static final String | |
| 94 | + DESC_USHORT_555_RGBx= "Short 555 RGBx"; | |
| 95 | + public static final String | |
| 96 | + DESC_USHORT_4444_ARGB= "Short 4444 ARGB"; | |
| 97 | + public static final String | |
| 98 | + DESC_BYTE_GRAY = "8-bit Gray"; | |
| 99 | + public static final String | |
| 100 | + DESC_USHORT_INDEXED = "16-bit Indexed"; | |
| 101 | + public static final String | |
| 102 | + DESC_USHORT_GRAY = "16-bit Gray"; | |
| 103 | + public static final String | |
| 104 | + DESC_BYTE_BINARY = "Packed Binary Bitmap"; | |
| 105 | + public static final String | |
| 106 | + DESC_BYTE_INDEXED = "8-bit Indexed"; | |
| 107 | + | |
| 108 | + /** | |
| 109 | + * wildcard format which indicates that the GraphicsPrimitive | |
| 110 | + * is independent of the color model on an IntegerComponent | |
| 111 | + * sample model surface | |
| 112 | + */ | |
| 113 | + public static final String DESC_ANY_INT = "Any Discrete Integer"; | |
| 114 | + | |
| 115 | + /** | |
| 116 | + * wildcard format which indicates that the GraphicsPrimitive | |
| 117 | + * is independent of the color model on a ShortComponent | |
| 118 | + * sample model surface | |
| 119 | + */ | |
| 120 | + public static final String DESC_ANY_SHORT = "Any Discrete Short"; | |
| 121 | + | |
| 122 | + /** | |
| 123 | + * wildcard format which indicates that the GraphicsPrimitive | |
| 124 | + * is independent of the color model on a ByteComponent | |
| 125 | + * sample model surface | |
| 126 | + */ | |
| 127 | + public static final String DESC_ANY_BYTE = "Any Discrete Byte"; | |
| 128 | + | |
| 129 | + /** | |
| 130 | + * wildcard format which indicates that the GraphicsPrimitive | |
| 131 | + * operates on a surface with 3 component interleaved Raster and | |
| 132 | + * sample model and a ComponentColorModel with an arbitrary ordering | |
| 133 | + * of the RGB channels | |
| 134 | + */ | |
| 135 | + public static final String DESC_ANY_3BYTE = "Any 3 Byte Component"; | |
| 136 | + | |
| 137 | + /** | |
| 138 | + * wildcard format which indicates that the GraphicsPrimitive | |
| 139 | + * operates on a surface with 4 component interleaved Raster and | |
| 140 | + * sample model and a ComponentColorModel with an arbitrary ordering | |
| 141 | + * of the ARGB channels | |
| 142 | + */ | |
| 143 | + public static final String DESC_ANY_4BYTE = "Any 4 Byte Component"; | |
| 144 | + | |
| 145 | + /** | |
| 146 | + * wildcard format which indicates that the GraphicsPrimitive | |
| 147 | + * operates on a surface with a single component IntegerComponent | |
| 148 | + * sample model and a DirectColorModel with an arbitrary ordering | |
| 149 | + * of the RGB channels | |
| 150 | + */ | |
| 151 | + public static final String DESC_ANY_INT_DCM = "Any Integer DCM"; | |
| 152 | + | |
| 153 | + /** | |
| 154 | + * additional IntegerComponent types common on Windows | |
| 155 | + */ | |
| 156 | + public static final String DESC_INT_RGBx = "Integer RGBx"; | |
| 157 | + public static final String DESC_INT_BGRx = "Integer BGRx"; | |
| 158 | + | |
| 159 | + /** | |
| 160 | + * additional 3 byte format common on Windows | |
| 161 | + */ | |
| 162 | + public static final String DESC_3BYTE_RGB = "3 Byte RGB"; | |
| 163 | + | |
| 164 | + /** | |
| 165 | + * common formats for BITMASK transparency. | |
| 166 | + */ | |
| 167 | + public static final String DESC_INT_ARGB_BM = "Int ARGB (Bitmask)"; | |
| 168 | + public static final String DESC_BYTE_INDEXED_BM = "8-bit Indexed (Bitmask)"; | |
| 169 | + | |
| 170 | + /** | |
| 171 | + * Opaque 8-bit indexed images | |
| 172 | + */ | |
| 173 | + public static final String | |
| 174 | + DESC_BYTE_INDEXED_OPAQUE = "8-bit Indexed (Opaque)"; | |
| 175 | + | |
| 176 | + /** | |
| 177 | + * Special Gray Scale types for rendering loops. Really indexed | |
| 178 | + * types, but colormap has all gray values. | |
| 179 | + */ | |
| 180 | + public static final String DESC_INDEX8_GRAY = "8-bit Palettized Gray"; | |
| 181 | + public static final String DESC_INDEX12_GRAY = "12-bit Palettized Gray"; | |
| 182 | + | |
| 183 | + public static final String | |
| 184 | + DESC_BYTE_BINARY_1BIT = "Packed Binary 1-bit Bitmap"; | |
| 185 | + public static final String | |
| 186 | + DESC_BYTE_BINARY_2BIT = "Packed Binary 2-bit Bitmap"; | |
| 187 | + public static final String | |
| 188 | + DESC_BYTE_BINARY_4BIT = "Packed Binary 4-bit Bitmap"; | |
| 189 | + | |
| 190 | + /** | |
| 191 | + * Special type for describing the sources of loops that render the | |
| 192 | + * current foreground color or paint instead of copying colors from | |
| 193 | + * a source surface. | |
| 194 | + */ | |
| 195 | + public static final String DESC_ANY_PAINT = "Paint Object"; | |
| 196 | + public static final String DESC_ANY_COLOR = "Single Color"; | |
| 197 | + public static final String DESC_OPAQUE_COLOR = "Opaque Color"; | |
| 198 | + public static final String | |
| 199 | + DESC_GRADIENT_PAINT = "Gradient Paint"; | |
| 200 | + public static final String | |
| 201 | + DESC_OPAQUE_GRADIENT_PAINT = "Opaque Gradient Paint"; | |
| 202 | + public static final String | |
| 203 | + DESC_TEXTURE_PAINT = "Texture Paint"; | |
| 204 | + public static final String | |
| 205 | + DESC_OPAQUE_TEXTURE_PAINT = "Opaque Texture Paint"; | |
| 206 | + public static final String | |
| 207 | + DESC_LINEAR_GRADIENT_PAINT = "Linear Gradient Paint"; | |
| 208 | + public static final String | |
| 209 | + DESC_OPAQUE_LINEAR_GRADIENT_PAINT = "Opaque Linear Gradient Paint"; | |
| 210 | + public static final String | |
| 211 | + DESC_RADIAL_GRADIENT_PAINT = "Radial Gradient Paint"; | |
| 212 | + public static final String | |
| 213 | + DESC_OPAQUE_RADIAL_GRADIENT_PAINT = "Opaque Radial Gradient Paint"; | |
| 214 | + | |
| 215 | + /* | |
| 216 | + * END OF SURFACE TYPE CONSTANTS | |
| 217 | + */ | |
| 218 | + | |
| 219 | + | |
| 220 | + /** | |
| 221 | + * The root SurfaceType object for all chains of surface descriptions. | |
| 222 | + * The root uses the default PixelConverter object, which uses a given | |
| 223 | + * ColorModel object to calculate its pixelFor() values when asked. | |
| 224 | + * Any SurfaceType objects that are not created with a specific | |
| 225 | + * PixelConverter object will inherit this behavior from the root. | |
| 226 | + */ | |
| 227 | + public static final SurfaceType Any = | |
| 228 | + new SurfaceType(null, DESC_ANY, PixelConverter.instance); | |
| 229 | + | |
| 230 | + /* | |
| 231 | + * START OF SurfaceType OBJECTS FOR THE VARIOUS CONSTANTS | |
| 232 | + */ | |
| 233 | + | |
| 234 | + public static final SurfaceType | |
| 235 | + AnyInt = Any.deriveSubType(DESC_ANY_INT); | |
| 236 | + public static final SurfaceType | |
| 237 | + AnyShort = Any.deriveSubType(DESC_ANY_SHORT); | |
| 238 | + public static final SurfaceType | |
| 239 | + AnyByte = Any.deriveSubType(DESC_ANY_BYTE); | |
| 240 | + public static final SurfaceType | |
| 241 | + AnyByteBinary = Any.deriveSubType(DESC_BYTE_BINARY); | |
| 242 | + public static final SurfaceType | |
| 243 | + Any3Byte = Any.deriveSubType(DESC_ANY_3BYTE); | |
| 244 | + public static final SurfaceType | |
| 245 | + Any4Byte = Any.deriveSubType(DESC_ANY_4BYTE); | |
| 246 | + public static final SurfaceType | |
| 247 | + AnyDcm = AnyInt.deriveSubType(DESC_ANY_INT_DCM); | |
| 248 | + | |
| 249 | + public static final SurfaceType | |
| 250 | + Custom = Any; | |
| 251 | + public static final SurfaceType IntRgb = | |
| 252 | + AnyDcm.deriveSubType(DESC_INT_RGB, PixelConverter.Xrgb.instance); | |
| 253 | + | |
| 254 | + public static final SurfaceType IntArgb = | |
| 255 | + AnyDcm.deriveSubType(DESC_INT_ARGB, PixelConverter.Argb.instance); | |
| 256 | + | |
| 257 | + public static final SurfaceType IntArgbPre = | |
| 258 | + AnyDcm.deriveSubType(DESC_INT_ARGB_PRE, | |
| 259 | + PixelConverter.ArgbPre.instance); | |
| 260 | + | |
| 261 | + public static final SurfaceType IntBgr = | |
| 262 | + AnyDcm.deriveSubType(DESC_INT_BGR, PixelConverter.Xbgr.instance); | |
| 263 | + | |
| 264 | + public static final SurfaceType ThreeByteBgr = | |
| 265 | + Any3Byte.deriveSubType(DESC_3BYTE_BGR, PixelConverter.Xrgb.instance); | |
| 266 | + | |
| 267 | + public static final SurfaceType FourByteAbgr = | |
| 268 | + Any4Byte.deriveSubType(DESC_4BYTE_ABGR, PixelConverter.Rgba.instance); | |
| 269 | + | |
| 270 | + public static final SurfaceType FourByteAbgrPre = | |
| 271 | + Any4Byte.deriveSubType(DESC_4BYTE_ABGR_PRE, | |
| 272 | + PixelConverter.RgbaPre.instance); | |
| 273 | + | |
| 274 | + public static final SurfaceType Ushort565Rgb = | |
| 275 | + AnyShort.deriveSubType(DESC_USHORT_565_RGB, | |
| 276 | + PixelConverter.Ushort565Rgb.instance); | |
| 277 | + | |
| 278 | + public static final SurfaceType Ushort555Rgb = | |
| 279 | + AnyShort.deriveSubType(DESC_USHORT_555_RGB, | |
| 280 | + PixelConverter.Ushort555Rgb.instance); | |
| 281 | + | |
| 282 | + public static final SurfaceType Ushort555Rgbx = | |
| 283 | + AnyShort.deriveSubType(DESC_USHORT_555_RGBx, | |
| 284 | + PixelConverter.Ushort555Rgbx.instance); | |
| 285 | + | |
| 286 | + public static final SurfaceType Ushort4444Argb = | |
| 287 | + AnyShort.deriveSubType(DESC_USHORT_4444_ARGB, | |
| 288 | + PixelConverter.Ushort4444Argb.instance); | |
| 289 | + | |
| 290 | + public static final SurfaceType UshortIndexed = | |
| 291 | + AnyShort.deriveSubType(DESC_USHORT_INDEXED); | |
| 292 | + | |
| 293 | + public static final SurfaceType ByteGray = | |
| 294 | + AnyByte.deriveSubType(DESC_BYTE_GRAY, | |
| 295 | + PixelConverter.ByteGray.instance); | |
| 296 | + | |
| 297 | + public static final SurfaceType UshortGray = | |
| 298 | + AnyShort.deriveSubType(DESC_USHORT_GRAY, | |
| 299 | + PixelConverter.UshortGray.instance); | |
| 300 | + | |
| 301 | + public static final SurfaceType ByteBinary1Bit = | |
| 302 | + AnyByteBinary.deriveSubType(DESC_BYTE_BINARY_1BIT); | |
| 303 | + public static final SurfaceType ByteBinary2Bit = | |
| 304 | + AnyByteBinary.deriveSubType(DESC_BYTE_BINARY_2BIT); | |
| 305 | + public static final SurfaceType ByteBinary4Bit = | |
| 306 | + AnyByteBinary.deriveSubType(DESC_BYTE_BINARY_4BIT); | |
| 307 | + | |
| 308 | + public static final SurfaceType ByteIndexed = | |
| 309 | + AnyByte.deriveSubType(DESC_BYTE_INDEXED); | |
| 310 | + | |
| 311 | + public static final SurfaceType IntRgbx = | |
| 312 | + AnyDcm.deriveSubType(DESC_INT_RGBx, PixelConverter.Rgbx.instance); | |
| 313 | + | |
| 314 | + public static final SurfaceType IntBgrx = | |
| 315 | + AnyDcm.deriveSubType(DESC_INT_BGRx, PixelConverter.Bgrx.instance); | |
| 316 | + | |
| 317 | + public static final SurfaceType ThreeByteRgb = | |
| 318 | + Any3Byte.deriveSubType(DESC_3BYTE_RGB, PixelConverter.Xbgr.instance); | |
| 319 | + | |
| 320 | + public static final SurfaceType IntArgbBm = | |
| 321 | + AnyDcm.deriveSubType(DESC_INT_ARGB_BM, PixelConverter.ArgbBm.instance); | |
| 322 | + | |
| 323 | + public static final SurfaceType ByteIndexedBm = | |
| 324 | + ByteIndexed.deriveSubType(DESC_BYTE_INDEXED_BM); | |
| 325 | + | |
| 326 | + public static final SurfaceType ByteIndexedOpaque = | |
| 327 | + ByteIndexedBm.deriveSubType(DESC_BYTE_INDEXED_OPAQUE); | |
| 328 | + | |
| 329 | + public static final SurfaceType Index8Gray = | |
| 330 | + ByteIndexedOpaque.deriveSubType(DESC_INDEX8_GRAY); | |
| 331 | + | |
| 332 | + public static final SurfaceType Index12Gray = | |
| 333 | + Any.deriveSubType(DESC_INDEX12_GRAY); | |
| 334 | + | |
| 335 | + public static final SurfaceType AnyPaint = | |
| 336 | + Any.deriveSubType(DESC_ANY_PAINT); | |
| 337 | + | |
| 338 | + public static final SurfaceType AnyColor = | |
| 339 | + AnyPaint.deriveSubType(DESC_ANY_COLOR); | |
| 340 | + | |
| 341 | + public static final SurfaceType OpaqueColor = | |
| 342 | + AnyColor.deriveSubType(DESC_OPAQUE_COLOR); | |
| 343 | + | |
| 344 | + public static final SurfaceType GradientPaint = | |
| 345 | + AnyPaint.deriveSubType(DESC_GRADIENT_PAINT); | |
| 346 | + public static final SurfaceType OpaqueGradientPaint = | |
| 347 | + GradientPaint.deriveSubType(DESC_OPAQUE_GRADIENT_PAINT); | |
| 348 | + | |
| 349 | + public static final SurfaceType LinearGradientPaint = | |
| 350 | + AnyPaint.deriveSubType(DESC_LINEAR_GRADIENT_PAINT); | |
| 351 | + public static final SurfaceType OpaqueLinearGradientPaint = | |
| 352 | + LinearGradientPaint.deriveSubType(DESC_OPAQUE_LINEAR_GRADIENT_PAINT); | |
| 353 | + | |
| 354 | + public static final SurfaceType RadialGradientPaint = | |
| 355 | + AnyPaint.deriveSubType(DESC_RADIAL_GRADIENT_PAINT); | |
| 356 | + public static final SurfaceType OpaqueRadialGradientPaint = | |
| 357 | + RadialGradientPaint.deriveSubType(DESC_OPAQUE_RADIAL_GRADIENT_PAINT); | |
| 358 | + | |
| 359 | + public static final SurfaceType TexturePaint = | |
| 360 | + AnyPaint.deriveSubType(DESC_TEXTURE_PAINT); | |
| 361 | + public static final SurfaceType OpaqueTexturePaint = | |
| 362 | + TexturePaint.deriveSubType(DESC_OPAQUE_TEXTURE_PAINT); | |
| 363 | + | |
| 364 | + /* | |
| 365 | + * END OF SurfaceType OBJECTS FOR THE VARIOUS CONSTANTS | |
| 366 | + */ | |
| 367 | + | |
| 368 | + /** | |
| 369 | + * Return a new SurfaceType object which uses this object as its | |
| 370 | + * more general "supertype" descriptor. If no operation can be | |
| 371 | + * found that manipulates the type of surface described more exactly | |
| 372 | + * by desc, then this object will define the more relaxed specification | |
| 373 | + * of the surface that can be used to find a more general operator. | |
| 374 | + */ | |
| 375 | + public SurfaceType deriveSubType(String desc) { | |
| 376 | + return new SurfaceType(this, desc); | |
| 377 | + } | |
| 378 | + | |
| 379 | + public SurfaceType deriveSubType(String desc, | |
| 380 | + PixelConverter pixelConverter) { | |
| 381 | + return new SurfaceType(this, desc, pixelConverter); | |
| 382 | + } | |
| 383 | + | |
| 384 | + private int uniqueID; | |
| 385 | + private String desc; | |
| 386 | + private SurfaceType next; | |
| 387 | + protected PixelConverter pixelConverter; | |
| 388 | + | |
| 389 | + private SurfaceType(SurfaceType parent, String desc, | |
| 390 | + PixelConverter pixelConverter) { | |
| 391 | + next = parent; | |
| 392 | + this.desc = desc; | |
| 393 | + this.uniqueID = makeUniqueID(desc); | |
| 394 | + this.pixelConverter = pixelConverter; | |
| 395 | + } | |
| 396 | + | |
| 397 | + private SurfaceType(SurfaceType parent, String desc) { | |
| 398 | + next = parent; | |
| 399 | + this.desc = desc; | |
| 400 | + this.uniqueID = makeUniqueID(desc); | |
| 401 | + this.pixelConverter = parent.pixelConverter; | |
| 402 | + } | |
| 403 | + | |
| 404 | + public synchronized static final int makeUniqueID(String desc) { | |
| 405 | + Integer i = (Integer) surfaceUIDMap.get((Object) desc); | |
| 406 | + | |
| 407 | + if (i == null) { | |
| 408 | + if (unusedUID > 255) { | |
| 409 | + throw new InternalError("surface type id overflow"); | |
| 410 | + } | |
| 411 | + i = Integer.valueOf(unusedUID++); | |
| 412 | + surfaceUIDMap.put(desc, i); | |
| 413 | + } | |
| 414 | + return i.intValue(); | |
| 415 | + } | |
| 416 | + | |
| 417 | + public int getUniqueID() { | |
| 418 | + return uniqueID; | |
| 419 | + } | |
| 420 | + | |
| 421 | + public String getDescriptor() { | |
| 422 | + return desc; | |
| 423 | + } | |
| 424 | + | |
| 425 | + public SurfaceType getSuperType() { | |
| 426 | + return next; | |
| 427 | + } | |
| 428 | + | |
| 429 | + public PixelConverter getPixelConverter() { | |
| 430 | + return pixelConverter; | |
| 431 | + } | |
| 432 | + | |
| 433 | + public int pixelFor(int rgb, ColorModel cm) { | |
| 434 | + return pixelConverter.rgbToPixel(rgb, cm); | |
| 435 | + } | |
| 436 | + | |
| 437 | + public int rgbFor(int pixel, ColorModel cm) { | |
| 438 | + return pixelConverter.pixelToRgb(pixel, cm); | |
| 439 | + } | |
| 440 | + | |
| 441 | + public int getAlphaMask() { | |
| 442 | + return pixelConverter.getAlphaMask(); | |
| 443 | + } | |
| 444 | + | |
| 445 | + public int hashCode() { | |
| 446 | + return desc.hashCode(); | |
| 447 | + } | |
| 448 | + | |
| 449 | + public boolean equals(Object o) { | |
| 450 | + if (o instanceof SurfaceType) { | |
| 451 | + return (((SurfaceType) o).uniqueID == this.uniqueID); | |
| 452 | + } | |
| 453 | + return false; | |
| 454 | + } | |
| 455 | + | |
| 456 | + public String toString() { | |
| 457 | + return desc; | |
| 458 | + } | |
| 459 | + | |
| 460 | +} | |
| @@ -0,0 +1,157 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.loops; | |
| 27 | + | |
| 28 | +import java.awt.Composite; | |
| 29 | +import java.awt.geom.AffineTransform; | |
| 30 | +import java.lang.ref.WeakReference; | |
| 31 | +import sun.java2d.SurfaceData; | |
| 32 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 33 | +import sun.java2d.pipe.Region; | |
| 34 | + | |
| 35 | +/** | |
| 36 | + * TransformBlit | |
| 37 | + * 1) applies an AffineTransform to a rectangle of pixels while copying | |
| 38 | + * from one surface to another | |
| 39 | + * 2) performs compositing of colors based upon a Composite | |
| 40 | + * parameter | |
| 41 | + * | |
| 42 | + * precise behavior is undefined if the source surface | |
| 43 | + * and the destination surface are the same surface | |
| 44 | + * with overlapping regions of pixels | |
| 45 | + */ | |
| 46 | + | |
| 47 | +public class TransformBlit extends GraphicsPrimitive | |
| 48 | +{ | |
| 49 | + public static final String methodSignature = | |
| 50 | + "TransformBlit(...)".toString(); | |
| 51 | + | |
| 52 | + public static final int primTypeID = makePrimTypeID(); | |
| 53 | + | |
| 54 | + private static RenderCache blitcache = new RenderCache(10); | |
| 55 | + | |
| 56 | + public static TransformBlit locate(SurfaceType srctype, | |
| 57 | + CompositeType comptype, | |
| 58 | + SurfaceType dsttype) | |
| 59 | + { | |
| 60 | + return (TransformBlit) | |
| 61 | + GraphicsPrimitiveMgr.locate(primTypeID, | |
| 62 | + srctype, comptype, dsttype); | |
| 63 | + } | |
| 64 | + | |
| 65 | + public static TransformBlit getFromCache(SurfaceType src, | |
| 66 | + CompositeType comp, | |
| 67 | + SurfaceType dst) | |
| 68 | + { | |
| 69 | + Object o = blitcache.get(src, comp, dst); | |
| 70 | + if (o != null) { | |
| 71 | + return (TransformBlit) o; | |
| 72 | + } | |
| 73 | + TransformBlit blit = locate(src, comp, dst); | |
| 74 | + if (blit == null) { | |
| 75 | + /* | |
| 76 | + System.out.println("blit loop not found for:"); | |
| 77 | + System.out.println("src: "+src); | |
| 78 | + System.out.println("comp: "+comp); | |
| 79 | + System.out.println("dst: "+dst); | |
| 80 | + */ | |
| 81 | + } else { | |
| 82 | + blitcache.put(src, comp, dst, blit); | |
| 83 | + } | |
| 84 | + return blit; | |
| 85 | + } | |
| 86 | + | |
| 87 | + protected TransformBlit(SurfaceType srctype, | |
| 88 | + CompositeType comptype, | |
| 89 | + SurfaceType dsttype) | |
| 90 | + { | |
| 91 | + super(methodSignature, primTypeID, srctype, comptype, dsttype); | |
| 92 | + } | |
| 93 | + | |
| 94 | + public TransformBlit(long pNativePrim, | |
| 95 | + SurfaceType srctype, | |
| 96 | + CompositeType comptype, | |
| 97 | + SurfaceType dsttype) | |
| 98 | + { | |
| 99 | + super(pNativePrim, methodSignature, primTypeID, | |
| 100 | + srctype, comptype, dsttype); | |
| 101 | + } | |
| 102 | + | |
| 103 | + public native void Transform(SurfaceData src, SurfaceData dst, | |
| 104 | + Composite comp, Region clip, | |
| 105 | + AffineTransform at, int hint, | |
| 106 | + int srcx, int srcy, int dstx, int dsty, | |
| 107 | + int width, int height); | |
| 108 | + | |
| 109 | + // REMIND: do we have a general loop? | |
| 110 | + static { | |
| 111 | + GraphicsPrimitiveMgr.registerGeneral(new TransformBlit(null, null, | |
| 112 | + null)); | |
| 113 | + } | |
| 114 | + | |
| 115 | + public GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 116 | + CompositeType comptype, | |
| 117 | + SurfaceType dsttype) | |
| 118 | + { | |
| 119 | + /* | |
| 120 | + System.out.println("Constructing general blit for:"); | |
| 121 | + System.out.println("src: "+srctype); | |
| 122 | + System.out.println("comp: "+comptype); | |
| 123 | + System.out.println("dst: "+dsttype); | |
| 124 | + */ | |
| 125 | + return null; | |
| 126 | + } | |
| 127 | + | |
| 128 | + public GraphicsPrimitive traceWrap() { | |
| 129 | + return new TraceTransformBlit(this); | |
| 130 | + } | |
| 131 | + | |
| 132 | + private static class TraceTransformBlit extends TransformBlit { | |
| 133 | + TransformBlit target; | |
| 134 | + | |
| 135 | + public TraceTransformBlit(TransformBlit target) { | |
| 136 | + super(target.getSourceType(), | |
| 137 | + target.getCompositeType(), | |
| 138 | + target.getDestType()); | |
| 139 | + this.target = target; | |
| 140 | + } | |
| 141 | + | |
| 142 | + public GraphicsPrimitive traceWrap() { | |
| 143 | + return this; | |
| 144 | + } | |
| 145 | + | |
| 146 | + public void Transform(SurfaceData src, SurfaceData dst, | |
| 147 | + Composite comp, Region clip, | |
| 148 | + AffineTransform at, int hint, | |
| 149 | + int srcx, int srcy, int dstx, int dsty, | |
| 150 | + int width, int height) | |
| 151 | + { | |
| 152 | + tracePrimitive(target); | |
| 153 | + target.Transform(src, dst, comp, clip, at, hint, | |
| 154 | + srcx, srcy, dstx, dsty, width, height); | |
| 155 | + } | |
| 156 | + } | |
| 157 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,140 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.loops; | |
| 27 | + | |
| 28 | +import java.awt.Composite; | |
| 29 | +import java.awt.geom.AffineTransform; | |
| 30 | +import java.lang.ref.WeakReference; | |
| 31 | +import sun.java2d.SurfaceData; | |
| 32 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 33 | +import sun.java2d.pipe.Region; | |
| 34 | + | |
| 35 | +/** | |
| 36 | + * TransformHelper | |
| 37 | + * 1) applies an AffineTransform to a rectangle of pixels while copying | |
| 38 | + * from one surface to another | |
| 39 | + * 2) performs compositing of colors based upon a Composite | |
| 40 | + * parameter | |
| 41 | + * | |
| 42 | + * precise behavior is undefined if the source surface | |
| 43 | + * and the destination surface are the same surface | |
| 44 | + * with overlapping regions of pixels | |
| 45 | + */ | |
| 46 | +public class TransformHelper extends GraphicsPrimitive | |
| 47 | +{ | |
| 48 | + public static final String methodSignature = | |
| 49 | + "TransformHelper(...)".toString(); | |
| 50 | + | |
| 51 | + public static final int primTypeID = makePrimTypeID(); | |
| 52 | + | |
| 53 | + private static RenderCache helpercache = new RenderCache(10); | |
| 54 | + | |
| 55 | + public static TransformHelper locate(SurfaceType srctype) { | |
| 56 | + return (TransformHelper) | |
| 57 | + GraphicsPrimitiveMgr.locate(primTypeID, | |
| 58 | + srctype, | |
| 59 | + CompositeType.SrcNoEa, | |
| 60 | + SurfaceType.IntArgbPre); | |
| 61 | + } | |
| 62 | + | |
| 63 | + public static synchronized TransformHelper getFromCache(SurfaceType src) { | |
| 64 | + Object o = helpercache.get(src, null, null); | |
| 65 | + if (o != null) { | |
| 66 | + return (TransformHelper) o; | |
| 67 | + } | |
| 68 | + TransformHelper helper = locate(src); | |
| 69 | + if (helper == null) { | |
| 70 | + /* | |
| 71 | + System.out.println("helper loop not found for:"); | |
| 72 | + System.out.println("src: "+src); | |
| 73 | + */ | |
| 74 | + } else { | |
| 75 | + helpercache.put(src, null, null, helper); | |
| 76 | + } | |
| 77 | + return helper; | |
| 78 | + } | |
| 79 | + | |
| 80 | + protected TransformHelper(SurfaceType srctype) { | |
| 81 | + super(methodSignature, primTypeID, srctype, | |
| 82 | + CompositeType.SrcNoEa, | |
| 83 | + SurfaceType.IntArgbPre); | |
| 84 | + } | |
| 85 | + | |
| 86 | + public TransformHelper(long pNativePrim, SurfaceType srctype, | |
| 87 | + CompositeType comptype, | |
| 88 | + SurfaceType dsttype) | |
| 89 | + { | |
| 90 | + super(pNativePrim, methodSignature, primTypeID, | |
| 91 | + srctype, comptype, dsttype); | |
| 92 | + } | |
| 93 | + | |
| 94 | + public native void Transform(MaskBlit output, | |
| 95 | + SurfaceData src, SurfaceData dst, | |
| 96 | + Composite comp, Region clip, | |
| 97 | + AffineTransform itx, int txtype, | |
| 98 | + int sx1, int sy1, int sx2, int sy2, | |
| 99 | + int dx1, int dy1, int dx2, int dy2, | |
| 100 | + int edges[], int dxoff, int dyoff); | |
| 101 | + | |
| 102 | + public GraphicsPrimitive makePrimitive(SurfaceType srctype, | |
| 103 | + CompositeType comptype, | |
| 104 | + SurfaceType dsttype) | |
| 105 | + { | |
| 106 | + return null; | |
| 107 | + } | |
| 108 | + | |
| 109 | + public GraphicsPrimitive traceWrap() { | |
| 110 | + return new TraceTransformHelper(this); | |
| 111 | + } | |
| 112 | + | |
| 113 | + private static class TraceTransformHelper extends TransformHelper { | |
| 114 | + TransformHelper target; | |
| 115 | + | |
| 116 | + public TraceTransformHelper(TransformHelper target) { | |
| 117 | + super(target.getSourceType()); | |
| 118 | + this.target = target; | |
| 119 | + } | |
| 120 | + | |
| 121 | + public GraphicsPrimitive traceWrap() { | |
| 122 | + return this; | |
| 123 | + } | |
| 124 | + | |
| 125 | + public void Transform(MaskBlit output, | |
| 126 | + SurfaceData src, SurfaceData dst, | |
| 127 | + Composite comp, Region clip, | |
| 128 | + AffineTransform itx, int txtype, | |
| 129 | + int sx1, int sy1, int sx2, int sy2, | |
| 130 | + int dx1, int dy1, int dx2, int dy2, | |
| 131 | + int edges[], int dxoff, int dyoff) | |
| 132 | + { | |
| 133 | + tracePrimitive(target); | |
| 134 | + target.Transform(output, src, dst, comp, clip, itx, txtype, | |
| 135 | + sx1, sy1, sx2, sy2, | |
| 136 | + dx1, dy1, dx2, dy2, | |
| 137 | + edges, dxoff, dyoff); | |
| 138 | + } | |
| 139 | + } | |
| 140 | +} | |
Binary file not shown.
| @@ -0,0 +1,72 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 2002, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.loops; | |
| 27 | + | |
| 28 | +import java.awt.image.ColorModel; | |
| 29 | +import java.awt.Color; | |
| 30 | +import java.awt.Composite; | |
| 31 | +import java.awt.CompositeContext; | |
| 32 | +import java.awt.RenderingHints; | |
| 33 | +import sun.java2d.SurfaceData; | |
| 34 | +import sun.java2d.SunCompositeContext; | |
| 35 | + | |
| 36 | +/** | |
| 37 | + * Bitwise XOR Composite class. | |
| 38 | + */ | |
| 39 | + | |
| 40 | +public final class XORComposite implements Composite { | |
| 41 | + | |
| 42 | + Color xorColor; | |
| 43 | + int xorPixel; | |
| 44 | + int alphaMask; | |
| 45 | + | |
| 46 | + public XORComposite(Color xorColor, SurfaceData sd) { | |
| 47 | + this.xorColor = xorColor; | |
| 48 | + | |
| 49 | + SurfaceType sType = sd.getSurfaceType(); | |
| 50 | + | |
| 51 | + this.xorPixel = sd.pixelFor(xorColor.getRGB()); | |
| 52 | + this.alphaMask = sType.getAlphaMask(); | |
| 53 | + } | |
| 54 | + | |
| 55 | + public Color getXorColor() { | |
| 56 | + return xorColor; | |
| 57 | + } | |
| 58 | + | |
| 59 | + public int getXorPixel() { | |
| 60 | + return xorPixel; | |
| 61 | + } | |
| 62 | + | |
| 63 | + public int getAlphaMask() { | |
| 64 | + return alphaMask; | |
| 65 | + } | |
| 66 | + | |
| 67 | + public CompositeContext createContext(ColorModel srcColorModel, | |
| 68 | + ColorModel dstColorModel, | |
| 69 | + RenderingHints hints) { | |
| 70 | + return new SunCompositeContext(this, srcColorModel, dstColorModel); | |
| 71 | + } | |
| 72 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,38 @@ | ||
| 1 | +<../../../../../mkconfig | |
| 2 | + | |
| 3 | +TARG=\ | |
| 4 | + Blit.dis\ | |
| 5 | + BlitBg.dis\ | |
| 6 | + CompositeType.dis\ | |
| 7 | + CustomComponent.dis\ | |
| 8 | + DrawGlyphList.dis\ | |
| 9 | + DrawGlyphListAA.dis\ | |
| 10 | + DrawGlyphListLCD.dis\ | |
| 11 | + DrawLine.dis\ | |
| 12 | + DrawParallelogram.dis\ | |
| 13 | + DrawPath.dis\ | |
| 14 | + DrawPolygons.dis\ | |
| 15 | + DrawRect.dis\ | |
| 16 | + FillParallelogram.dis\ | |
| 17 | + FillPath.dis\ | |
| 18 | + FillRect.dis\ | |
| 19 | + FillSpans.dis\ | |
| 20 | + FontInfo.dis\ | |
| 21 | + GeneralRenderer.dis\ | |
| 22 | + GraphicsPrimitive.dis\ | |
| 23 | + GraphicsPrimitiveMgr.dis\ | |
| 24 | + GraphicsPrimitiveProxy.dis\ | |
| 25 | + MaskBlit.dis\ | |
| 26 | + MaskFill.dis\ | |
| 27 | + ProcessPath.dis\ | |
| 28 | + RenderCache.dis\ | |
| 29 | + RenderLoops.dis\ | |
| 30 | + ScaledBlit.dis\ | |
| 31 | + SurfaceType.dis\ | |
| 32 | + TransformBlit.dis\ | |
| 33 | + TransformHelper.dis\ | |
| 34 | + XORComposite.dis\ | |
| 35 | + | |
| 36 | +DISBIN=$ROOT/java/dis/java/java/sun/java2d/loops | |
| 37 | + | |
| 38 | +<$ROOT/mkfiles/mkjava | |
| @@ -0,0 +1,35 @@ | ||
| 1 | +<../../../../mkconfig | |
| 2 | + | |
| 3 | +DIRS=\ | |
| 4 | + cmm\ | |
| 5 | + loops\ | |
| 6 | + opengl\ | |
| 7 | + pipe\ | |
| 8 | + pisces\ | |
| 9 | + | |
| 10 | +TARG=\ | |
| 11 | + DefaultDisposerRecord.dis\ | |
| 12 | + DestSurfaceProvider.dis\ | |
| 13 | + Disposer.dis\ | |
| 14 | + DisposerRecord.dis\ | |
| 15 | + DisposerTarget.dis\ | |
| 16 | + FontSupport.dis\ | |
| 17 | + HeadlessGraphicsEnvironment.dis\ | |
| 18 | + InvalidPipeException.dis\ | |
| 19 | + NullSurfaceData.dis\ | |
| 20 | + Spans.dis\ | |
| 21 | + StateTrackable.dis\ | |
| 22 | + StateTrackableDelegate.dis\ | |
| 23 | + StateTracker.dis\ | |
| 24 | + SunCompositeContext.dis\ | |
| 25 | + SunGraphics2D.dis\ | |
| 26 | + SunGraphicsEnvironment.dis\ | |
| 27 | + Surface.dis\ | |
| 28 | + SurfaceData.dis\ | |
| 29 | + SurfaceDataProxy.dis\ | |
| 30 | + SurfaceManagerFactory.dis\ | |
| 31 | + | |
| 32 | +DISBIN=$ROOT/java/dis/java/java/sun/java2d | |
| 33 | + | |
| 34 | +<$ROOT/mkfiles/mkjava | |
| 35 | +<$ROOT/mkfiles/mksubdirs | |
| @@ -0,0 +1,762 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.opengl; | |
| 27 | + | |
| 28 | +import java.awt.Composite; | |
| 29 | +import java.awt.Transparency; | |
| 30 | +import java.awt.geom.AffineTransform; | |
| 31 | +import java.awt.image.AffineTransformOp; | |
| 32 | +import java.awt.image.BufferedImage; | |
| 33 | +import java.awt.image.BufferedImageOp; | |
| 34 | +import java.lang.ref.WeakReference; | |
| 35 | +import sun.java2d.SurfaceData; | |
| 36 | +import sun.java2d.loops.Blit; | |
| 37 | +import sun.java2d.loops.CompositeType; | |
| 38 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 39 | +import sun.java2d.loops.GraphicsPrimitiveMgr; | |
| 40 | +import sun.java2d.loops.ScaledBlit; | |
| 41 | +import sun.java2d.loops.SurfaceType; | |
| 42 | +import sun.java2d.loops.TransformBlit; | |
| 43 | +import sun.java2d.pipe.Region; | |
| 44 | +import sun.java2d.pipe.RenderBuffer; | |
| 45 | +import sun.java2d.pipe.RenderQueue; | |
| 46 | +import static sun.java2d.pipe.BufferedOpCodes.*; | |
| 47 | + | |
| 48 | +class OGLBlitLoops { | |
| 49 | + | |
| 50 | + static void register() { | |
| 51 | + Blit blitIntArgbPreToSurface = | |
| 52 | + new OGLSwToSurfaceBlit(SurfaceType.IntArgbPre, | |
| 53 | + OGLSurfaceData.PF_INT_ARGB_PRE); | |
| 54 | + Blit blitIntArgbPreToTexture = | |
| 55 | + new OGLSwToTextureBlit(SurfaceType.IntArgbPre, | |
| 56 | + OGLSurfaceData.PF_INT_ARGB_PRE); | |
| 57 | + | |
| 58 | + GraphicsPrimitive[] primitives = { | |
| 59 | + // surface->surface ops | |
| 60 | + new OGLSurfaceToSurfaceBlit(), | |
| 61 | + new OGLSurfaceToSurfaceScale(), | |
| 62 | + new OGLSurfaceToSurfaceTransform(), | |
| 63 | + | |
| 64 | + // render-to-texture surface->surface ops | |
| 65 | + new OGLRTTSurfaceToSurfaceBlit(), | |
| 66 | + new OGLRTTSurfaceToSurfaceScale(), | |
| 67 | + new OGLRTTSurfaceToSurfaceTransform(), | |
| 68 | + | |
| 69 | + // surface->sw ops | |
| 70 | + new OGLSurfaceToSwBlit(SurfaceType.IntArgb, | |
| 71 | + OGLSurfaceData.PF_INT_ARGB), | |
| 72 | + | |
| 73 | + // sw->surface ops | |
| 74 | + blitIntArgbPreToSurface, | |
| 75 | + new OGLSwToSurfaceBlit(SurfaceType.IntRgb, | |
| 76 | + OGLSurfaceData.PF_INT_RGB), | |
| 77 | + new OGLSwToSurfaceBlit(SurfaceType.IntRgbx, | |
| 78 | + OGLSurfaceData.PF_INT_RGBX), | |
| 79 | + new OGLSwToSurfaceBlit(SurfaceType.IntBgr, | |
| 80 | + OGLSurfaceData.PF_INT_BGR), | |
| 81 | + new OGLSwToSurfaceBlit(SurfaceType.IntBgrx, | |
| 82 | + OGLSurfaceData.PF_INT_BGRX), | |
| 83 | + new OGLSwToSurfaceBlit(SurfaceType.ThreeByteBgr, | |
| 84 | + OGLSurfaceData.PF_3BYTE_BGR), | |
| 85 | + new OGLSwToSurfaceBlit(SurfaceType.Ushort565Rgb, | |
| 86 | + OGLSurfaceData.PF_USHORT_565_RGB), | |
| 87 | + new OGLSwToSurfaceBlit(SurfaceType.Ushort555Rgb, | |
| 88 | + OGLSurfaceData.PF_USHORT_555_RGB), | |
| 89 | + new OGLSwToSurfaceBlit(SurfaceType.Ushort555Rgbx, | |
| 90 | + OGLSurfaceData.PF_USHORT_555_RGBX), | |
| 91 | + new OGLSwToSurfaceBlit(SurfaceType.ByteGray, | |
| 92 | + OGLSurfaceData.PF_BYTE_GRAY), | |
| 93 | + new OGLSwToSurfaceBlit(SurfaceType.UshortGray, | |
| 94 | + OGLSurfaceData.PF_USHORT_GRAY), | |
| 95 | + new OGLGeneralBlit(OGLSurfaceData.OpenGLSurface, | |
| 96 | + CompositeType.AnyAlpha, | |
| 97 | + blitIntArgbPreToSurface), | |
| 98 | + | |
| 99 | + new OGLSwToSurfaceScale(SurfaceType.IntRgb, | |
| 100 | + OGLSurfaceData.PF_INT_RGB), | |
| 101 | + new OGLSwToSurfaceScale(SurfaceType.IntRgbx, | |
| 102 | + OGLSurfaceData.PF_INT_RGBX), | |
| 103 | + new OGLSwToSurfaceScale(SurfaceType.IntBgr, | |
| 104 | + OGLSurfaceData.PF_INT_BGR), | |
| 105 | + new OGLSwToSurfaceScale(SurfaceType.IntBgrx, | |
| 106 | + OGLSurfaceData.PF_INT_BGRX), | |
| 107 | + new OGLSwToSurfaceScale(SurfaceType.ThreeByteBgr, | |
| 108 | + OGLSurfaceData.PF_3BYTE_BGR), | |
| 109 | + new OGLSwToSurfaceScale(SurfaceType.Ushort565Rgb, | |
| 110 | + OGLSurfaceData.PF_USHORT_565_RGB), | |
| 111 | + new OGLSwToSurfaceScale(SurfaceType.Ushort555Rgb, | |
| 112 | + OGLSurfaceData.PF_USHORT_555_RGB), | |
| 113 | + new OGLSwToSurfaceScale(SurfaceType.Ushort555Rgbx, | |
| 114 | + OGLSurfaceData.PF_USHORT_555_RGBX), | |
| 115 | + new OGLSwToSurfaceScale(SurfaceType.ByteGray, | |
| 116 | + OGLSurfaceData.PF_BYTE_GRAY), | |
| 117 | + new OGLSwToSurfaceScale(SurfaceType.UshortGray, | |
| 118 | + OGLSurfaceData.PF_USHORT_GRAY), | |
| 119 | + new OGLSwToSurfaceScale(SurfaceType.IntArgbPre, | |
| 120 | + OGLSurfaceData.PF_INT_ARGB_PRE), | |
| 121 | + | |
| 122 | + new OGLSwToSurfaceTransform(SurfaceType.IntRgb, | |
| 123 | + OGLSurfaceData.PF_INT_RGB), | |
| 124 | + new OGLSwToSurfaceTransform(SurfaceType.IntRgbx, | |
| 125 | + OGLSurfaceData.PF_INT_RGBX), | |
| 126 | + new OGLSwToSurfaceTransform(SurfaceType.IntBgr, | |
| 127 | + OGLSurfaceData.PF_INT_BGR), | |
| 128 | + new OGLSwToSurfaceTransform(SurfaceType.IntBgrx, | |
| 129 | + OGLSurfaceData.PF_INT_BGRX), | |
| 130 | + new OGLSwToSurfaceTransform(SurfaceType.ThreeByteBgr, | |
| 131 | + OGLSurfaceData.PF_3BYTE_BGR), | |
| 132 | + new OGLSwToSurfaceTransform(SurfaceType.Ushort565Rgb, | |
| 133 | + OGLSurfaceData.PF_USHORT_565_RGB), | |
| 134 | + new OGLSwToSurfaceTransform(SurfaceType.Ushort555Rgb, | |
| 135 | + OGLSurfaceData.PF_USHORT_555_RGB), | |
| 136 | + new OGLSwToSurfaceTransform(SurfaceType.Ushort555Rgbx, | |
| 137 | + OGLSurfaceData.PF_USHORT_555_RGBX), | |
| 138 | + new OGLSwToSurfaceTransform(SurfaceType.ByteGray, | |
| 139 | + OGLSurfaceData.PF_BYTE_GRAY), | |
| 140 | + new OGLSwToSurfaceTransform(SurfaceType.UshortGray, | |
| 141 | + OGLSurfaceData.PF_USHORT_GRAY), | |
| 142 | + new OGLSwToSurfaceTransform(SurfaceType.IntArgbPre, | |
| 143 | + OGLSurfaceData.PF_INT_ARGB_PRE), | |
| 144 | + | |
| 145 | + // texture->surface ops | |
| 146 | + new OGLTextureToSurfaceBlit(), | |
| 147 | + new OGLTextureToSurfaceScale(), | |
| 148 | + new OGLTextureToSurfaceTransform(), | |
| 149 | + | |
| 150 | + // sw->texture ops | |
| 151 | + blitIntArgbPreToTexture, | |
| 152 | + new OGLSwToTextureBlit(SurfaceType.IntRgb, | |
| 153 | + OGLSurfaceData.PF_INT_RGB), | |
| 154 | + new OGLSwToTextureBlit(SurfaceType.IntRgbx, | |
| 155 | + OGLSurfaceData.PF_INT_RGBX), | |
| 156 | + new OGLSwToTextureBlit(SurfaceType.IntBgr, | |
| 157 | + OGLSurfaceData.PF_INT_BGR), | |
| 158 | + new OGLSwToTextureBlit(SurfaceType.IntBgrx, | |
| 159 | + OGLSurfaceData.PF_INT_BGRX), | |
| 160 | + new OGLSwToTextureBlit(SurfaceType.ThreeByteBgr, | |
| 161 | + OGLSurfaceData.PF_3BYTE_BGR), | |
| 162 | + new OGLSwToTextureBlit(SurfaceType.Ushort565Rgb, | |
| 163 | + OGLSurfaceData.PF_USHORT_565_RGB), | |
| 164 | + new OGLSwToTextureBlit(SurfaceType.Ushort555Rgb, | |
| 165 | + OGLSurfaceData.PF_USHORT_555_RGB), | |
| 166 | + new OGLSwToTextureBlit(SurfaceType.Ushort555Rgbx, | |
| 167 | + OGLSurfaceData.PF_USHORT_555_RGBX), | |
| 168 | + new OGLSwToTextureBlit(SurfaceType.ByteGray, | |
| 169 | + OGLSurfaceData.PF_BYTE_GRAY), | |
| 170 | + new OGLSwToTextureBlit(SurfaceType.UshortGray, | |
| 171 | + OGLSurfaceData.PF_USHORT_GRAY), | |
| 172 | + new OGLGeneralBlit(OGLSurfaceData.OpenGLTexture, | |
| 173 | + CompositeType.SrcNoEa, | |
| 174 | + blitIntArgbPreToTexture), | |
| 175 | + }; | |
| 176 | + GraphicsPrimitiveMgr.register(primitives); | |
| 177 | + } | |
| 178 | + | |
| 179 | + /** | |
| 180 | + * The following offsets are used to pack the parameters in | |
| 181 | + * createPackedParams(). (They are also used at the native level when | |
| 182 | + * unpacking the params.) | |
| 183 | + */ | |
| 184 | + private static final int OFFSET_SRCTYPE = 16; | |
| 185 | + private static final int OFFSET_HINT = 8; | |
| 186 | + private static final int OFFSET_TEXTURE = 3; | |
| 187 | + private static final int OFFSET_RTT = 2; | |
| 188 | + private static final int OFFSET_XFORM = 1; | |
| 189 | + private static final int OFFSET_ISOBLIT = 0; | |
| 190 | + | |
| 191 | + /** | |
| 192 | + * Packs the given parameters into a single int value in order to save | |
| 193 | + * space on the rendering queue. | |
| 194 | + */ | |
| 195 | + private static int createPackedParams(boolean isoblit, boolean texture, | |
| 196 | + boolean rtt, boolean xform, | |
| 197 | + int hint, int srctype) | |
| 198 | + { | |
| 199 | + return | |
| 200 | + ((srctype << OFFSET_SRCTYPE) | | |
| 201 | + (hint << OFFSET_HINT ) | | |
| 202 | + ((texture ? 1 : 0) << OFFSET_TEXTURE) | | |
| 203 | + ((rtt ? 1 : 0) << OFFSET_RTT ) | | |
| 204 | + ((xform ? 1 : 0) << OFFSET_XFORM ) | | |
| 205 | + ((isoblit ? 1 : 0) << OFFSET_ISOBLIT)); | |
| 206 | + } | |
| 207 | + | |
| 208 | + /** | |
| 209 | + * Enqueues a BLIT operation with the given parameters. Note that the | |
| 210 | + * RenderQueue lock must be held before calling this method. | |
| 211 | + */ | |
| 212 | + private static void enqueueBlit(RenderQueue rq, | |
| 213 | + SurfaceData src, SurfaceData dst, | |
| 214 | + int packedParams, | |
| 215 | + int sx1, int sy1, | |
| 216 | + int sx2, int sy2, | |
| 217 | + double dx1, double dy1, | |
| 218 | + double dx2, double dy2) | |
| 219 | + { | |
| 220 | + // assert rq.lock.isHeldByCurrentThread(); | |
| 221 | + RenderBuffer buf = rq.getBuffer(); | |
| 222 | + rq.ensureCapacityAndAlignment(72, 24); | |
| 223 | + buf.putInt(BLIT); | |
| 224 | + buf.putInt(packedParams); | |
| 225 | + buf.putInt(sx1).putInt(sy1); | |
| 226 | + buf.putInt(sx2).putInt(sy2); | |
| 227 | + buf.putDouble(dx1).putDouble(dy1); | |
| 228 | + buf.putDouble(dx2).putDouble(dy2); | |
| 229 | + buf.putLong(src.getNativeOps()); | |
| 230 | + buf.putLong(dst.getNativeOps()); | |
| 231 | + } | |
| 232 | + | |
| 233 | + static void Blit(SurfaceData srcData, SurfaceData dstData, | |
| 234 | + Composite comp, Region clip, | |
| 235 | + AffineTransform xform, int hint, | |
| 236 | + int sx1, int sy1, | |
| 237 | + int sx2, int sy2, | |
| 238 | + double dx1, double dy1, | |
| 239 | + double dx2, double dy2, | |
| 240 | + int srctype, boolean texture) | |
| 241 | + { | |
| 242 | + int ctxflags = 0; | |
| 243 | + if (srcData.getTransparency() == Transparency.OPAQUE) { | |
| 244 | + ctxflags |= OGLContext.SRC_IS_OPAQUE; | |
| 245 | + } | |
| 246 | + | |
| 247 | + OGLRenderQueue rq = OGLRenderQueue.getInstance(); | |
| 248 | + rq.lock(); | |
| 249 | + try { | |
| 250 | + // make sure the RenderQueue keeps a hard reference to the | |
| 251 | + // source (sysmem) SurfaceData to prevent it from being | |
| 252 | + // disposed while the operation is processed on the QFT | |
| 253 | + rq.addReference(srcData); | |
| 254 | + | |
| 255 | + OGLSurfaceData oglDst = (OGLSurfaceData)dstData; | |
| 256 | + if (texture) { | |
| 257 | + // make sure we have a current context before uploading | |
| 258 | + // the sysmem data to the texture object | |
| 259 | + OGLGraphicsConfig gc = oglDst.getOGLGraphicsConfig(); | |
| 260 | + OGLContext.setScratchSurface(gc); | |
| 261 | + } else { | |
| 262 | + OGLContext.validateContext(oglDst, oglDst, | |
| 263 | + clip, comp, xform, null, null, | |
| 264 | + ctxflags); | |
| 265 | + } | |
| 266 | + | |
| 267 | + int packedParams = createPackedParams(false, texture, | |
| 268 | + false, xform != null, | |
| 269 | + hint, srctype); | |
| 270 | + enqueueBlit(rq, srcData, dstData, | |
| 271 | + packedParams, | |
| 272 | + sx1, sy1, sx2, sy2, | |
| 273 | + dx1, dy1, dx2, dy2); | |
| 274 | + | |
| 275 | + // always flush immediately, since we (currently) have no means | |
| 276 | + // of tracking changes to the system memory surface | |
| 277 | + rq.flushNow(); | |
| 278 | + } finally { | |
| 279 | + rq.unlock(); | |
| 280 | + } | |
| 281 | + } | |
| 282 | + | |
| 283 | + /** | |
| 284 | + * Note: The srcImg and biop parameters are only used when invoked | |
| 285 | + * from the OGLBufImgOps.renderImageWithOp() method; in all other cases, | |
| 286 | + * this method can be called with null values for those two parameters, | |
| 287 | + * and they will be effectively ignored. | |
| 288 | + */ | |
| 289 | + static void IsoBlit(SurfaceData srcData, SurfaceData dstData, | |
| 290 | + BufferedImage srcImg, BufferedImageOp biop, | |
| 291 | + Composite comp, Region clip, | |
| 292 | + AffineTransform xform, int hint, | |
| 293 | + int sx1, int sy1, | |
| 294 | + int sx2, int sy2, | |
| 295 | + double dx1, double dy1, | |
| 296 | + double dx2, double dy2, | |
| 297 | + boolean texture) | |
| 298 | + { | |
| 299 | + int ctxflags = 0; | |
| 300 | + if (srcData.getTransparency() == Transparency.OPAQUE) { | |
| 301 | + ctxflags |= OGLContext.SRC_IS_OPAQUE; | |
| 302 | + } | |
| 303 | + | |
| 304 | + OGLRenderQueue rq = OGLRenderQueue.getInstance(); | |
| 305 | + rq.lock(); | |
| 306 | + try { | |
| 307 | + OGLSurfaceData oglSrc = (OGLSurfaceData)srcData; | |
| 308 | + OGLSurfaceData oglDst = (OGLSurfaceData)dstData; | |
| 309 | + int srctype = oglSrc.getType(); | |
| 310 | + boolean rtt; | |
| 311 | + OGLSurfaceData srcCtxData; | |
| 312 | + if (srctype == OGLSurfaceData.TEXTURE) { | |
| 313 | + // the source is a regular texture object; we substitute | |
| 314 | + // the destination surface for the purposes of making a | |
| 315 | + // context current | |
| 316 | + rtt = false; | |
| 317 | + srcCtxData = oglDst; | |
| 318 | + } else { | |
| 319 | + // the source is a pbuffer, backbuffer, or render-to-texture | |
| 320 | + // surface; we set rtt to true to differentiate this kind | |
| 321 | + // of surface from a regular texture object | |
| 322 | + rtt = true; | |
| 323 | + if (srctype == OGLSurfaceData.FBOBJECT) { | |
| 324 | + srcCtxData = oglDst; | |
| 325 | + } else { | |
| 326 | + srcCtxData = oglSrc; | |
| 327 | + } | |
| 328 | + } | |
| 329 | + | |
| 330 | + OGLContext.validateContext(srcCtxData, oglDst, | |
| 331 | + clip, comp, xform, null, null, | |
| 332 | + ctxflags); | |
| 333 | + | |
| 334 | + if (biop != null) { | |
| 335 | + OGLBufImgOps.enableBufImgOp(rq, oglSrc, srcImg, biop); | |
| 336 | + } | |
| 337 | + | |
| 338 | + int packedParams = createPackedParams(true, texture, | |
| 339 | + rtt, xform != null, | |
| 340 | + hint, 0 /*unused*/); | |
| 341 | + enqueueBlit(rq, srcData, dstData, | |
| 342 | + packedParams, | |
| 343 | + sx1, sy1, sx2, sy2, | |
| 344 | + dx1, dy1, dx2, dy2); | |
| 345 | + | |
| 346 | + if (biop != null) { | |
| 347 | + OGLBufImgOps.disableBufImgOp(rq, biop); | |
| 348 | + } | |
| 349 | + | |
| 350 | + if (rtt && (oglDst.getType() == OGLSurfaceData.WINDOW)) { | |
| 351 | + // we only have to flush immediately when copying from a | |
| 352 | + // (non-texture) surface to the screen; otherwise Swing apps | |
| 353 | + // might appear unresponsive until the auto-flush completes | |
| 354 | + rq.flushNow(); | |
| 355 | + } | |
| 356 | + } finally { | |
| 357 | + rq.unlock(); | |
| 358 | + } | |
| 359 | + } | |
| 360 | +} | |
| 361 | + | |
| 362 | +class OGLSurfaceToSurfaceBlit extends Blit { | |
| 363 | + | |
| 364 | + OGLSurfaceToSurfaceBlit() { | |
| 365 | + super(OGLSurfaceData.OpenGLSurface, | |
| 366 | + CompositeType.AnyAlpha, | |
| 367 | + OGLSurfaceData.OpenGLSurface); | |
| 368 | + } | |
| 369 | + | |
| 370 | + public void Blit(SurfaceData src, SurfaceData dst, | |
| 371 | + Composite comp, Region clip, | |
| 372 | + int sx, int sy, int dx, int dy, int w, int h) | |
| 373 | + { | |
| 374 | + OGLBlitLoops.IsoBlit(src, dst, | |
| 375 | + null, null, | |
| 376 | + comp, clip, null, | |
| 377 | + AffineTransformOp.TYPE_NEAREST_NEIGHBOR, | |
| 378 | + sx, sy, sx+w, sy+h, | |
| 379 | + dx, dy, dx+w, dy+h, | |
| 380 | + false); | |
| 381 | + } | |
| 382 | +} | |
| 383 | + | |
| 384 | +class OGLSurfaceToSurfaceScale extends ScaledBlit { | |
| 385 | + | |
| 386 | + OGLSurfaceToSurfaceScale() { | |
| 387 | + super(OGLSurfaceData.OpenGLSurface, | |
| 388 | + CompositeType.AnyAlpha, | |
| 389 | + OGLSurfaceData.OpenGLSurface); | |
| 390 | + } | |
| 391 | + | |
| 392 | + public void Scale(SurfaceData src, SurfaceData dst, | |
| 393 | + Composite comp, Region clip, | |
| 394 | + int sx1, int sy1, | |
| 395 | + int sx2, int sy2, | |
| 396 | + double dx1, double dy1, | |
| 397 | + double dx2, double dy2) | |
| 398 | + { | |
| 399 | + OGLBlitLoops.IsoBlit(src, dst, | |
| 400 | + null, null, | |
| 401 | + comp, clip, null, | |
| 402 | + AffineTransformOp.TYPE_NEAREST_NEIGHBOR, | |
| 403 | + sx1, sy1, sx2, sy2, | |
| 404 | + dx1, dy1, dx2, dy2, | |
| 405 | + false); | |
| 406 | + } | |
| 407 | +} | |
| 408 | + | |
| 409 | +class OGLSurfaceToSurfaceTransform extends TransformBlit { | |
| 410 | + | |
| 411 | + OGLSurfaceToSurfaceTransform() { | |
| 412 | + super(OGLSurfaceData.OpenGLSurface, | |
| 413 | + CompositeType.AnyAlpha, | |
| 414 | + OGLSurfaceData.OpenGLSurface); | |
| 415 | + } | |
| 416 | + | |
| 417 | + public void Transform(SurfaceData src, SurfaceData dst, | |
| 418 | + Composite comp, Region clip, | |
| 419 | + AffineTransform at, int hint, | |
| 420 | + int sx, int sy, int dx, int dy, | |
| 421 | + int w, int h) | |
| 422 | + { | |
| 423 | + OGLBlitLoops.IsoBlit(src, dst, | |
| 424 | + null, null, | |
| 425 | + comp, clip, at, hint, | |
| 426 | + sx, sy, sx+w, sy+h, | |
| 427 | + dx, dy, dx+w, dy+h, | |
| 428 | + false); | |
| 429 | + } | |
| 430 | +} | |
| 431 | + | |
| 432 | +class OGLRTTSurfaceToSurfaceBlit extends Blit { | |
| 433 | + | |
| 434 | + OGLRTTSurfaceToSurfaceBlit() { | |
| 435 | + super(OGLSurfaceData.OpenGLSurfaceRTT, | |
| 436 | + CompositeType.AnyAlpha, | |
| 437 | + OGLSurfaceData.OpenGLSurface); | |
| 438 | + } | |
| 439 | + | |
| 440 | + public void Blit(SurfaceData src, SurfaceData dst, | |
| 441 | + Composite comp, Region clip, | |
| 442 | + int sx, int sy, int dx, int dy, int w, int h) | |
| 443 | + { | |
| 444 | + OGLBlitLoops.IsoBlit(src, dst, | |
| 445 | + null, null, | |
| 446 | + comp, clip, null, | |
| 447 | + AffineTransformOp.TYPE_NEAREST_NEIGHBOR, | |
| 448 | + sx, sy, sx+w, sy+h, | |
| 449 | + dx, dy, dx+w, dy+h, | |
| 450 | + true); | |
| 451 | + } | |
| 452 | +} | |
| 453 | + | |
| 454 | +class OGLRTTSurfaceToSurfaceScale extends ScaledBlit { | |
| 455 | + | |
| 456 | + OGLRTTSurfaceToSurfaceScale() { | |
| 457 | + super(OGLSurfaceData.OpenGLSurfaceRTT, | |
| 458 | + CompositeType.AnyAlpha, | |
| 459 | + OGLSurfaceData.OpenGLSurface); | |
| 460 | + } | |
| 461 | + | |
| 462 | + public void Scale(SurfaceData src, SurfaceData dst, | |
| 463 | + Composite comp, Region clip, | |
| 464 | + int sx1, int sy1, | |
| 465 | + int sx2, int sy2, | |
| 466 | + double dx1, double dy1, | |
| 467 | + double dx2, double dy2) | |
| 468 | + { | |
| 469 | + OGLBlitLoops.IsoBlit(src, dst, | |
| 470 | + null, null, | |
| 471 | + comp, clip, null, | |
| 472 | + AffineTransformOp.TYPE_NEAREST_NEIGHBOR, | |
| 473 | + sx1, sy1, sx2, sy2, | |
| 474 | + dx1, dy1, dx2, dy2, | |
| 475 | + true); | |
| 476 | + } | |
| 477 | +} | |
| 478 | + | |
| 479 | +class OGLRTTSurfaceToSurfaceTransform extends TransformBlit { | |
| 480 | + | |
| 481 | + OGLRTTSurfaceToSurfaceTransform() { | |
| 482 | + super(OGLSurfaceData.OpenGLSurfaceRTT, | |
| 483 | + CompositeType.AnyAlpha, | |
| 484 | + OGLSurfaceData.OpenGLSurface); | |
| 485 | + } | |
| 486 | + | |
| 487 | + public void Transform(SurfaceData src, SurfaceData dst, | |
| 488 | + Composite comp, Region clip, | |
| 489 | + AffineTransform at, int hint, | |
| 490 | + int sx, int sy, int dx, int dy, int w, int h) | |
| 491 | + { | |
| 492 | + OGLBlitLoops.IsoBlit(src, dst, | |
| 493 | + null, null, | |
| 494 | + comp, clip, at, hint, | |
| 495 | + sx, sy, sx+w, sy+h, | |
| 496 | + dx, dy, dx+w, dy+h, | |
| 497 | + true); | |
| 498 | + } | |
| 499 | +} | |
| 500 | + | |
| 501 | +class OGLSurfaceToSwBlit extends Blit { | |
| 502 | + | |
| 503 | + private int typeval; | |
| 504 | + | |
| 505 | + // REMIND: destination will actually be opaque/premultiplied... | |
| 506 | + OGLSurfaceToSwBlit(SurfaceType dstType, int typeval) { | |
| 507 | + super(OGLSurfaceData.OpenGLSurface, | |
| 508 | + CompositeType.SrcNoEa, | |
| 509 | + dstType); | |
| 510 | + this.typeval = typeval; | |
| 511 | + } | |
| 512 | + | |
| 513 | + public void Blit(SurfaceData src, SurfaceData dst, | |
| 514 | + Composite comp, Region clip, | |
| 515 | + int sx, int sy, int dx, int dy, | |
| 516 | + int w, int h) | |
| 517 | + { | |
| 518 | + OGLRenderQueue rq = OGLRenderQueue.getInstance(); | |
| 519 | + rq.lock(); | |
| 520 | + try { | |
| 521 | + // make sure the RenderQueue keeps a hard reference to the | |
| 522 | + // destination (sysmem) SurfaceData to prevent it from being | |
| 523 | + // disposed while the operation is processed on the QFT | |
| 524 | + rq.addReference(dst); | |
| 525 | + | |
| 526 | + RenderBuffer buf = rq.getBuffer(); | |
| 527 | + OGLContext.validateContext((OGLSurfaceData)src); | |
| 528 | + | |
| 529 | + rq.ensureCapacityAndAlignment(48, 32); | |
| 530 | + buf.putInt(SURFACE_TO_SW_BLIT); | |
| 531 | + buf.putInt(sx).putInt(sy); | |
| 532 | + buf.putInt(dx).putInt(dy); | |
| 533 | + buf.putInt(w).putInt(h); | |
| 534 | + buf.putInt(typeval); | |
| 535 | + buf.putLong(src.getNativeOps()); | |
| 536 | + buf.putLong(dst.getNativeOps()); | |
| 537 | + | |
| 538 | + // always flush immediately | |
| 539 | + rq.flushNow(); | |
| 540 | + } finally { | |
| 541 | + rq.unlock(); | |
| 542 | + } | |
| 543 | + } | |
| 544 | +} | |
| 545 | + | |
| 546 | +class OGLSwToSurfaceBlit extends Blit { | |
| 547 | + | |
| 548 | + private int typeval; | |
| 549 | + | |
| 550 | + OGLSwToSurfaceBlit(SurfaceType srcType, int typeval) { | |
| 551 | + super(srcType, | |
| 552 | + CompositeType.AnyAlpha, | |
| 553 | + OGLSurfaceData.OpenGLSurface); | |
| 554 | + this.typeval = typeval; | |
| 555 | + } | |
| 556 | + | |
| 557 | + public void Blit(SurfaceData src, SurfaceData dst, | |
| 558 | + Composite comp, Region clip, | |
| 559 | + int sx, int sy, int dx, int dy, int w, int h) | |
| 560 | + { | |
| 561 | + OGLBlitLoops.Blit(src, dst, | |
| 562 | + comp, clip, null, | |
| 563 | + AffineTransformOp.TYPE_NEAREST_NEIGHBOR, | |
| 564 | + sx, sy, sx+w, sy+h, | |
| 565 | + dx, dy, dx+w, dy+h, | |
| 566 | + typeval, false); | |
| 567 | + } | |
| 568 | +} | |
| 569 | + | |
| 570 | +class OGLSwToSurfaceScale extends ScaledBlit { | |
| 571 | + | |
| 572 | + private int typeval; | |
| 573 | + | |
| 574 | + OGLSwToSurfaceScale(SurfaceType srcType, int typeval) { | |
| 575 | + super(srcType, | |
| 576 | + CompositeType.AnyAlpha, | |
| 577 | + OGLSurfaceData.OpenGLSurface); | |
| 578 | + this.typeval = typeval; | |
| 579 | + } | |
| 580 | + | |
| 581 | + public void Scale(SurfaceData src, SurfaceData dst, | |
| 582 | + Composite comp, Region clip, | |
| 583 | + int sx1, int sy1, | |
| 584 | + int sx2, int sy2, | |
| 585 | + double dx1, double dy1, | |
| 586 | + double dx2, double dy2) | |
| 587 | + { | |
| 588 | + OGLBlitLoops.Blit(src, dst, | |
| 589 | + comp, clip, null, | |
| 590 | + AffineTransformOp.TYPE_NEAREST_NEIGHBOR, | |
| 591 | + sx1, sy1, sx2, sy2, | |
| 592 | + dx1, dy1, dx2, dy2, | |
| 593 | + typeval, false); | |
| 594 | + } | |
| 595 | +} | |
| 596 | + | |
| 597 | +class OGLSwToSurfaceTransform extends TransformBlit { | |
| 598 | + | |
| 599 | + private int typeval; | |
| 600 | + | |
| 601 | + OGLSwToSurfaceTransform(SurfaceType srcType, int typeval) { | |
| 602 | + super(srcType, | |
| 603 | + CompositeType.AnyAlpha, | |
| 604 | + OGLSurfaceData.OpenGLSurface); | |
| 605 | + this.typeval = typeval; | |
| 606 | + } | |
| 607 | + | |
| 608 | + public void Transform(SurfaceData src, SurfaceData dst, | |
| 609 | + Composite comp, Region clip, | |
| 610 | + AffineTransform at, int hint, | |
| 611 | + int sx, int sy, int dx, int dy, int w, int h) | |
| 612 | + { | |
| 613 | + OGLBlitLoops.Blit(src, dst, | |
| 614 | + comp, clip, at, hint, | |
| 615 | + sx, sy, sx+w, sy+h, | |
| 616 | + dx, dy, dx+w, dy+h, | |
| 617 | + typeval, false); | |
| 618 | + } | |
| 619 | +} | |
| 620 | + | |
| 621 | +class OGLSwToTextureBlit extends Blit { | |
| 622 | + | |
| 623 | + private int typeval; | |
| 624 | + | |
| 625 | + OGLSwToTextureBlit(SurfaceType srcType, int typeval) { | |
| 626 | + super(srcType, | |
| 627 | + CompositeType.SrcNoEa, | |
| 628 | + OGLSurfaceData.OpenGLTexture); | |
| 629 | + this.typeval = typeval; | |
| 630 | + } | |
| 631 | + | |
| 632 | + public void Blit(SurfaceData src, SurfaceData dst, | |
| 633 | + Composite comp, Region clip, | |
| 634 | + int sx, int sy, int dx, int dy, int w, int h) | |
| 635 | + { | |
| 636 | + OGLBlitLoops.Blit(src, dst, | |
| 637 | + comp, clip, null, | |
| 638 | + AffineTransformOp.TYPE_NEAREST_NEIGHBOR, | |
| 639 | + sx, sy, sx+w, sy+h, | |
| 640 | + dx, dy, dx+w, dy+h, | |
| 641 | + typeval, true); | |
| 642 | + } | |
| 643 | +} | |
| 644 | + | |
| 645 | +class OGLTextureToSurfaceBlit extends Blit { | |
| 646 | + | |
| 647 | + OGLTextureToSurfaceBlit() { | |
| 648 | + super(OGLSurfaceData.OpenGLTexture, | |
| 649 | + CompositeType.AnyAlpha, | |
| 650 | + OGLSurfaceData.OpenGLSurface); | |
| 651 | + } | |
| 652 | + | |
| 653 | + public void Blit(SurfaceData src, SurfaceData dst, | |
| 654 | + Composite comp, Region clip, | |
| 655 | + int sx, int sy, int dx, int dy, int w, int h) | |
| 656 | + { | |
| 657 | + OGLBlitLoops.IsoBlit(src, dst, | |
| 658 | + null, null, | |
| 659 | + comp, clip, null, | |
| 660 | + AffineTransformOp.TYPE_NEAREST_NEIGHBOR, | |
| 661 | + sx, sy, sx+w, sy+h, | |
| 662 | + dx, dy, dx+w, dy+h, | |
| 663 | + true); | |
| 664 | + } | |
| 665 | +} | |
| 666 | + | |
| 667 | +class OGLTextureToSurfaceScale extends ScaledBlit { | |
| 668 | + | |
| 669 | + OGLTextureToSurfaceScale() { | |
| 670 | + super(OGLSurfaceData.OpenGLTexture, | |
| 671 | + CompositeType.AnyAlpha, | |
| 672 | + OGLSurfaceData.OpenGLSurface); | |
| 673 | + } | |
| 674 | + | |
| 675 | + public void Scale(SurfaceData src, SurfaceData dst, | |
| 676 | + Composite comp, Region clip, | |
| 677 | + int sx1, int sy1, | |
| 678 | + int sx2, int sy2, | |
| 679 | + double dx1, double dy1, | |
| 680 | + double dx2, double dy2) | |
| 681 | + { | |
| 682 | + OGLBlitLoops.IsoBlit(src, dst, | |
| 683 | + null, null, | |
| 684 | + comp, clip, null, | |
| 685 | + AffineTransformOp.TYPE_NEAREST_NEIGHBOR, | |
| 686 | + sx1, sy1, sx2, sy2, | |
| 687 | + dx1, dy1, dx2, dy2, | |
| 688 | + true); | |
| 689 | + } | |
| 690 | +} | |
| 691 | + | |
| 692 | +class OGLTextureToSurfaceTransform extends TransformBlit { | |
| 693 | + | |
| 694 | + OGLTextureToSurfaceTransform() { | |
| 695 | + super(OGLSurfaceData.OpenGLTexture, | |
| 696 | + CompositeType.AnyAlpha, | |
| 697 | + OGLSurfaceData.OpenGLSurface); | |
| 698 | + } | |
| 699 | + | |
| 700 | + public void Transform(SurfaceData src, SurfaceData dst, | |
| 701 | + Composite comp, Region clip, | |
| 702 | + AffineTransform at, int hint, | |
| 703 | + int sx, int sy, int dx, int dy, | |
| 704 | + int w, int h) | |
| 705 | + { | |
| 706 | + OGLBlitLoops.IsoBlit(src, dst, | |
| 707 | + null, null, | |
| 708 | + comp, clip, at, hint, | |
| 709 | + sx, sy, sx+w, sy+h, | |
| 710 | + dx, dy, dx+w, dy+h, | |
| 711 | + true); | |
| 712 | + } | |
| 713 | +} | |
| 714 | + | |
| 715 | +/** | |
| 716 | + * This general Blit implemenation converts any source surface to an | |
| 717 | + * intermediate IntArgbPre surface, and then uses the more specific | |
| 718 | + * IntArgbPre->OpenGLSurface/Texture loop to get the intermediate | |
| 719 | + * (premultiplied) surface down to OpenGL. | |
| 720 | + */ | |
| 721 | +class OGLGeneralBlit extends Blit { | |
| 722 | + | |
| 723 | + private Blit performop; | |
| 724 | + private WeakReference srcTmp; | |
| 725 | + | |
| 726 | + OGLGeneralBlit(SurfaceType dstType, | |
| 727 | + CompositeType compType, | |
| 728 | + Blit performop) | |
| 729 | + { | |
| 730 | + super(SurfaceType.Any, compType, dstType); | |
| 731 | + this.performop = performop; | |
| 732 | + } | |
| 733 | + | |
| 734 | + public synchronized void Blit(SurfaceData src, SurfaceData dst, | |
| 735 | + Composite comp, Region clip, | |
| 736 | + int sx, int sy, int dx, int dy, | |
| 737 | + int w, int h) | |
| 738 | + { | |
| 739 | + Blit convertsrc = Blit.getFromCache(src.getSurfaceType(), | |
| 740 | + CompositeType.SrcNoEa, | |
| 741 | + SurfaceType.IntArgbPre); | |
| 742 | + | |
| 743 | + SurfaceData cachedSrc = null; | |
| 744 | + if (srcTmp != null) { | |
| 745 | + // use cached intermediate surface, if available | |
| 746 | + cachedSrc = (SurfaceData)srcTmp.get(); | |
| 747 | + } | |
| 748 | + | |
| 749 | + // convert source to IntArgbPre | |
| 750 | + src = convertFrom(convertsrc, src, sx, sy, w, h, | |
| 751 | + cachedSrc, BufferedImage.TYPE_INT_ARGB_PRE); | |
| 752 | + | |
| 753 | + // copy IntArgbPre intermediate surface to OpenGL surface | |
| 754 | + performop.Blit(src, dst, comp, clip, | |
| 755 | + 0, 0, dx, dy, w, h); | |
| 756 | + | |
| 757 | + if (src != cachedSrc) { | |
| 758 | + // cache the intermediate surface | |
| 759 | + srcTmp = new WeakReference(src); | |
| 760 | + } | |
| 761 | + } | |
| 762 | +} | |
| @@ -0,0 +1,115 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.opengl; | |
| 27 | + | |
| 28 | +import java.awt.image.AffineTransformOp; | |
| 29 | +import java.awt.image.BufferedImage; | |
| 30 | +import java.awt.image.BufferedImageOp; | |
| 31 | +import java.awt.image.ConvolveOp; | |
| 32 | +import java.awt.image.LookupOp; | |
| 33 | +import java.awt.image.RescaleOp; | |
| 34 | +import sun.java2d.SunGraphics2D; | |
| 35 | +import sun.java2d.SurfaceData; | |
| 36 | +import sun.java2d.loops.CompositeType; | |
| 37 | +import sun.java2d.pipe.BufferedBufImgOps; | |
| 38 | +import static sun.java2d.opengl.OGLContext.OGLContextCaps.*; | |
| 39 | + | |
| 40 | +class OGLBufImgOps extends BufferedBufImgOps { | |
| 41 | + | |
| 42 | + /** | |
| 43 | + * This method is called from OGLDrawImage.transformImage() only. It | |
| 44 | + * validates the provided BufferedImageOp to determine whether the op | |
| 45 | + * is one that can be accelerated by the OGL pipeline. If the operation | |
| 46 | + * cannot be completed for any reason, this method returns false; | |
| 47 | + * otherwise, the given BufferedImage is rendered to the destination | |
| 48 | + * using the provided BufferedImageOp and this method returns true. | |
| 49 | + */ | |
| 50 | + static boolean renderImageWithOp(SunGraphics2D sg, BufferedImage img, | |
| 51 | + BufferedImageOp biop, int x, int y) | |
| 52 | + { | |
| 53 | + // Validate the provided BufferedImage (make sure it is one that | |
| 54 | + // is supported, and that its properties are acceleratable) | |
| 55 | + if (biop instanceof ConvolveOp) { | |
| 56 | + if (!isConvolveOpValid((ConvolveOp)biop)) { | |
| 57 | + return false; | |
| 58 | + } | |
| 59 | + } else if (biop instanceof RescaleOp) { | |
| 60 | + if (!isRescaleOpValid((RescaleOp)biop, img)) { | |
| 61 | + return false; | |
| 62 | + } | |
| 63 | + } else if (biop instanceof LookupOp) { | |
| 64 | + if (!isLookupOpValid((LookupOp)biop, img)) { | |
| 65 | + return false; | |
| 66 | + } | |
| 67 | + } else { | |
| 68 | + // No acceleration for other BufferedImageOps (yet) | |
| 69 | + return false; | |
| 70 | + } | |
| 71 | + | |
| 72 | + SurfaceData dstData = sg.surfaceData; | |
| 73 | + if (!(dstData instanceof OGLSurfaceData) || | |
| 74 | + (sg.interpolationType == AffineTransformOp.TYPE_BICUBIC) || | |
| 75 | + (sg.compositeState > SunGraphics2D.COMP_ALPHA)) | |
| 76 | + { | |
| 77 | + return false; | |
| 78 | + } | |
| 79 | + | |
| 80 | + SurfaceData srcData = | |
| 81 | + dstData.getSourceSurfaceData(img, sg.TRANSFORM_ISIDENT, | |
| 82 | + CompositeType.SrcOver, null); | |
| 83 | + if (!(srcData instanceof OGLSurfaceData)) { | |
| 84 | + // REMIND: this hack tries to ensure that we have a cached texture | |
| 85 | + srcData = | |
| 86 | + dstData.getSourceSurfaceData(img, sg.TRANSFORM_ISIDENT, | |
| 87 | + CompositeType.SrcOver, null); | |
| 88 | + if (!(srcData instanceof OGLSurfaceData)) { | |
| 89 | + return false; | |
| 90 | + } | |
| 91 | + } | |
| 92 | + | |
| 93 | + // Verify that the source surface is actually a texture and | |
| 94 | + // that the operation is supported | |
| 95 | + OGLSurfaceData oglSrc = (OGLSurfaceData)srcData; | |
| 96 | + OGLGraphicsConfig gc = oglSrc.getOGLGraphicsConfig(); | |
| 97 | + if (oglSrc.getType() != OGLSurfaceData.TEXTURE || | |
| 98 | + !gc.isCapPresent(CAPS_EXT_BIOP_SHADER)) | |
| 99 | + { | |
| 100 | + return false; | |
| 101 | + } | |
| 102 | + | |
| 103 | + int sw = img.getWidth(); | |
| 104 | + int sh = img.getHeight(); | |
| 105 | + OGLBlitLoops.IsoBlit(srcData, dstData, | |
| 106 | + img, biop, | |
| 107 | + sg.composite, sg.getCompClip(), | |
| 108 | + sg.transform, sg.interpolationType, | |
| 109 | + 0, 0, sw, sh, | |
| 110 | + x, y, x+sw, y+sh, | |
| 111 | + true); | |
| 112 | + | |
| 113 | + return true; | |
| 114 | + } | |
| 115 | +} | |
| @@ -0,0 +1,220 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.opengl; | |
| 27 | + | |
| 28 | +import sun.java2d.pipe.BufferedContext; | |
| 29 | +import sun.java2d.pipe.RenderBuffer; | |
| 30 | +import sun.java2d.pipe.RenderQueue; | |
| 31 | +import sun.java2d.pipe.hw.ContextCapabilities; | |
| 32 | +import static sun.java2d.pipe.BufferedOpCodes.*; | |
| 33 | +import static sun.java2d.pipe.hw.ContextCapabilities.*; | |
| 34 | + | |
| 35 | +/** | |
| 36 | + * Note that the RenderQueue lock must be acquired before calling any of | |
| 37 | + * the methods in this class. | |
| 38 | + */ | |
| 39 | +public class OGLContext extends BufferedContext { | |
| 40 | + | |
| 41 | + private final OGLGraphicsConfig config; | |
| 42 | + | |
| 43 | + OGLContext(RenderQueue rq, OGLGraphicsConfig config) { | |
| 44 | + super(rq); | |
| 45 | + this.config = config; | |
| 46 | + } | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * Convenience method that delegates to setScratchSurface() below. | |
| 50 | + */ | |
| 51 | + static void setScratchSurface(OGLGraphicsConfig gc) { | |
| 52 | + setScratchSurface(gc.getNativeConfigInfo()); | |
| 53 | + } | |
| 54 | + | |
| 55 | + /** | |
| 56 | + * Makes the given GraphicsConfig's context current to its associated | |
| 57 | + * "scratch surface". Each GraphicsConfig maintains a native context | |
| 58 | + * (GLXContext on Unix, HGLRC on Windows) as well as a native pbuffer | |
| 59 | + * known as the "scratch surface". By making the context current to the | |
| 60 | + * scratch surface, we are assured that we have a current context for | |
| 61 | + * the relevant GraphicsConfig, and can therefore perform operations | |
| 62 | + * depending on the capabilities of that GraphicsConfig. For example, | |
| 63 | + * if the GraphicsConfig supports the GL_ARB_texture_non_power_of_two | |
| 64 | + * extension, then we should be able to make a non-pow2 texture for this | |
| 65 | + * GraphicsConfig once we make the context current to the scratch surface. | |
| 66 | + * | |
| 67 | + * This method should be used for operations with an OpenGL texture | |
| 68 | + * as the destination surface (e.g. a sw->texture blit loop), or in those | |
| 69 | + * situations where we may not otherwise have a current context (e.g. | |
| 70 | + * when disposing a texture-based surface). | |
| 71 | + */ | |
| 72 | + static void setScratchSurface(long pConfigInfo) { | |
| 73 | + // assert OGLRenderQueue.getInstance().lock.isHeldByCurrentThread(); | |
| 74 | + | |
| 75 | + // invalidate the current context | |
| 76 | + currentContext = null; | |
| 77 | + | |
| 78 | + // set the scratch context | |
| 79 | + OGLRenderQueue rq = OGLRenderQueue.getInstance(); | |
| 80 | + RenderBuffer buf = rq.getBuffer(); | |
| 81 | + rq.ensureCapacityAndAlignment(12, 4); | |
| 82 | + buf.putInt(SET_SCRATCH_SURFACE); | |
| 83 | + buf.putLong(pConfigInfo); | |
| 84 | + } | |
| 85 | + | |
| 86 | + /** | |
| 87 | + * Invalidates the currentContext field to ensure that we properly | |
| 88 | + * revalidate the OGLContext (make it current, etc.) next time through | |
| 89 | + * the validate() method. This is typically invoked from methods | |
| 90 | + * that affect the current context state (e.g. disposing a context or | |
| 91 | + * surface). | |
| 92 | + */ | |
| 93 | + static void invalidateCurrentContext() { | |
| 94 | + // assert OGLRenderQueue.getInstance().lock.isHeldByCurrentThread(); | |
| 95 | + | |
| 96 | + // invalidate the current Java-level context so that we | |
| 97 | + // revalidate everything the next time around | |
| 98 | + if (currentContext != null) { | |
| 99 | + currentContext.invalidateContext(); | |
| 100 | + currentContext = null; | |
| 101 | + } | |
| 102 | + | |
| 103 | + // invalidate the context reference at the native level, and | |
| 104 | + // then flush the queue so that we have no pending operations | |
| 105 | + // dependent on the current context | |
| 106 | + OGLRenderQueue rq = OGLRenderQueue.getInstance(); | |
| 107 | + rq.ensureCapacity(4); | |
| 108 | + rq.getBuffer().putInt(INVALIDATE_CONTEXT); | |
| 109 | + rq.flushNow(); | |
| 110 | + } | |
| 111 | + | |
| 112 | + public RenderQueue getRenderQueue() { | |
| 113 | + return OGLRenderQueue.getInstance(); | |
| 114 | + } | |
| 115 | + | |
| 116 | + /** | |
| 117 | + * Returns a string representing adapter id (vendor, renderer, version). | |
| 118 | + * Must be called on the rendering thread. | |
| 119 | + * | |
| 120 | + * @return an id string for the adapter | |
| 121 | + */ | |
| 122 | + static final native String getOGLIdString(); | |
| 123 | + | |
| 124 | + @Override | |
| 125 | + public void saveState() { | |
| 126 | + // assert rq.lock.isHeldByCurrentThread(); | |
| 127 | + | |
| 128 | + // reset all attributes of this and current contexts | |
| 129 | + invalidateContext(); | |
| 130 | + invalidateCurrentContext(); | |
| 131 | + | |
| 132 | + setScratchSurface(config); | |
| 133 | + | |
| 134 | + // save the state on the native level | |
| 135 | + rq.ensureCapacity(4); | |
| 136 | + buf.putInt(SAVE_STATE); | |
| 137 | + rq.flushNow(); | |
| 138 | + } | |
| 139 | + | |
| 140 | + @Override | |
| 141 | + public void restoreState() { | |
| 142 | + // assert rq.lock.isHeldByCurrentThread(); | |
| 143 | + | |
| 144 | + // reset all attributes of this and current contexts | |
| 145 | + invalidateContext(); | |
| 146 | + invalidateCurrentContext(); | |
| 147 | + | |
| 148 | + setScratchSurface(config); | |
| 149 | + | |
| 150 | + // restore the state on the native level | |
| 151 | + rq.ensureCapacity(4); | |
| 152 | + buf.putInt(RESTORE_STATE); | |
| 153 | + rq.flushNow(); | |
| 154 | + } | |
| 155 | + | |
| 156 | + static class OGLContextCaps extends ContextCapabilities { | |
| 157 | + /** | |
| 158 | + * Indicates the presence of the GL_EXT_framebuffer_object extension. | |
| 159 | + * This cap will only be set if the fbobject system property has been | |
| 160 | + * enabled and we are able to create an FBO with depth buffer. | |
| 161 | + */ | |
| 162 | + static final int CAPS_EXT_FBOBJECT = | |
| 163 | + (CAPS_RT_TEXTURE_ALPHA | CAPS_RT_TEXTURE_OPAQUE); | |
| 164 | + /** Indicates that the context supports a stored alpha channel. */ | |
| 165 | + static final int CAPS_STORED_ALPHA = CAPS_RT_PLAIN_ALPHA; | |
| 166 | + /** Indicates that the context is doublebuffered. */ | |
| 167 | + static final int CAPS_DOUBLEBUFFERED = (FIRST_PRIVATE_CAP << 0); | |
| 168 | + /** | |
| 169 | + * Indicates the presence of the GL_ARB_fragment_shader extension. | |
| 170 | + * This cap will only be set if the lcdshader system property has been | |
| 171 | + * enabled and the hardware supports the minimum number of texture units | |
| 172 | + */ | |
| 173 | + static final int CAPS_EXT_LCD_SHADER = (FIRST_PRIVATE_CAP << 1); | |
| 174 | + /** | |
| 175 | + * Indicates the presence of the GL_ARB_fragment_shader extension. | |
| 176 | + * This cap will only be set if the biopshader system property has been | |
| 177 | + * enabled and the hardware meets our minimum requirements. | |
| 178 | + */ | |
| 179 | + static final int CAPS_EXT_BIOP_SHADER = (FIRST_PRIVATE_CAP << 2); | |
| 180 | + /** | |
| 181 | + * Indicates the presence of the GL_ARB_fragment_shader extension. | |
| 182 | + * This cap will only be set if the gradshader system property has been | |
| 183 | + * enabled and the hardware meets our minimum requirements. | |
| 184 | + */ | |
| 185 | + static final int CAPS_EXT_GRAD_SHADER = (FIRST_PRIVATE_CAP << 3); | |
| 186 | + /** Indicates the presence of the GL_ARB_texture_rectangle extension. */ | |
| 187 | + static final int CAPS_EXT_TEXRECT = (FIRST_PRIVATE_CAP << 4); | |
| 188 | + | |
| 189 | + OGLContextCaps(int caps, String adapterId) { | |
| 190 | + super(caps, adapterId); | |
| 191 | + } | |
| 192 | + | |
| 193 | + @Override | |
| 194 | + public String toString() { | |
| 195 | + StringBuffer buf = new StringBuffer(super.toString()); | |
| 196 | + if ((caps & CAPS_EXT_FBOBJECT) != 0) { | |
| 197 | + buf.append("CAPS_EXT_FBOBJECT|"); | |
| 198 | + } | |
| 199 | + if ((caps & CAPS_STORED_ALPHA) != 0) { | |
| 200 | + buf.append("CAPS_STORED_ALPHA|"); | |
| 201 | + } | |
| 202 | + if ((caps & CAPS_DOUBLEBUFFERED) != 0) { | |
| 203 | + buf.append("CAPS_DOUBLEBUFFERED|"); | |
| 204 | + } | |
| 205 | + if ((caps & CAPS_EXT_LCD_SHADER) != 0) { | |
| 206 | + buf.append("CAPS_EXT_LCD_SHADER|"); | |
| 207 | + } | |
| 208 | + if ((caps & CAPS_EXT_BIOP_SHADER) != 0) { | |
| 209 | + buf.append("CAPS_BIOP_SHADER|"); | |
| 210 | + } | |
| 211 | + if ((caps & CAPS_EXT_GRAD_SHADER) != 0) { | |
| 212 | + buf.append("CAPS_EXT_GRAD_SHADER|"); | |
| 213 | + } | |
| 214 | + if ((caps & CAPS_EXT_TEXRECT) != 0) { | |
| 215 | + buf.append("CAPS_EXT_TEXRECT|"); | |
| 216 | + } | |
| 217 | + return buf.toString(); | |
| 218 | + } | |
| 219 | + } | |
| 220 | +} | |
| @@ -0,0 +1,113 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.opengl; | |
| 27 | + | |
| 28 | +import java.awt.Color; | |
| 29 | +import java.awt.Image; | |
| 30 | +import java.awt.geom.AffineTransform; | |
| 31 | +import java.awt.image.AffineTransformOp; | |
| 32 | +import java.awt.image.BufferedImage; | |
| 33 | +import java.awt.image.BufferedImageOp; | |
| 34 | +import sun.java2d.SunGraphics2D; | |
| 35 | +import sun.java2d.SurfaceData; | |
| 36 | +import sun.java2d.loops.SurfaceType; | |
| 37 | +import sun.java2d.loops.TransformBlit; | |
| 38 | +import sun.java2d.pipe.DrawImage; | |
| 39 | + | |
| 40 | +public class OGLDrawImage extends DrawImage { | |
| 41 | + | |
| 42 | + @Override | |
| 43 | + protected void renderImageXform(SunGraphics2D sg, Image img, | |
| 44 | + AffineTransform tx, int interpType, | |
| 45 | + int sx1, int sy1, int sx2, int sy2, | |
| 46 | + Color bgColor) | |
| 47 | + { | |
| 48 | + // punt to the MediaLib-based transformImage() in the superclass if: | |
| 49 | + // - bicubic interpolation is specified | |
| 50 | + // - a background color is specified and will be used | |
| 51 | + // - the source surface is neither a texture nor render-to-texture | |
| 52 | + // surface, and a non-default interpolation hint is specified | |
| 53 | + // (we can only control the filtering for texture->surface | |
| 54 | + // copies) | |
| 55 | + // REMIND: we should tweak the sw->texture->surface | |
| 56 | + // transform case to handle filtering appropriately | |
| 57 | + // (see 4841762)... | |
| 58 | + // - an appropriate TransformBlit primitive could not be found | |
| 59 | + if (interpType != AffineTransformOp.TYPE_BICUBIC) { | |
| 60 | + SurfaceData dstData = sg.surfaceData; | |
| 61 | + SurfaceData srcData = | |
| 62 | + dstData.getSourceSurfaceData(img, | |
| 63 | + sg.TRANSFORM_GENERIC, | |
| 64 | + sg.imageComp, | |
| 65 | + bgColor); | |
| 66 | + | |
| 67 | + if (srcData != null && | |
| 68 | + !isBgOperation(srcData, bgColor) && | |
| 69 | + (srcData.getSurfaceType() == OGLSurfaceData.OpenGLTexture || | |
| 70 | + srcData.getSurfaceType() == OGLSurfaceData.OpenGLSurfaceRTT || | |
| 71 | + interpType == AffineTransformOp.TYPE_NEAREST_NEIGHBOR)) | |
| 72 | + { | |
| 73 | + SurfaceType srcType = srcData.getSurfaceType(); | |
| 74 | + SurfaceType dstType = dstData.getSurfaceType(); | |
| 75 | + TransformBlit blit = TransformBlit.getFromCache(srcType, | |
| 76 | + sg.imageComp, | |
| 77 | + dstType); | |
| 78 | + | |
| 79 | + if (blit != null) { | |
| 80 | + blit.Transform(srcData, dstData, | |
| 81 | + sg.composite, sg.getCompClip(), | |
| 82 | + tx, interpType, | |
| 83 | + sx1, sy1, 0, 0, sx2-sx1, sy2-sy1); | |
| 84 | + return; | |
| 85 | + } | |
| 86 | + } | |
| 87 | + } | |
| 88 | + | |
| 89 | + super.renderImageXform(sg, img, tx, interpType, | |
| 90 | + sx1, sy1, sx2, sy2, bgColor); | |
| 91 | + } | |
| 92 | + | |
| 93 | + @Override | |
| 94 | + public void transformImage(SunGraphics2D sg, BufferedImage img, | |
| 95 | + BufferedImageOp op, int x, int y) | |
| 96 | + { | |
| 97 | + if (op != null) { | |
| 98 | + if (op instanceof AffineTransformOp) { | |
| 99 | + AffineTransformOp atop = (AffineTransformOp) op; | |
| 100 | + transformImage(sg, img, x, y, | |
| 101 | + atop.getTransform(), | |
| 102 | + atop.getInterpolationType()); | |
| 103 | + return; | |
| 104 | + } else { | |
| 105 | + if (OGLBufImgOps.renderImageWithOp(sg, img, op, x, y)) { | |
| 106 | + return; | |
| 107 | + } | |
| 108 | + } | |
| 109 | + img = op.filter(img, null); | |
| 110 | + } | |
| 111 | + copyImage(sg, img, x, y, null); | |
| 112 | + } | |
| 113 | +} | |
| @@ -0,0 +1,44 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.opengl; | |
| 27 | + | |
| 28 | +import sun.java2d.SurfaceData; | |
| 29 | +import sun.awt.image.SurfaceManager; | |
| 30 | +import sun.java2d.pipe.hw.AccelGraphicsConfig; | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * This interface collects the methods that are provided by both | |
| 34 | + * GLXGraphicsConfig and WGLGraphicsConfig, making it easier to invoke these | |
| 35 | + * methods directly from OGLSurfaceData. | |
| 36 | + */ | |
| 37 | +interface OGLGraphicsConfig extends | |
| 38 | + AccelGraphicsConfig, SurfaceManager.ProxiedGraphicsConfig | |
| 39 | +{ | |
| 40 | + OGLContext getContext(); | |
| 41 | + long getNativeConfigInfo(); | |
| 42 | + boolean isCapPresent(int cap); | |
| 43 | + SurfaceData createManagedSurface(int w, int h, int transparency); | |
| 44 | +} | |
| @@ -0,0 +1,69 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.opengl; | |
| 27 | + | |
| 28 | +import java.awt.Composite; | |
| 29 | +import sun.java2d.SurfaceData; | |
| 30 | +import sun.java2d.loops.CompositeType; | |
| 31 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 32 | +import sun.java2d.loops.GraphicsPrimitiveMgr; | |
| 33 | +import sun.java2d.loops.SurfaceType; | |
| 34 | +import sun.java2d.pipe.Region; | |
| 35 | +import sun.java2d.pipe.BufferedMaskBlit; | |
| 36 | +import static sun.java2d.loops.CompositeType.*; | |
| 37 | +import static sun.java2d.loops.SurfaceType.*; | |
| 38 | + | |
| 39 | +class OGLMaskBlit extends BufferedMaskBlit { | |
| 40 | + | |
| 41 | + static void register() { | |
| 42 | + GraphicsPrimitive[] primitives = { | |
| 43 | + new OGLMaskBlit(IntArgb, SrcOver), | |
| 44 | + new OGLMaskBlit(IntArgbPre, SrcOver), | |
| 45 | + new OGLMaskBlit(IntRgb, SrcOver), | |
| 46 | + new OGLMaskBlit(IntRgb, SrcNoEa), | |
| 47 | + new OGLMaskBlit(IntBgr, SrcOver), | |
| 48 | + new OGLMaskBlit(IntBgr, SrcNoEa), | |
| 49 | + }; | |
| 50 | + GraphicsPrimitiveMgr.register(primitives); | |
| 51 | + } | |
| 52 | + | |
| 53 | + private OGLMaskBlit(SurfaceType srcType, | |
| 54 | + CompositeType compType) | |
| 55 | + { | |
| 56 | + super(OGLRenderQueue.getInstance(), | |
| 57 | + srcType, compType, OGLSurfaceData.OpenGLSurface); | |
| 58 | + } | |
| 59 | + | |
| 60 | + @Override | |
| 61 | + protected void validateContext(SurfaceData dstData, | |
| 62 | + Composite comp, Region clip) | |
| 63 | + { | |
| 64 | + OGLSurfaceData oglDst = (OGLSurfaceData)dstData; | |
| 65 | + OGLContext.validateContext(oglDst, oglDst, | |
| 66 | + clip, comp, null, null, null, | |
| 67 | + OGLContext.NO_CONTEXT_FLAGS); | |
| 68 | + } | |
| 69 | +} | |
| @@ -0,0 +1,75 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.opengl; | |
| 27 | + | |
| 28 | +import java.awt.Composite; | |
| 29 | +import sun.java2d.SunGraphics2D; | |
| 30 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 31 | +import sun.java2d.loops.GraphicsPrimitiveMgr; | |
| 32 | +import sun.java2d.loops.CompositeType; | |
| 33 | +import sun.java2d.loops.SurfaceType; | |
| 34 | +import sun.java2d.pipe.BufferedMaskFill; | |
| 35 | +import static sun.java2d.loops.CompositeType.*; | |
| 36 | +import static sun.java2d.loops.SurfaceType.*; | |
| 37 | + | |
| 38 | +class OGLMaskFill extends BufferedMaskFill { | |
| 39 | + | |
| 40 | + static void register() { | |
| 41 | + GraphicsPrimitive[] primitives = { | |
| 42 | + new OGLMaskFill(AnyColor, SrcOver), | |
| 43 | + new OGLMaskFill(OpaqueColor, SrcNoEa), | |
| 44 | + new OGLMaskFill(GradientPaint, SrcOver), | |
| 45 | + new OGLMaskFill(OpaqueGradientPaint, SrcNoEa), | |
| 46 | + new OGLMaskFill(LinearGradientPaint, SrcOver), | |
| 47 | + new OGLMaskFill(OpaqueLinearGradientPaint, SrcNoEa), | |
| 48 | + new OGLMaskFill(RadialGradientPaint, SrcOver), | |
| 49 | + new OGLMaskFill(OpaqueRadialGradientPaint, SrcNoEa), | |
| 50 | + new OGLMaskFill(TexturePaint, SrcOver), | |
| 51 | + new OGLMaskFill(OpaqueTexturePaint, SrcNoEa), | |
| 52 | + }; | |
| 53 | + GraphicsPrimitiveMgr.register(primitives); | |
| 54 | + } | |
| 55 | + | |
| 56 | + protected OGLMaskFill(SurfaceType srcType, CompositeType compType) { | |
| 57 | + super(OGLRenderQueue.getInstance(), | |
| 58 | + srcType, compType, OGLSurfaceData.OpenGLSurface); | |
| 59 | + } | |
| 60 | + | |
| 61 | + @Override | |
| 62 | + protected native void maskFill(int x, int y, int w, int h, | |
| 63 | + int maskoff, int maskscan, int masklen, | |
| 64 | + byte[] mask); | |
| 65 | + | |
| 66 | + @Override | |
| 67 | + protected void validateContext(SunGraphics2D sg2d, | |
| 68 | + Composite comp, int ctxflags) | |
| 69 | + { | |
| 70 | + OGLSurfaceData dstData = (OGLSurfaceData)sg2d.surfaceData; | |
| 71 | + OGLContext.validateContext(dstData, dstData, | |
| 72 | + sg2d.getCompClip(), comp, | |
| 73 | + null, sg2d.paint, sg2d, ctxflags); | |
| 74 | + } | |
| 75 | +} | |
| @@ -0,0 +1,209 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.opengl; | |
| 27 | + | |
| 28 | +import java.awt.GradientPaint; | |
| 29 | +import java.awt.LinearGradientPaint; | |
| 30 | +import java.awt.MultipleGradientPaint; | |
| 31 | +import java.awt.MultipleGradientPaint.ColorSpaceType; | |
| 32 | +import java.awt.MultipleGradientPaint.CycleMethod; | |
| 33 | +import java.awt.RadialGradientPaint; | |
| 34 | +import java.awt.TexturePaint; | |
| 35 | +import java.awt.image.BufferedImage; | |
| 36 | +import java.util.HashMap; | |
| 37 | +import java.util.Map; | |
| 38 | +import sun.java2d.SunGraphics2D; | |
| 39 | +import sun.java2d.SurfaceData; | |
| 40 | +import sun.java2d.loops.CompositeType; | |
| 41 | +import static sun.java2d.pipe.BufferedPaints.*; | |
| 42 | +import static sun.java2d.opengl.OGLContext.OGLContextCaps.*; | |
| 43 | + | |
| 44 | +abstract class OGLPaints { | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * Holds all registered implementations, using the corresponding | |
| 48 | + * SunGraphics2D.PAINT_* constant as the hash key. | |
| 49 | + */ | |
| 50 | + private static Map<Integer, OGLPaints> impls = | |
| 51 | + new HashMap<Integer, OGLPaints>(4, 1.0f); | |
| 52 | + | |
| 53 | + static { | |
| 54 | + impls.put(SunGraphics2D.PAINT_GRADIENT, new Gradient()); | |
| 55 | + impls.put(SunGraphics2D.PAINT_LIN_GRADIENT, new LinearGradient()); | |
| 56 | + impls.put(SunGraphics2D.PAINT_RAD_GRADIENT, new RadialGradient()); | |
| 57 | + impls.put(SunGraphics2D.PAINT_TEXTURE, new Texture()); | |
| 58 | + } | |
| 59 | + | |
| 60 | + /** | |
| 61 | + * Attempts to locate an implementation corresponding to the paint state | |
| 62 | + * of the provided SunGraphics2D object. If no implementation can be | |
| 63 | + * found, or if the paint cannot be accelerated under the conditions | |
| 64 | + * of the SunGraphics2D, this method returns false; otherwise, returns | |
| 65 | + * true. | |
| 66 | + */ | |
| 67 | + static boolean isValid(SunGraphics2D sg2d) { | |
| 68 | + OGLPaints impl = impls.get(sg2d.paintState); | |
| 69 | + return (impl != null && impl.isPaintValid(sg2d)); | |
| 70 | + } | |
| 71 | + | |
| 72 | + /** | |
| 73 | + * Returns true if this implementation is able to accelerate the | |
| 74 | + * Paint object associated with, and under the conditions of, the | |
| 75 | + * provided SunGraphics2D instance; otherwise returns false. | |
| 76 | + */ | |
| 77 | + abstract boolean isPaintValid(SunGraphics2D sg2d); | |
| 78 | + | |
| 79 | +/************************* GradientPaint support ****************************/ | |
| 80 | + | |
| 81 | + private static class Gradient extends OGLPaints { | |
| 82 | + private Gradient() {} | |
| 83 | + | |
| 84 | + /** | |
| 85 | + * There are no restrictions for accelerating GradientPaint, so | |
| 86 | + * this method always returns true. | |
| 87 | + */ | |
| 88 | + @Override | |
| 89 | + boolean isPaintValid(SunGraphics2D sg2d) { | |
| 90 | + return true; | |
| 91 | + } | |
| 92 | + } | |
| 93 | + | |
| 94 | +/************************** TexturePaint support ****************************/ | |
| 95 | + | |
| 96 | + private static class Texture extends OGLPaints { | |
| 97 | + private Texture() {} | |
| 98 | + | |
| 99 | + /** | |
| 100 | + * Returns true if the given TexturePaint instance can be used by the | |
| 101 | + * accelerated OGLPaints.Texture implementation. A TexturePaint is | |
| 102 | + * considered valid if the following conditions are met: | |
| 103 | + * - the texture image dimensions are power-of-two (or the | |
| 104 | + * GL_ARB_texture_non_power_of_two extension is present) | |
| 105 | + * - the texture image can be (or is already) cached in an OpenGL | |
| 106 | + * texture object | |
| 107 | + */ | |
| 108 | + @Override | |
| 109 | + boolean isPaintValid(SunGraphics2D sg2d) { | |
| 110 | + TexturePaint paint = (TexturePaint)sg2d.paint; | |
| 111 | + OGLSurfaceData dstData = (OGLSurfaceData)sg2d.surfaceData; | |
| 112 | + BufferedImage bi = paint.getImage(); | |
| 113 | + | |
| 114 | + // see if texture-non-pow2 extension is available | |
| 115 | + if (!dstData.isTexNonPow2Available()) { | |
| 116 | + int imgw = bi.getWidth(); | |
| 117 | + int imgh = bi.getHeight(); | |
| 118 | + | |
| 119 | + // verify that the texture image dimensions are pow2 | |
| 120 | + if ((imgw & (imgw - 1)) != 0 || (imgh & (imgh - 1)) != 0) { | |
| 121 | + return false; | |
| 122 | + } | |
| 123 | + } | |
| 124 | + | |
| 125 | + SurfaceData srcData = | |
| 126 | + dstData.getSourceSurfaceData(bi, sg2d.TRANSFORM_ISIDENT, | |
| 127 | + CompositeType.SrcOver, null); | |
| 128 | + if (!(srcData instanceof OGLSurfaceData)) { | |
| 129 | + // REMIND: this is a hack that attempts to cache the system | |
| 130 | + // memory image from the TexturePaint instance into an | |
| 131 | + // OpenGL texture... | |
| 132 | + srcData = | |
| 133 | + dstData.getSourceSurfaceData(bi, sg2d.TRANSFORM_ISIDENT, | |
| 134 | + CompositeType.SrcOver, null); | |
| 135 | + if (!(srcData instanceof OGLSurfaceData)) { | |
| 136 | + return false; | |
| 137 | + } | |
| 138 | + } | |
| 139 | + | |
| 140 | + // verify that the source surface is actually a texture | |
| 141 | + OGLSurfaceData oglData = (OGLSurfaceData)srcData; | |
| 142 | + if (oglData.getType() != OGLSurfaceData.TEXTURE) { | |
| 143 | + return false; | |
| 144 | + } | |
| 145 | + | |
| 146 | + return true; | |
| 147 | + } | |
| 148 | + } | |
| 149 | + | |
| 150 | +/****************** Shared MultipleGradientPaint support ********************/ | |
| 151 | + | |
| 152 | + private static abstract class MultiGradient extends OGLPaints { | |
| 153 | + protected MultiGradient() {} | |
| 154 | + | |
| 155 | + /** | |
| 156 | + * Returns true if the given MultipleGradientPaint instance can be | |
| 157 | + * used by the accelerated OGLPaints.MultiGradient implementation. | |
| 158 | + * A MultipleGradientPaint is considered valid if the following | |
| 159 | + * conditions are met: | |
| 160 | + * - the number of gradient "stops" is <= MAX_FRACTIONS | |
| 161 | + * - the destination has support for fragment shaders | |
| 162 | + */ | |
| 163 | + @Override | |
| 164 | + boolean isPaintValid(SunGraphics2D sg2d) { | |
| 165 | + MultipleGradientPaint paint = (MultipleGradientPaint)sg2d.paint; | |
| 166 | + // REMIND: ugh, this creates garbage; would be nicer if | |
| 167 | + // we had a MultipleGradientPaint.getNumStops() method... | |
| 168 | + if (paint.getFractions().length > MULTI_MAX_FRACTIONS) { | |
| 169 | + return false; | |
| 170 | + } | |
| 171 | + | |
| 172 | + OGLSurfaceData dstData = (OGLSurfaceData)sg2d.surfaceData; | |
| 173 | + OGLGraphicsConfig gc = dstData.getOGLGraphicsConfig(); | |
| 174 | + if (!gc.isCapPresent(CAPS_EXT_GRAD_SHADER)) { | |
| 175 | + return false; | |
| 176 | + } | |
| 177 | + | |
| 178 | + return true; | |
| 179 | + } | |
| 180 | + } | |
| 181 | + | |
| 182 | +/********************** LinearGradientPaint support *************************/ | |
| 183 | + | |
| 184 | + private static class LinearGradient extends MultiGradient { | |
| 185 | + private LinearGradient() {} | |
| 186 | + | |
| 187 | + @Override | |
| 188 | + boolean isPaintValid(SunGraphics2D sg2d) { | |
| 189 | + LinearGradientPaint paint = (LinearGradientPaint)sg2d.paint; | |
| 190 | + | |
| 191 | + if (paint.getFractions().length == 2 && | |
| 192 | + paint.getCycleMethod() != CycleMethod.REPEAT && | |
| 193 | + paint.getColorSpace() != ColorSpaceType.LINEAR_RGB) | |
| 194 | + { | |
| 195 | + // we can delegate to the optimized two-color gradient | |
| 196 | + // codepath, which does not require fragment shader support | |
| 197 | + return true; | |
| 198 | + } | |
| 199 | + | |
| 200 | + return super.isPaintValid(sg2d); | |
| 201 | + } | |
| 202 | + } | |
| 203 | + | |
| 204 | +/********************** RadialGradientPaint support *************************/ | |
| 205 | + | |
| 206 | + private static class RadialGradient extends MultiGradient { | |
| 207 | + private RadialGradient() {} | |
| 208 | + } | |
| 209 | +} | |
| @@ -0,0 +1,239 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.opengl; | |
| 27 | + | |
| 28 | +import sun.java2d.pipe.RenderBuffer; | |
| 29 | +import sun.java2d.pipe.RenderQueue; | |
| 30 | +import static sun.java2d.pipe.BufferedOpCodes.*; | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * OGL-specific implementation of RenderQueue. This class provides a | |
| 34 | + * single (daemon) thread that is responsible for periodically flushing | |
| 35 | + * the queue, thus ensuring that only one thread communicates with the native | |
| 36 | + * OpenGL libraries for the entire process. | |
| 37 | + */ | |
| 38 | +public class OGLRenderQueue extends RenderQueue { | |
| 39 | + | |
| 40 | + private static OGLRenderQueue theInstance; | |
| 41 | + private final QueueFlusher flusher; | |
| 42 | + | |
| 43 | + private OGLRenderQueue() { | |
| 44 | + flusher = new QueueFlusher(); | |
| 45 | + } | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * Returns the single OGLRenderQueue instance. If it has not yet been | |
| 49 | + * initialized, this method will first construct the single instance | |
| 50 | + * before returning it. | |
| 51 | + */ | |
| 52 | + public static synchronized OGLRenderQueue getInstance() { | |
| 53 | + if (theInstance == null) { | |
| 54 | + theInstance = new OGLRenderQueue(); | |
| 55 | + } | |
| 56 | + return theInstance; | |
| 57 | + } | |
| 58 | + | |
| 59 | + /** | |
| 60 | + * Flushes the single OGLRenderQueue instance synchronously. If an | |
| 61 | + * OGLRenderQueue has not yet been instantiated, this method is a no-op. | |
| 62 | + * This method is useful in the case of Toolkit.sync(), in which we want | |
| 63 | + * to flush the OGL pipeline, but only if the OGL pipeline is currently | |
| 64 | + * enabled. Since this class has few external dependencies, callers need | |
| 65 | + * not be concerned that calling this method will trigger initialization | |
| 66 | + * of the OGL pipeline and related classes. | |
| 67 | + */ | |
| 68 | + public static void sync() { | |
| 69 | + if (theInstance != null) { | |
| 70 | + theInstance.lock(); | |
| 71 | + try { | |
| 72 | + theInstance.ensureCapacity(4); | |
| 73 | + theInstance.getBuffer().putInt(SYNC); | |
| 74 | + theInstance.flushNow(); | |
| 75 | + } finally { | |
| 76 | + theInstance.unlock(); | |
| 77 | + } | |
| 78 | + } | |
| 79 | + } | |
| 80 | + | |
| 81 | + /** | |
| 82 | + * Disposes the native memory associated with the given native | |
| 83 | + * graphics config info pointer on the single queue flushing thread. | |
| 84 | + */ | |
| 85 | + public static void disposeGraphicsConfig(long pConfigInfo) { | |
| 86 | + OGLRenderQueue rq = getInstance(); | |
| 87 | + rq.lock(); | |
| 88 | + try { | |
| 89 | + // make sure we make the context associated with the given | |
| 90 | + // GraphicsConfig current before disposing the native resources | |
| 91 | + OGLContext.setScratchSurface(pConfigInfo); | |
| 92 | + | |
| 93 | + RenderBuffer buf = rq.getBuffer(); | |
| 94 | + rq.ensureCapacityAndAlignment(12, 4); | |
| 95 | + buf.putInt(DISPOSE_CONFIG); | |
| 96 | + buf.putLong(pConfigInfo); | |
| 97 | + | |
| 98 | + // this call is expected to complete synchronously, so flush now | |
| 99 | + rq.flushNow(); | |
| 100 | + } finally { | |
| 101 | + rq.unlock(); | |
| 102 | + } | |
| 103 | + } | |
| 104 | + | |
| 105 | + /** | |
| 106 | + * Returns true if the current thread is the OGL QueueFlusher thread. | |
| 107 | + */ | |
| 108 | + public static boolean isQueueFlusherThread() { | |
| 109 | + return (Thread.currentThread() == getInstance().flusher); | |
| 110 | + } | |
| 111 | + | |
| 112 | + public void flushNow() { | |
| 113 | + // assert lock.isHeldByCurrentThread(); | |
| 114 | + try { | |
| 115 | + flusher.flushNow(); | |
| 116 | + } catch (Exception e) { | |
| 117 | + System.err.println("exception in flushNow:"); | |
| 118 | + e.printStackTrace(); | |
| 119 | + } | |
| 120 | + } | |
| 121 | + | |
| 122 | + public void flushAndInvokeNow(Runnable r) { | |
| 123 | + // assert lock.isHeldByCurrentThread(); | |
| 124 | + try { | |
| 125 | + flusher.flushAndInvokeNow(r); | |
| 126 | + } catch (Exception e) { | |
| 127 | + System.err.println("exception in flushAndInvokeNow:"); | |
| 128 | + e.printStackTrace(); | |
| 129 | + } | |
| 130 | + } | |
| 131 | + | |
| 132 | + private native void flushBuffer(long buf, int limit); | |
| 133 | + | |
| 134 | + private void flushBuffer() { | |
| 135 | + // assert lock.isHeldByCurrentThread(); | |
| 136 | + int limit = buf.position(); | |
| 137 | + if (limit > 0) { | |
| 138 | + // process the queue | |
| 139 | + flushBuffer(buf.getAddress(), limit); | |
| 140 | + } | |
| 141 | + // reset the buffer position | |
| 142 | + buf.clear(); | |
| 143 | + // clear the set of references, since we no longer need them | |
| 144 | + refSet.clear(); | |
| 145 | + } | |
| 146 | + | |
| 147 | + private class QueueFlusher extends Thread { | |
| 148 | + private boolean needsFlush; | |
| 149 | + private Runnable task; | |
| 150 | + private Error error; | |
| 151 | + | |
| 152 | + public QueueFlusher() { | |
| 153 | + super("Java2D Queue Flusher"); | |
| 154 | + setDaemon(true); | |
| 155 | + setPriority(Thread.MAX_PRIORITY); | |
| 156 | + start(); | |
| 157 | + } | |
| 158 | + | |
| 159 | + public synchronized void flushNow() { | |
| 160 | + // wake up the flusher | |
| 161 | + needsFlush = true; | |
| 162 | + notify(); | |
| 163 | + | |
| 164 | + // wait for flush to complete | |
| 165 | + while (needsFlush) { | |
| 166 | + try { | |
| 167 | + wait(); | |
| 168 | + } catch (InterruptedException e) { | |
| 169 | + } | |
| 170 | + } | |
| 171 | + | |
| 172 | + // re-throw any error that may have occurred during the flush | |
| 173 | + if (error != null) { | |
| 174 | + throw error; | |
| 175 | + } | |
| 176 | + } | |
| 177 | + | |
| 178 | + public synchronized void flushAndInvokeNow(Runnable task) { | |
| 179 | + this.task = task; | |
| 180 | + flushNow(); | |
| 181 | + } | |
| 182 | + | |
| 183 | + public synchronized void run() { | |
| 184 | + boolean timedOut = false; | |
| 185 | + while (true) { | |
| 186 | + while (!needsFlush) { | |
| 187 | + try { | |
| 188 | + timedOut = false; | |
| 189 | + /* | |
| 190 | + * Wait until we're woken up with a flushNow() call, | |
| 191 | + * or the timeout period elapses (so that we can | |
| 192 | + * flush the queue periodically). | |
| 193 | + */ | |
| 194 | + wait(100); | |
| 195 | + /* | |
| 196 | + * We will automatically flush the queue if the | |
| 197 | + * following conditions apply: | |
| 198 | + * - the wait() timed out | |
| 199 | + * - we can lock the queue (without blocking) | |
| 200 | + * - there is something in the queue to flush | |
| 201 | + * Otherwise, just continue (we'll flush eventually). | |
| 202 | + */ | |
| 203 | + if (!needsFlush && (timedOut = tryLock())) { | |
| 204 | + if (buf.position() > 0) { | |
| 205 | + needsFlush = true; | |
| 206 | + } else { | |
| 207 | + unlock(); | |
| 208 | + } | |
| 209 | + } | |
| 210 | + } catch (InterruptedException e) { | |
| 211 | + } | |
| 212 | + } | |
| 213 | + try { | |
| 214 | + // reset the throwable state | |
| 215 | + error = null; | |
| 216 | + // flush the buffer now | |
| 217 | + flushBuffer(); | |
| 218 | + // if there's a task, invoke that now as well | |
| 219 | + if (task != null) { | |
| 220 | + task.run(); | |
| 221 | + } | |
| 222 | + } catch (Error e) { | |
| 223 | + error = e; | |
| 224 | + } catch (Exception x) { | |
| 225 | + System.err.println("exception in QueueFlusher:"); | |
| 226 | + x.printStackTrace(); | |
| 227 | + } finally { | |
| 228 | + if (timedOut) { | |
| 229 | + unlock(); | |
| 230 | + } | |
| 231 | + task = null; | |
| 232 | + // allow the waiting thread to continue | |
| 233 | + needsFlush = false; | |
| 234 | + notify(); | |
| 235 | + } | |
| 236 | + } | |
| 237 | + } | |
| 238 | + } | |
| 239 | +} | |
| @@ -0,0 +1,206 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.opengl; | |
| 27 | + | |
| 28 | +import java.awt.Transparency; | |
| 29 | +import java.awt.geom.Path2D; | |
| 30 | +import sun.java2d.SunGraphics2D; | |
| 31 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 32 | +import sun.java2d.pipe.BufferedRenderPipe; | |
| 33 | +import sun.java2d.pipe.ParallelogramPipe; | |
| 34 | +import sun.java2d.pipe.RenderQueue; | |
| 35 | +import sun.java2d.pipe.SpanIterator; | |
| 36 | +import static sun.java2d.pipe.BufferedOpCodes.*; | |
| 37 | + | |
| 38 | +class OGLRenderer extends BufferedRenderPipe { | |
| 39 | + | |
| 40 | + OGLRenderer(RenderQueue rq) { | |
| 41 | + super(rq); | |
| 42 | + } | |
| 43 | + | |
| 44 | + @Override | |
| 45 | + protected void validateContext(SunGraphics2D sg2d) { | |
| 46 | + int ctxflags = | |
| 47 | + sg2d.paint.getTransparency() == Transparency.OPAQUE ? | |
| 48 | + OGLContext.SRC_IS_OPAQUE : OGLContext.NO_CONTEXT_FLAGS; | |
| 49 | + OGLSurfaceData dstData = (OGLSurfaceData)sg2d.surfaceData; | |
| 50 | + OGLContext.validateContext(dstData, dstData, | |
| 51 | + sg2d.getCompClip(), sg2d.composite, | |
| 52 | + null, sg2d.paint, sg2d, ctxflags); | |
| 53 | + } | |
| 54 | + | |
| 55 | + @Override | |
| 56 | + protected void validateContextAA(SunGraphics2D sg2d) { | |
| 57 | + int ctxflags = OGLContext.NO_CONTEXT_FLAGS; | |
| 58 | + OGLSurfaceData dstData = (OGLSurfaceData)sg2d.surfaceData; | |
| 59 | + OGLContext.validateContext(dstData, dstData, | |
| 60 | + sg2d.getCompClip(), sg2d.composite, | |
| 61 | + null, sg2d.paint, sg2d, ctxflags); | |
| 62 | + } | |
| 63 | + | |
| 64 | + void copyArea(SunGraphics2D sg2d, | |
| 65 | + int x, int y, int w, int h, int dx, int dy) | |
| 66 | + { | |
| 67 | + rq.lock(); | |
| 68 | + try { | |
| 69 | + int ctxflags = | |
| 70 | + sg2d.surfaceData.getTransparency() == Transparency.OPAQUE ? | |
| 71 | + OGLContext.SRC_IS_OPAQUE : OGLContext.NO_CONTEXT_FLAGS; | |
| 72 | + OGLSurfaceData dstData = (OGLSurfaceData)sg2d.surfaceData; | |
| 73 | + OGLContext.validateContext(dstData, dstData, | |
| 74 | + sg2d.getCompClip(), sg2d.composite, | |
| 75 | + null, null, null, ctxflags); | |
| 76 | + | |
| 77 | + rq.ensureCapacity(28); | |
| 78 | + buf.putInt(COPY_AREA); | |
| 79 | + buf.putInt(x).putInt(y).putInt(w).putInt(h); | |
| 80 | + buf.putInt(dx).putInt(dy); | |
| 81 | + } finally { | |
| 82 | + rq.unlock(); | |
| 83 | + } | |
| 84 | + } | |
| 85 | + | |
| 86 | + @Override | |
| 87 | + protected native void drawPoly(int[] xPoints, int[] yPoints, | |
| 88 | + int nPoints, boolean isClosed, | |
| 89 | + int transX, int transY); | |
| 90 | + | |
| 91 | + OGLRenderer traceWrap() { | |
| 92 | + return new Tracer(this); | |
| 93 | + } | |
| 94 | + | |
| 95 | + private class Tracer extends OGLRenderer { | |
| 96 | + private OGLRenderer oglr; | |
| 97 | + Tracer(OGLRenderer oglr) { | |
| 98 | + super(oglr.rq); | |
| 99 | + this.oglr = oglr; | |
| 100 | + } | |
| 101 | + public ParallelogramPipe getAAParallelogramPipe() { | |
| 102 | + final ParallelogramPipe realpipe = oglr.getAAParallelogramPipe(); | |
| 103 | + return new ParallelogramPipe() { | |
| 104 | + public void fillParallelogram(SunGraphics2D sg2d, | |
| 105 | + double ux1, double uy1, | |
| 106 | + double ux2, double uy2, | |
| 107 | + double x, double y, | |
| 108 | + double dx1, double dy1, | |
| 109 | + double dx2, double dy2) | |
| 110 | + { | |
| 111 | + GraphicsPrimitive.tracePrimitive("OGLFillAAParallelogram"); | |
| 112 | + realpipe.fillParallelogram(sg2d, | |
| 113 | + ux1, uy1, ux2, uy2, | |
| 114 | + x, y, dx1, dy1, dx2, dy2); | |
| 115 | + } | |
| 116 | + public void drawParallelogram(SunGraphics2D sg2d, | |
| 117 | + double ux1, double uy1, | |
| 118 | + double ux2, double uy2, | |
| 119 | + double x, double y, | |
| 120 | + double dx1, double dy1, | |
| 121 | + double dx2, double dy2, | |
| 122 | + double lw1, double lw2) | |
| 123 | + { | |
| 124 | + GraphicsPrimitive.tracePrimitive("OGLDrawAAParallelogram"); | |
| 125 | + realpipe.drawParallelogram(sg2d, | |
| 126 | + ux1, uy1, ux2, uy2, | |
| 127 | + x, y, dx1, dy1, dx2, dy2, | |
| 128 | + lw1, lw2); | |
| 129 | + } | |
| 130 | + }; | |
| 131 | + } | |
| 132 | + protected void validateContext(SunGraphics2D sg2d) { | |
| 133 | + oglr.validateContext(sg2d); | |
| 134 | + } | |
| 135 | + public void drawLine(SunGraphics2D sg2d, | |
| 136 | + int x1, int y1, int x2, int y2) | |
| 137 | + { | |
| 138 | + GraphicsPrimitive.tracePrimitive("OGLDrawLine"); | |
| 139 | + oglr.drawLine(sg2d, x1, y1, x2, y2); | |
| 140 | + } | |
| 141 | + public void drawRect(SunGraphics2D sg2d, int x, int y, int w, int h) { | |
| 142 | + GraphicsPrimitive.tracePrimitive("OGLDrawRect"); | |
| 143 | + oglr.drawRect(sg2d, x, y, w, h); | |
| 144 | + } | |
| 145 | + protected void drawPoly(SunGraphics2D sg2d, | |
| 146 | + int[] xPoints, int[] yPoints, | |
| 147 | + int nPoints, boolean isClosed) | |
| 148 | + { | |
| 149 | + GraphicsPrimitive.tracePrimitive("OGLDrawPoly"); | |
| 150 | + oglr.drawPoly(sg2d, xPoints, yPoints, nPoints, isClosed); | |
| 151 | + } | |
| 152 | + public void fillRect(SunGraphics2D sg2d, int x, int y, int w, int h) { | |
| 153 | + GraphicsPrimitive.tracePrimitive("OGLFillRect"); | |
| 154 | + oglr.fillRect(sg2d, x, y, w, h); | |
| 155 | + } | |
| 156 | + protected void drawPath(SunGraphics2D sg2d, | |
| 157 | + Path2D.Float p2df, int transx, int transy) | |
| 158 | + { | |
| 159 | + GraphicsPrimitive.tracePrimitive("OGLDrawPath"); | |
| 160 | + oglr.drawPath(sg2d, p2df, transx, transy); | |
| 161 | + } | |
| 162 | + protected void fillPath(SunGraphics2D sg2d, | |
| 163 | + Path2D.Float p2df, int transx, int transy) | |
| 164 | + { | |
| 165 | + GraphicsPrimitive.tracePrimitive("OGLFillPath"); | |
| 166 | + oglr.fillPath(sg2d, p2df, transx, transy); | |
| 167 | + } | |
| 168 | + protected void fillSpans(SunGraphics2D sg2d, SpanIterator si, | |
| 169 | + int transx, int transy) | |
| 170 | + { | |
| 171 | + GraphicsPrimitive.tracePrimitive("OGLFillSpans"); | |
| 172 | + oglr.fillSpans(sg2d, si, transx, transy); | |
| 173 | + } | |
| 174 | + public void fillParallelogram(SunGraphics2D sg2d, | |
| 175 | + double ux1, double uy1, | |
| 176 | + double ux2, double uy2, | |
| 177 | + double x, double y, | |
| 178 | + double dx1, double dy1, | |
| 179 | + double dx2, double dy2) | |
| 180 | + { | |
| 181 | + GraphicsPrimitive.tracePrimitive("OGLFillParallelogram"); | |
| 182 | + oglr.fillParallelogram(sg2d, | |
| 183 | + ux1, uy1, ux2, uy2, | |
| 184 | + x, y, dx1, dy1, dx2, dy2); | |
| 185 | + } | |
| 186 | + public void drawParallelogram(SunGraphics2D sg2d, | |
| 187 | + double ux1, double uy1, | |
| 188 | + double ux2, double uy2, | |
| 189 | + double x, double y, | |
| 190 | + double dx1, double dy1, | |
| 191 | + double dx2, double dy2, | |
| 192 | + double lw1, double lw2) | |
| 193 | + { | |
| 194 | + GraphicsPrimitive.tracePrimitive("OGLDrawParallelogram"); | |
| 195 | + oglr.drawParallelogram(sg2d, | |
| 196 | + ux1, uy1, ux2, uy2, | |
| 197 | + x, y, dx1, dy1, dx2, dy2, lw1, lw2); | |
| 198 | + } | |
| 199 | + public void copyArea(SunGraphics2D sg2d, | |
| 200 | + int x, int y, int w, int h, int dx, int dy) | |
| 201 | + { | |
| 202 | + GraphicsPrimitive.tracePrimitive("OGLCopyArea"); | |
| 203 | + oglr.copyArea(sg2d, x, y, w, h, dx, dy); | |
| 204 | + } | |
| 205 | + } | |
| 206 | +} | |
| @@ -0,0 +1,653 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.java2d.opengl; | |
| 27 | + | |
| 28 | +import java.awt.AlphaComposite; | |
| 29 | +import java.awt.GraphicsEnvironment; | |
| 30 | +import java.awt.Rectangle; | |
| 31 | +import java.awt.Transparency; | |
| 32 | +import java.awt.image.ColorModel; | |
| 33 | +import java.awt.image.Raster; | |
| 34 | +import sun.awt.SunHints; | |
| 35 | +import sun.awt.image.PixelConverter; | |
| 36 | +import sun.java2d.pipe.hw.AccelSurface; | |
| 37 | +import sun.java2d.SunGraphics2D; | |
| 38 | +import sun.java2d.SurfaceData; | |
| 39 | +import sun.java2d.SurfaceDataProxy; | |
| 40 | +import sun.java2d.loops.CompositeType; | |
| 41 | +import sun.java2d.loops.GraphicsPrimitive; | |
| 42 | +import sun.java2d.loops.MaskFill; | |
| 43 | +import sun.java2d.loops.SurfaceType; | |
| 44 | +import sun.java2d.pipe.ParallelogramPipe; | |
| 45 | +import sun.java2d.pipe.PixelToParallelogramConverter; | |
| 46 | +import sun.java2d.pipe.RenderBuffer; | |
| 47 | +import sun.java2d.pipe.TextPipe; | |
| 48 | +import static sun.java2d.pipe.BufferedOpCodes.*; | |
| 49 | +import static sun.java2d.opengl.OGLContext.OGLContextCaps.*; | |
| 50 | + | |
| 51 | +/** | |
| 52 | + * This class describes an OpenGL "surface", that is, a region of pixels | |
| 53 | + * managed via OpenGL. An OGLSurfaceData can be tagged with one of three | |
| 54 | + * different SurfaceType objects for the purpose of registering loops, etc. | |
| 55 | + * This diagram shows the hierarchy of OGL SurfaceTypes: | |
| 56 | + * | |
| 57 | + * Any | |
| 58 | + * / \ | |
| 59 | + * OpenGLSurface OpenGLTexture | |
| 60 | + * | | |
| 61 | + * OpenGLSurfaceRTT | |
| 62 | + * | |
| 63 | + * OpenGLSurface | |
| 64 | + * This kind of surface can be rendered to using OpenGL APIs. It is also | |
| 65 | + * possible to copy an OpenGLSurface to another OpenGLSurface (or to itself). | |
| 66 | + * This is typically accomplished by calling MakeContextCurrent(dstSD, srcSD) | |
| 67 | + * and then calling glCopyPixels() (although there are other techniques to | |
| 68 | + * achieve the same goal). | |
| 69 | + * | |
| 70 | + * OpenGLTexture | |
| 71 | + * This kind of surface cannot be rendered to using OpenGL (in the same sense | |
| 72 | + * as in OpenGLSurface). However, it is possible to upload a region of pixels | |
| 73 | + * to an OpenGLTexture object via glTexSubImage2D(). One can also copy a | |
| 74 | + * surface of type OpenGLTexture to an OpenGLSurface by binding the texture | |
| 75 | + * to a quad and then rendering it to the destination surface (this process | |
| 76 | + * is known as "texture mapping"). | |
| 77 | + * | |
| 78 | + * OpenGLSurfaceRTT | |
| 79 | + * This kind of surface can be thought of as a sort of hybrid between | |
| 80 | + * OpenGLSurface and OpenGLTexture, in that one can render to this kind of | |
| 81 | + * surface as if it were of type OpenGLSurface, but the process of copying | |
| 82 | + * this kind of surface to another is more like an OpenGLTexture. (Note that | |
| 83 | + * "RTT" stands for "render-to-texture".) | |
| 84 | + * | |
| 85 | + * In addition to these SurfaceType variants, we have also defined some | |
| 86 | + * constants that describe in more detail the type of underlying OpenGL | |
| 87 | + * surface. This table helps explain the relationships between those | |
| 88 | + * "type" constants and their corresponding SurfaceType: | |
| 89 | + * | |
| 90 | + * OGL Type Corresponding SurfaceType | |
| 91 | + * -------- ------------------------- | |
| 92 | + * WINDOW OpenGLSurface | |
| 93 | + * PBUFFER OpenGLSurface | |
| 94 | + * TEXTURE OpenGLTexture | |
| 95 | + * FLIP_BACKBUFFER OpenGLSurface | |
| 96 | + * FBOBJECT OpenGLSurfaceRTT | |
| 97 | + */ | |
| 98 | +public abstract class OGLSurfaceData extends SurfaceData | |
| 99 | + implements AccelSurface { | |
| 100 | + | |
| 101 | + /** | |
| 102 | + * OGL-specific surface types | |
| 103 | + * | |
| 104 | + * @see sun.java2d.pipe.hw.AccelSurface | |
| 105 | + */ | |
| 106 | + public static final int PBUFFER = RT_PLAIN; | |
| 107 | + public static final int FBOBJECT = RT_TEXTURE; | |
| 108 | + | |
| 109 | + /** | |
| 110 | + * Pixel formats | |
| 111 | + */ | |
| 112 | + public static final int PF_INT_ARGB = 0; | |
| 113 | + public static final int PF_INT_ARGB_PRE = 1; | |
| 114 | + public static final int PF_INT_RGB = 2; | |
| 115 | + public static final int PF_INT_RGBX = 3; | |
| 116 | + public static final int PF_INT_BGR = 4; | |
| 117 | + public static final int PF_INT_BGRX = 5; | |
| 118 | + public static final int PF_USHORT_565_RGB = 6; | |
| 119 | + public static final int PF_USHORT_555_RGB = 7; | |
| 120 | + public static final int PF_USHORT_555_RGBX = 8; | |
| 121 | + public static final int PF_BYTE_GRAY = 9; | |
| 122 | + public static final int PF_USHORT_GRAY = 10; | |
| 123 | + public static final int PF_3BYTE_BGR = 11; | |
| 124 | + | |
| 125 | + /** | |
| 126 | + * SurfaceTypes | |
| 127 | + */ | |
| 128 | + private static final String DESC_OPENGL_SURFACE = "OpenGL Surface"; | |
| 129 | + private static final String DESC_OPENGL_SURFACE_RTT = | |
| 130 | + "OpenGL Surface (render-to-texture)"; | |
| 131 | + private static final String DESC_OPENGL_TEXTURE = "OpenGL Texture"; | |
| 132 | + | |
| 133 | + static final SurfaceType OpenGLSurface = | |
| 134 | + SurfaceType.Any.deriveSubType(DESC_OPENGL_SURFACE, | |
| 135 | + PixelConverter.ArgbPre.instance); | |
| 136 | + static final SurfaceType OpenGLSurfaceRTT = | |
| 137 | + OpenGLSurface.deriveSubType(DESC_OPENGL_SURFACE_RTT); | |
| 138 | + static final SurfaceType OpenGLTexture = | |
| 139 | + SurfaceType.Any.deriveSubType(DESC_OPENGL_TEXTURE); | |
| 140 | + | |
| 141 | + /** This will be true if the fbobject system property has been enabled. */ | |
| 142 | + private static boolean isFBObjectEnabled; | |
| 143 | + | |
| 144 | + /** This will be true if the lcdshader system property has been enabled.*/ | |
| 145 | + private static boolean isLCDShaderEnabled; | |
| 146 | + | |
| 147 | + /** This will be true if the biopshader system property has been enabled.*/ | |
| 148 | + private static boolean isBIOpShaderEnabled; | |
| 149 | + | |
| 150 | + /** This will be true if the gradshader system property has been enabled.*/ | |
| 151 | + private static boolean isGradShaderEnabled; | |
| 152 | + | |
| 153 | + private OGLGraphicsConfig graphicsConfig; | |
| 154 | + protected int type; | |
| 155 | + // these fields are set from the native code when the surface is | |
| 156 | + // initialized | |
| 157 | + private int nativeWidth, nativeHeight; | |
| 158 | + | |
| 159 | + protected static OGLRenderer oglRenderPipe; | |
| 160 | + protected static PixelToParallelogramConverter oglTxRenderPipe; | |
| 161 | + protected static ParallelogramPipe oglAAPgramPipe; | |
| 162 | + protected static OGLTextRenderer oglTextPipe; | |
| 163 | + protected static OGLDrawImage oglImagePipe; | |
| 164 | + | |
| 165 | + protected native boolean initTexture(long pData, | |
| 166 | + boolean isOpaque, boolean texNonPow2, | |
| 167 | + boolean texRect, | |
| 168 | + int width, int height); | |
| 169 | + protected native boolean initFBObject(long pData, | |
| 170 | + boolean isOpaque, boolean texNonPow2, | |
| 171 | + boolean texRect, | |
| 172 | + int width, int height); | |
| 173 | + protected native boolean initFlipBackbuffer(long pData); | |
| 174 | + protected abstract boolean initPbuffer(long pData, long pConfigInfo, | |
| 175 | + boolean isOpaque, | |
| 176 | + int width, int height); | |
| 177 | + | |
| 178 | + private native int getTextureTarget(long pData); | |
| 179 | + private native int getTextureID(long pData); | |
| 180 | + | |
| 181 | + static { | |
| 182 | + if (!GraphicsEnvironment.isHeadless()) { | |
| 183 | + // fbobject currently enabled by default; use "false" to disable | |
| 184 | + String fbo = (String)java.security.AccessController.doPrivileged( | |
| 185 | + new sun.security.action.GetPropertyAction( | |
| 186 | + "sun.java2d.opengl.fbobject")); | |
| 187 | + isFBObjectEnabled = !"false".equals(fbo); | |
| 188 | + | |
| 189 | + // lcdshader currently enabled by default; use "false" to disable | |
| 190 | + String lcd = (String)java.security.AccessController.doPrivileged( | |
| 191 | + new sun.security.action.GetPropertyAction( | |
| 192 | + "sun.java2d.opengl.lcdshader")); | |
| 193 | + isLCDShaderEnabled = !"false".equals(lcd); | |
| 194 | + | |
| 195 | + // biopshader currently enabled by default; use "false" to disable | |
| 196 | + String biop = (String)java.security.AccessController.doPrivileged( | |
| 197 | + new sun.security.action.GetPropertyAction( | |
| 198 | + "sun.java2d.opengl.biopshader")); | |
| 199 | + isBIOpShaderEnabled = !"false".equals(biop); | |
| 200 | + | |
| 201 | + // gradshader currently enabled by default; use "false" to disable | |
| 202 | + String grad = (String)java.security.AccessController.doPrivileged( | |
| 203 | + new sun.security.action.GetPropertyAction( | |
| 204 | + "sun.java2d.opengl.gradshader")); | |
| 205 | + isGradShaderEnabled = !"false".equals(grad); | |
| 206 | + | |
| 207 | + OGLRenderQueue rq = OGLRenderQueue.getInstance(); | |
| 208 | + oglImagePipe = new OGLDrawImage(); | |
| 209 | + oglTextPipe = new OGLTextRenderer(rq); | |
| 210 | + oglRenderPipe = new OGLRenderer(rq); | |
| 211 | + if (GraphicsPrimitive.tracingEnabled()) { | |
| 212 | + oglTextPipe = oglTextPipe.traceWrap(); | |
| 213 | + //The wrapped oglRenderPipe will wrap the AA pipe as well... | |
| 214 | + //oglAAPgramPipe = oglRenderPipe.traceWrap(); | |
| 215 | + } | |
| 216 | + oglAAPgramPipe = oglRenderPipe.getAAParallelogramPipe(); | |
| 217 | + oglTxRenderPipe = | |
| 218 | + new PixelToParallelogramConverter(oglRenderPipe, | |
| 219 | + oglRenderPipe, | |
| 220 | + 1.0, 0.25, true); | |
| 221 | + | |
| 222 | + OGLBlitLoops.register(); | |
| 223 | + OGLMaskFill.register(); | |
| 224 | + OGLMaskBlit.register(); | |
| 225 | + } | |
| 226 | + } | |
| 227 | + | |
| 228 | + protected OGLSurfaceData(OGLGraphicsConfig gc, | |
| 229 | + ColorModel cm, int type) | |
| 230 | + { | |
| 231 | + super(getCustomSurfaceType(type), cm); | |
| 232 | + this.graphicsConfig = gc; | |
| 233 | + this.type = type; | |
| 234 | + setBlitProxyKey(gc.getProxyKey()); | |
| 235 | + } | |
| 236 | + | |
| 237 | + @Override | |
| 238 | + public SurfaceDataProxy makeProxyFor(SurfaceData srcData) { | |
| 239 | + return OGLSurfaceDataProxy.createProxy(srcData, graphicsConfig); | |
| 240 | + } | |
| 241 | + | |
| 242 | + /** | |
| 243 | + * Returns the appropriate SurfaceType corresponding to the given OpenGL | |
| 244 | + * surface type constant (e.g. TEXTURE -> OpenGLTexture). | |
| 245 | + */ | |
| 246 | + private static SurfaceType getCustomSurfaceType(int oglType) { | |
| 247 | + switch (oglType) { | |
| 248 | + case TEXTURE: | |
| 249 | + return OpenGLTexture; | |
| 250 | + case FBOBJECT: | |
| 251 | + return OpenGLSurfaceRTT; | |
| 252 | + case PBUFFER: | |
| 253 | + default: | |
| 254 | + return OpenGLSurface; | |
| 255 | + } | |
| 256 | + } | |
| 257 | + | |
396 more lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 339 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
Binary file not shown.
This diff is large: its 216 lines aren’t shown here.
Binary file not shown.
This diff is large: its 46 lines aren’t shown here.
Binary file not shown.
This diff is large: its 112 lines aren’t shown here.
Binary file not shown.
This diff is large: its 91 lines aren’t shown here.
Binary file not shown.
Binary file not shown.
This diff is large: its 207 lines aren’t shown here.
This diff is large: its 394 lines aren’t shown here.
Binary file not shown.
This diff is large: its 471 lines aren’t shown here.
This diff is large: its 164 lines aren’t shown here.
This diff is large: its 154 lines aren’t shown here.
Binary file not shown.
This diff is large: its 100 lines aren’t shown here.
Binary file not shown.
This diff is large: its 534 lines aren’t shown here.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This diff is large: its 602 lines aren’t shown here.
This diff is large: its 169 lines aren’t shown here.
Binary file not shown.
This diff is large: its 51 lines aren’t shown here.
Binary file not shown.
This diff is large: its 1111 lines aren’t shown here.
Binary file not shown.
This diff is large: its 87 lines aren’t shown here.
Binary file not shown.
Binary file not shown.
This diff is large: its 155 lines aren’t shown here.
Binary file not shown.
This diff is large: its 61 lines aren’t shown here.
Binary file not shown.
This diff is large: its 148 lines aren’t shown here.
Binary file not shown.
This diff is large: its 45 lines aren’t shown here.
Binary file not shown.
This diff is large: its 38 lines aren’t shown here.
Binary file not shown.
This diff is large: its 379 lines aren’t shown here.
Binary file not shown.
This diff is large: its 156 lines aren’t shown here.
Binary file not shown.
This diff is large: its 146 lines aren’t shown here.
Binary file not shown.
This diff is large: its 77 lines aren’t shown here.
Binary file not shown.
This diff is large: its 68 lines aren’t shown here.
Binary file not shown.
This diff is large: its 62 lines aren’t shown here.
Binary file not shown.
This diff is large: its 430 lines aren’t shown here.
Binary file not shown.
This diff is large: its 134 lines aren’t shown here.
Binary file not shown.
Binary file not shown.
This diff is large: its 1256 lines aren’t shown here.
Binary file not shown.
This diff is large: its 393 lines aren’t shown here.
Binary file not shown.
This diff is large: its 102 lines aren’t shown here.
Binary file not shown.
This diff is large: its 211 lines aren’t shown here.
Binary file not shown.
This diff is large: its 295 lines aren’t shown here.
Binary file not shown.
This diff is large: its 224 lines aren’t shown here.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This diff is large: its 483 lines aren’t shown here.
Binary file not shown.
This diff is large: its 41 lines aren’t shown here.
Binary file not shown.
This diff is large: its 202 lines aren’t shown here.
Binary file not shown.
This diff is large: its 45 lines aren’t shown here.
Binary file not shown.
Binary file not shown.
This diff is large: its 142 lines aren’t shown here.
Binary file not shown.
This diff is large: its 96 lines aren’t shown here.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This diff is large: its 217 lines aren’t shown here.
Binary file not shown.
This diff is large: its 50 lines aren’t shown here.
Binary file not shown.
This diff is large: its 99 lines aren’t shown here.
Binary file not shown.
This diff is large: its 242 lines aren’t shown here.
Binary file not shown.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 168 lines aren’t shown here.
Binary file not shown.
This diff is large: its 96 lines aren’t shown here.
Binary file not shown.
This diff is large: its 137 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
Binary file not shown.
This diff is large: its 46 lines aren’t shown here.
Binary file not shown.
This diff is large: its 129 lines aren’t shown here.
Binary file not shown.
Binary file not shown.
This diff is large: its 155 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 291 lines aren’t shown here.
This diff is large: its 576 lines aren’t shown here.
This diff is large: its 459 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 187 lines aren’t shown here.
This diff is large: its 657 lines aren’t shown here.
This diff is large: its 253 lines aren’t shown here.
This diff is large: its 572 lines aren’t shown here.
This diff is large: its 1224 lines aren’t shown here.
This diff is large: its 394 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.