1 /*
2 * Copyright 2007, The Android Open Source Project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "android_graphics.h"
28 #include "IntPoint.h"
29 #include "IntRect.h"
30 #include "FloatPoint.h"
31 #include "FloatRect.h"
32 #include "SkCanvas.h"
33 #include "SkColorPriv.h"
34 #include "SkCornerPathEffect.h"
35 #include "SkGradientShader.h"
36 #include "SkPath.h"
37 #include "SkRegion.h"
38
android_setpt(SkPoint * dst,const WebCore::IntPoint & src)39 SkPoint* android_setpt(SkPoint* dst, const WebCore::IntPoint& src)
40 {
41 dst->set(SkIntToScalar(src.x()), SkIntToScalar(src.y()));
42 return dst;
43 }
44
android_setpt(SkPoint * dst,const WebCore::FloatPoint & src)45 SkPoint* android_setpt(SkPoint* dst, const WebCore::FloatPoint& src)
46 {
47 dst->set(SkFloatToScalar(src.x()), SkFloatToScalar(src.y()));
48 return dst;
49 }
50
android_setrect(SkRect * dst,const WebCore::IntRect & src)51 SkRect* android_setrect(SkRect* dst, const WebCore::IntRect& src)
52 {
53 dst->set(SkIntToScalar(src.x()),
54 SkIntToScalar(src.y()),
55 SkIntToScalar(src.x() + src.width()),
56 SkIntToScalar(src.y() + src.height()));
57 return dst;
58 }
59
android_setrect(SkIRect * dst,const WebCore::IntRect & src)60 SkIRect* android_setrect(SkIRect* dst, const WebCore::IntRect& src)
61 {
62 dst->set(src.x(), src.y(),
63 src.x() + src.width(),
64 src.y() + src.height());
65 return dst;
66 }
67
android_setrect(SkRect * dst,const WebCore::FloatRect & src)68 SkRect* android_setrect(SkRect* dst, const WebCore::FloatRect& src)
69 {
70 dst->set(SkFloatToScalar(src.x()),
71 SkFloatToScalar(src.y()),
72 SkFloatToScalar(src.x() + src.width()),
73 SkFloatToScalar(src.y() + src.height()));
74 return dst;
75 }
76
android_setrect(SkIRect * dst,const WebCore::FloatRect & src)77 SkIRect* android_setrect(SkIRect* dst, const WebCore::FloatRect& src)
78 {
79 dst->set(SkScalarRound(SkFloatToScalar(src.x())),
80 SkScalarRound(SkFloatToScalar(src.y())),
81 SkScalarRound(SkFloatToScalar(src.x() + src.width())),
82 SkScalarRound(SkFloatToScalar(src.y() + src.height())));
83 return dst;
84 }
85
android_setrect_scaled(SkIRect * dst,const WebCore::FloatRect & src,float sx,float sy)86 SkIRect* android_setrect_scaled(SkIRect* dst, const WebCore::FloatRect& src,
87 float sx, float sy)
88 {
89 dst->set(SkScalarRound(SkFloatToScalar(src.x() * sx)),
90 SkScalarRound(SkFloatToScalar(src.y() * sy)),
91 SkScalarRound(SkFloatToScalar((src.x() + src.width()) * sx)),
92 SkScalarRound(SkFloatToScalar((src.y() + src.height()) * sy)));
93 return dst;
94 }
95
96 static const struct CompositOpToPorterDuffMode {
97 uint8_t mCompositOp;
98 uint8_t mPorterDuffMode;
99 } gMapCompositOpsToPorterDuffModes[] = {
100 { WebCore::CompositeClear, SkPorterDuff::kClear_Mode },
101 { WebCore::CompositeCopy, SkPorterDuff::kSrc_Mode },
102 { WebCore::CompositeSourceOver, SkPorterDuff::kSrcOver_Mode },
103 { WebCore::CompositeSourceIn, SkPorterDuff::kSrcIn_Mode },
104 { WebCore::CompositeSourceOut, SkPorterDuff::kSrcOut_Mode },
105 { WebCore::CompositeSourceAtop, SkPorterDuff::kSrcATop_Mode },
106 { WebCore::CompositeDestinationOver, SkPorterDuff::kDstOver_Mode },
107 { WebCore::CompositeDestinationIn, SkPorterDuff::kDstIn_Mode },
108 { WebCore::CompositeDestinationOut, SkPorterDuff::kDstOut_Mode },
109 { WebCore::CompositeDestinationAtop, SkPorterDuff::kDstATop_Mode },
110 { WebCore::CompositeXOR, SkPorterDuff::kXor_Mode },
111 { WebCore::CompositePlusDarker, SkPorterDuff::kDarken_Mode },
112 { WebCore::CompositeHighlight, SkPorterDuff::kSrcOver_Mode }, // TODO
113 { WebCore::CompositePlusLighter, SkPorterDuff::kLighten_Mode }
114 };
115
android_convert_compositeOp(WebCore::CompositeOperator op)116 SkPorterDuff::Mode android_convert_compositeOp(WebCore::CompositeOperator op)
117 {
118 const CompositOpToPorterDuffMode* table = gMapCompositOpsToPorterDuffModes;
119
120 for (unsigned i = 0; i < SK_ARRAY_COUNT(gMapCompositOpsToPorterDuffModes); i++) {
121 if (table[i].mCompositOp == op) {
122 return (SkPorterDuff::Mode)table[i].mPorterDuffMode;
123 }
124 }
125
126 SkDEBUGF(("GraphicsContext::setCompositeOperation uknown CompositOperator %d\n", op));
127 return SkPorterDuff::kSrcOver_Mode; // fall-back
128 }
129
android_convert_TileRule(WebCore::Image::TileRule rule)130 SkShader::TileMode android_convert_TileRule(WebCore::Image::TileRule rule)
131 {
132 // stretch == clamp
133 // repeat == repeat
134 // RoundTile???
135
136 return WebCore::Image::RepeatTile == rule ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode;
137 }
138
139 /////////////////////////////////////////////////////////////////////////////////////////////////////////
140
InvScaleByte(U8CPU component,uint32_t scale)141 static U8CPU InvScaleByte(U8CPU component, uint32_t scale)
142 {
143 SkASSERT(component == (uint8_t)component);
144 return (component * scale + 0x8000) >> 16;
145 }
146
147 // move this guy into SkColor.h
SkPMColorToColor(SkPMColor pm)148 static SkColor SkPMColorToColor(SkPMColor pm)
149 {
150 if (0 == pm)
151 return 0;
152
153 unsigned a = SkGetPackedA32(pm);
154 uint32_t scale = (255 << 16) / a;
155
156 return SkColorSetARGB(a,
157 InvScaleByte(SkGetPackedR32(pm), scale),
158 InvScaleByte(SkGetPackedG32(pm), scale),
159 InvScaleByte(SkGetPackedB32(pm), scale));
160 }
161
android_SkPMColorToWebCoreColor(SkPMColor pm)162 WebCore::Color android_SkPMColorToWebCoreColor(SkPMColor pm)
163 {
164 SkColor c = SkPMColorToColor(pm);
165
166 // need the cast to find the right constructor
167 return WebCore::Color((int)SkColorGetR(c), (int)SkColorGetG(c),
168 (int)SkColorGetB(c), (int)SkColorGetA(c));
169 }
170
171 const static SkColor focusOuterColors[] = {
172 SkColorSetARGB(0xff, 0xB3, 0x3F, 0x08), // normal focus ring select
173 SkColorSetARGB(0xff, 0x46, 0xb0, 0x00), // fake focus ring select, for phone, email, text
174 SkColorSetARGB(0xff, 0xb0, 0x16, 0x00), // invalid focus ring color
175 SkColorSetARGB(0xff, 0xAD, 0x5C, 0x0A), // normal focus ring pressed
176 SkColorSetARGB(0xff, 0x36, 0xc0, 0x00) // fake focus ring pressed
177 };
178
179 const static SkColor focusInnerColors[] = {
180 SkColorSetARGB(0xff, 0xFE, 0x92, 0x30), // normal focus ring select
181 SkColorSetARGB(0xff, 0x8c, 0xd9, 0x00), // fake focus ring select, for phone, email, text
182 SkColorSetARGB(0xff, 0xd9, 0x2c, 0x00), // invalid focus ring color
183 SkColorSetARGB(0xff, 0xFE, 0xBD, 0x3A), // normal focus ring pressed
184 SkColorSetARGB(0xff, 0x7c, 0xe9, 0x00) // fake focus ring pressed
185 };
186
187 const static SkColor focusPressedColors[] = {
188 SkColorSetARGB(0x80, 0xFF, 0xC6, 0x4B), // normal focus ring pressed
189 SkColorSetARGB(0x80, 0x7c, 0xe9, 0x00) // fake focus ring pressed
190 };
191
192 #define FOCUS_RING_ROUNDEDNESS SkIntToScalar(5) // used to draw corners
193 #define FOCUS_RING_INNER_DIAMETER SkFixedToScalar(SkIntToFixed(3)>>1) // 3/2 == 1.5
194 #define FOCUS_RING_OUTER_OUTSET 2 // used to inflate rects added to region
195
DrawRing(SkCanvas * canvas,const Vector<WebCore::IntRect> & rects,Flavor flavor)196 void FocusRing::DrawRing(SkCanvas* canvas,
197 const Vector<WebCore::IntRect>& rects, Flavor flavor)
198 {
199 unsigned rectCount = rects.size();
200 SkRegion rgn;
201 SkPath path;
202 for (unsigned i = 0; i < rectCount; i++)
203 {
204 SkIRect r;
205
206 android_setrect(&r, rects[i]);
207 r.inset(-FOCUS_RING_OUTER_OUTSET, -FOCUS_RING_OUTER_OUTSET);
208 rgn.op(r, SkRegion::kUnion_Op);
209 }
210 rgn.getBoundaryPath(&path);
211
212 SkPaint paint;
213 paint.setAntiAlias(true);
214 paint.setPathEffect(new SkCornerPathEffect(FOCUS_RING_ROUNDEDNESS))->unref();
215 if (flavor >= NORMAL_ANIMATING) { // pressed
216 paint.setColor(focusPressedColors[flavor - NORMAL_ANIMATING]);
217 canvas->drawPath(path, paint);
218 }
219 paint.setStyle(SkPaint::kStroke_Style);
220 paint.setStrokeWidth(FOCUS_RING_OUTER_DIAMETER);
221 paint.setColor(focusOuterColors[flavor]);
222 canvas->drawPath(path, paint);
223 paint.setStrokeWidth(FOCUS_RING_INNER_DIAMETER);
224 paint.setColor(focusInnerColors[flavor]);
225 canvas->drawPath(path, paint);
226 }
227
228
229