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