Showing the changes to java/pkg/sun/java2d/SurfaceDataProxy.java (1 of 18352 files). Show all
Unified · Split
| @@ -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 | } | ||