1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/* 2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Copyright (C) 2010 The Android Open Source Project 3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * you may not use this file except in compliance with the License. 6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * You may obtain a copy of the License at 7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Unless required by applicable law or agreed to in writing, software 11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * See the License for the specific language governing permissions and 14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * limitations under the License. 15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipackage android.graphics; 18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.layoutlib.bridge.impl.DelegateManager; 20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.tools.layoutlib.annotations.LayoutlibDelegate; 21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 22f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Guptaimport android.graphics.PorterDuff.Mode; 23f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta 24f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Guptaimport java.awt.Graphics2D; 25f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Guptaimport java.awt.image.BufferedImage; 26f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta 278ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Guptaimport static com.android.layoutlib.bridge.impl.PorterDuffUtility.getComposite; 28f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Guptaimport static com.android.layoutlib.bridge.impl.PorterDuffUtility.getPorterDuffMode; 29f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta 30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/** 31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Delegate implementing the native methods of android.graphics.PorterDuffColorFilter 32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Through the layoutlib_create tool, the original native methods of PorterDuffColorFilter have 34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * been replaced by calls to methods of the same name in this delegate class. 35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * This class behaves like the original native implementation, but in Java, keeping previously 37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * native data into its own objects and mapping them to int that are sent back and forth between 38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * it and the original PorterDuffColorFilter class. 39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Because this extends {@link ColorFilter_Delegate}, there's no need to use a 41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * {@link DelegateManager}, as all the Shader classes will be added to the manager 42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * owned by {@link ColorFilter_Delegate}. 43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @see ColorFilter_Delegate 45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipublic class PorterDuffColorFilter_Delegate extends ColorFilter_Delegate { 48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // ---- delegate data ---- 50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 51f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta private final int mSrcColor; 52f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta private final Mode mMode; 53f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta 54f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta 55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // ---- Public Helper methods ---- 56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski @Override 58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public boolean isSupported() { 598ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta return true; 60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski @Override 63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public String getSupportMessage() { 64f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta return "PorterDuff Color Filter is not supported for mode: " + mMode.name() + "."; 65f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta } 66f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta 67f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta @Override 68f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta public void applyFilter(Graphics2D g, int width, int height) { 697a139f3fc9b8c90e4580bb3f4f8f4c90a2b8d088Deepanshu Gupta BufferedImage image = createFilterImage(width, height); 708ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta g.setComposite(getComposite(mMode, 0xFF)); 717a139f3fc9b8c90e4580bb3f4f8f4c90a2b8d088Deepanshu Gupta g.drawImage(image, 0, 0, null); 72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // ---- native methods ---- 75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski @LayoutlibDelegate 7788a8364c386c694f7ad56662ef89713dbf7c9d63Narayan Kamath /*package*/ static long native_CreatePorterDuffFilter(int srcColor, int porterDuffMode) { 78f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta PorterDuffColorFilter_Delegate newDelegate = 79f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta new PorterDuffColorFilter_Delegate(srcColor, porterDuffMode); 80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return sManager.addNewDelegate(newDelegate); 81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 83f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta 84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // ---- Private delegate/helper methods ---- 85f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta 86f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta private PorterDuffColorFilter_Delegate(int srcColor, int mode) { 87f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta mSrcColor = srcColor; 887a139f3fc9b8c90e4580bb3f4f8f4c90a2b8d088Deepanshu Gupta mMode = getCompatibleMode(getPorterDuffMode(mode)); 89f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta } 90f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta 917a139f3fc9b8c90e4580bb3f4f8f4c90a2b8d088Deepanshu Gupta private BufferedImage createFilterImage(int width, int height) { 927a139f3fc9b8c90e4580bb3f4f8f4c90a2b8d088Deepanshu Gupta BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 937a139f3fc9b8c90e4580bb3f4f8f4c90a2b8d088Deepanshu Gupta Graphics2D graphics = image.createGraphics(); 94f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta try { 95f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta graphics.setColor(new java.awt.Color(mSrcColor, true /* hasAlpha */)); 96f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta graphics.fillRect(0, 0, width, height); 97f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta } finally { 98f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta graphics.dispose(); 99f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta } 1007a139f3fc9b8c90e4580bb3f4f8f4c90a2b8d088Deepanshu Gupta return image; 101f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta } 102f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta 1037a139f3fc9b8c90e4580bb3f4f8f4c90a2b8d088Deepanshu Gupta // For filtering the colors, the src image should contain the "color" only for pixel values 1047a139f3fc9b8c90e4580bb3f4f8f4c90a2b8d088Deepanshu Gupta // which are not transparent in the target image. But, we are using a simple rectangular image 1058ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta // completely filled with color. Hence some Composite rules do not apply as intended. However, 1068ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta // in such cases, they can usually be mapped to some other mode, which produces an 1077a139f3fc9b8c90e4580bb3f4f8f4c90a2b8d088Deepanshu Gupta // equivalent result. 1087a139f3fc9b8c90e4580bb3f4f8f4c90a2b8d088Deepanshu Gupta private Mode getCompatibleMode(Mode mode) { 1097a139f3fc9b8c90e4580bb3f4f8f4c90a2b8d088Deepanshu Gupta Mode m = mode; 1108ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta // Modes that are directly supported: 1118ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta // CLEAR, DST, SRC_IN, DST_IN, DST_OUT, SRC_ATOP, DARKEN, LIGHTEN, MULTIPLY, SCREEN, 1128ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta // ADD, OVERLAY 1137a139f3fc9b8c90e4580bb3f4f8f4c90a2b8d088Deepanshu Gupta switch (mode) { 1148ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta // Modes that can be mapped to one of the supported modes. 1158ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta case SRC: 1168ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta m = Mode.SRC_IN; 1178ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta break; 1188ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta case SRC_OVER: 1198ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta m = Mode.SRC_ATOP; 1208ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta break; 1218ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta case DST_OVER: 1228ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta m = Mode.DST; 1238ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta break; 1248ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta case SRC_OUT: 1258ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta m = Mode.CLEAR; 1268ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta break; 1278ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta case DST_ATOP: 1288ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta m = Mode.DST_IN; 1298ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta break; 1308ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta case XOR: 1318ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta m = Mode.DST_OUT; 1328ee6bcf8096803fe5c4fbc3838a296a692173e49Deepanshu Gupta break; 1337a139f3fc9b8c90e4580bb3f4f8f4c90a2b8d088Deepanshu Gupta } 1347a139f3fc9b8c90e4580bb3f4f8f4c90a2b8d088Deepanshu Gupta return m; 135f2af1f5d8aaff684f8cc6d8e31454c945e190976Deepanshu Gupta } 136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski} 137