Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.graphics;
     18 
     19 import com.android.layoutlib.bridge.impl.DelegateManager;
     20 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
     21 
     22 import android.graphics.PorterDuff.Mode;
     23 
     24 import java.awt.Graphics2D;
     25 import java.awt.image.BufferedImage;
     26 
     27 import static com.android.layoutlib.bridge.impl.PorterDuffUtility.getComposite;
     28 import static com.android.layoutlib.bridge.impl.PorterDuffUtility.getPorterDuffMode;
     29 
     30 /**
     31  * Delegate implementing the native methods of android.graphics.PorterDuffColorFilter
     32  *
     33  * Through the layoutlib_create tool, the original native methods of PorterDuffColorFilter have
     34  * been replaced by calls to methods of the same name in this delegate class.
     35  *
     36  * This class behaves like the original native implementation, but in Java, keeping previously
     37  * native data into its own objects and mapping them to int that are sent back and forth between
     38  * it and the original PorterDuffColorFilter class.
     39  *
     40  * Because this extends {@link ColorFilter_Delegate}, there's no need to use a
     41  * {@link DelegateManager}, as all the Shader classes will be added to the manager
     42  * owned by {@link ColorFilter_Delegate}.
     43  *
     44  * @see ColorFilter_Delegate
     45  *
     46  */
     47 public class PorterDuffColorFilter_Delegate extends ColorFilter_Delegate {
     48 
     49     // ---- delegate data ----
     50 
     51     private final int mSrcColor;
     52     private final Mode mMode;
     53 
     54 
     55     // ---- Public Helper methods ----
     56 
     57     @Override
     58     public boolean isSupported() {
     59         return true;
     60     }
     61 
     62     @Override
     63     public String getSupportMessage() {
     64         return "PorterDuff Color Filter is not supported for mode: " + mMode.name() + ".";
     65     }
     66 
     67     @Override
     68     public void applyFilter(Graphics2D g, int width, int height) {
     69         BufferedImage image = createFilterImage(width, height);
     70         g.setComposite(getComposite(mMode, 0xFF));
     71         g.drawImage(image, 0, 0, null);
     72     }
     73 
     74     // ---- native methods ----
     75 
     76     @LayoutlibDelegate
     77     /*package*/ static long native_CreatePorterDuffFilter(int srcColor, int porterDuffMode) {
     78         PorterDuffColorFilter_Delegate newDelegate =
     79                 new PorterDuffColorFilter_Delegate(srcColor, porterDuffMode);
     80         return sManager.addNewDelegate(newDelegate);
     81     }
     82 
     83 
     84     // ---- Private delegate/helper methods ----
     85 
     86     private PorterDuffColorFilter_Delegate(int srcColor, int mode) {
     87         mSrcColor = srcColor;
     88         mMode = getCompatibleMode(getPorterDuffMode(mode));
     89     }
     90 
     91     private BufferedImage createFilterImage(int width, int height) {
     92         BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
     93         Graphics2D graphics = image.createGraphics();
     94         try {
     95             graphics.setColor(new java.awt.Color(mSrcColor, true /* hasAlpha */));
     96             graphics.fillRect(0, 0, width, height);
     97         } finally {
     98             graphics.dispose();
     99         }
    100         return image;
    101     }
    102 
    103     // For filtering the colors, the src image should contain the "color" only for pixel values
    104     // which are not transparent in the target image. But, we are using a simple rectangular image
    105     // completely filled with color. Hence some Composite rules do not apply as intended. However,
    106     // in such cases, they can usually be mapped to some other mode, which produces an
    107     // equivalent result.
    108     private Mode getCompatibleMode(Mode mode) {
    109         Mode m = mode;
    110         // Modes that are directly supported:
    111         // CLEAR, DST, SRC_IN, DST_IN, DST_OUT, SRC_ATOP, DARKEN, LIGHTEN, MULTIPLY, SCREEN,
    112         // ADD, OVERLAY
    113         switch (mode) {
    114         // Modes that can be mapped to one of the supported modes.
    115         case SRC:
    116             m = Mode.SRC_IN;
    117             break;
    118         case SRC_OVER:
    119             m = Mode.SRC_ATOP;
    120             break;
    121         case DST_OVER:
    122             m = Mode.DST;
    123             break;
    124         case SRC_OUT:
    125             m = Mode.CLEAR;
    126             break;
    127         case DST_ATOP:
    128             m = Mode.DST_IN;
    129             break;
    130         case XOR:
    131             m = Mode.DST_OUT;
    132             break;
    133         }
    134         return m;
    135     }
    136 }
    137