Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(456)

Side by Side Diff: sky/sdk/lib/painting/box_painter.dart

Issue 1217623002: Support for background images on cards, style demo home (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: rebase Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sky/sdk/home.dart ('k') | sky/sdk/lib/rendering/box.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 import 'dart:math' as math;
5 import 'dart:sky' as sky; 6 import 'dart:sky' as sky;
6 import 'dart:sky' show Point, Offset, Size, Rect, Color, Paint, Path; 7 import 'dart:sky' show Point, Offset, Size, Rect, Color, Paint, Path;
7 8
8 import 'shadows.dart'; 9 import 'shadows.dart';
10 import 'package:sky/mojo/net/image_cache.dart' as image_cache;
9 11
10 class BorderSide { 12 class BorderSide {
11 const BorderSide({ 13 const BorderSide({
12 this.color: const Color(0xFF000000), 14 this.color: const Color(0xFF000000),
13 this.width: 1.0 15 this.width: 1.0
14 }); 16 });
15 final Color color; 17 final Color color;
16 final double width; 18 final double width;
17 19
18 static const none = const BorderSide(width: 0.0); 20 static const none = const BorderSide(width: 0.0);
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
113 this.colorStops, this.tileMode); 115 this.colorStops, this.tileMode);
114 } 116 }
115 117
116 final Point center; 118 final Point center;
117 final double radius; 119 final double radius;
118 final List<Color> colors; 120 final List<Color> colors;
119 final List<double> colorStops; 121 final List<double> colorStops;
120 final sky.TileMode tileMode; 122 final sky.TileMode tileMode;
121 } 123 }
122 124
125 enum BackgroundFit { fill, contain, cover, none, scaleDown }
126
127 enum BackgroundRepeat { repeat, repeatX, repeatY, noRepeat }
128
129 // TODO(jackson): We should abstract this out into a separate class
130 // that handles the image caching and so forth, which has callbacks
131 // for "size changed" and "image changed". This would also enable us
132 // to do animated images.
133
134 class BackgroundImage {
135 final String src;
136 final BackgroundFit fit;
137 final BackgroundRepeat repeat;
138 BackgroundImage({
139 this.src,
140 this.fit: BackgroundFit.scaleDown,
141 this.repeat: BackgroundRepeat.noRepeat
142 }) {
143 image_cache.load(src, (image) {
144 if (image == null)
145 return;
146 _image = image;
147 _size = new Size(image.width.toDouble(), image.height.toDouble());
148 for (Function listener in _listeners) {
149 listener();
150 }
151 });
152 }
153
154 sky.Image _image;
155 sky.Image get image => _image;
156
157 Size _size;
158
159 final List<Function> _listeners = new List<Function>();
160
161 void addChangeListener(Function listener) {
162 _listeners.add(listener);
163 }
164
165 void removeChangeListener(Function listener) {
166 _listeners.remove(listener);
167 }
168
169 String toString() => 'BackgroundImage($src, $fit, $repeat)';
170 }
171
123 enum Shape { rectangle, circle } 172 enum Shape { rectangle, circle }
124 173
125 // This must be immutable, because we won't notice when it changes 174 // This must be immutable, because we won't notice when it changes
126 class BoxDecoration { 175 class BoxDecoration {
127 const BoxDecoration({ 176 const BoxDecoration({
128 this.backgroundColor, // null = don't draw background 177 this.backgroundColor, // null = don't draw background color
178 this.backgroundImage, // null = don't draw background image
129 this.border, // null = don't draw border 179 this.border, // null = don't draw border
130 this.borderRadius, // null = use more efficient background drawing; note tha t this must be null for circles 180 this.borderRadius, // null = use more efficient background drawing; note tha t this must be null for circles
131 this.boxShadow, // null = don't draw shadows 181 this.boxShadow, // null = don't draw shadows
132 this.gradient, // null = don't allocate gradient objects 182 this.gradient, // null = don't allocate gradient objects
133 this.shape: Shape.rectangle 183 this.shape: Shape.rectangle
134 }); 184 });
135 185
136 final Color backgroundColor; 186 final Color backgroundColor;
187 final BackgroundImage backgroundImage;
137 final double borderRadius; 188 final double borderRadius;
138 final Border border; 189 final Border border;
139 final List<BoxShadow> boxShadow; 190 final List<BoxShadow> boxShadow;
140 final Gradient gradient; 191 final Gradient gradient;
141 final Shape shape; 192 final Shape shape;
142 193
143 String toString([String prefix = '']) { 194 String toString([String prefix = '']) {
144 List<String> result = []; 195 List<String> result = [];
145 if (backgroundColor != null) 196 if (backgroundColor != null)
146 result.add('${prefix}backgroundColor: $backgroundColor'); 197 result.add('${prefix}backgroundColor: $backgroundColor');
198 if (backgroundImage != null)
199 result.add('${prefix}backgroundImage: $backgroundImage');
147 if (border != null) 200 if (border != null)
148 result.add('${prefix}border: $border'); 201 result.add('${prefix}border: $border');
149 if (borderRadius != null) 202 if (borderRadius != null)
150 result.add('${prefix}borderRadius: $borderRadius'); 203 result.add('${prefix}borderRadius: $borderRadius');
151 if (boxShadow != null) 204 if (boxShadow != null)
152 result.add('${prefix}boxShadow: ${boxShadow.map((shadow) => shadow.toStrin g())}'); 205 result.add('${prefix}boxShadow: ${boxShadow.map((shadow) => shadow.toStrin g())}');
153 if (gradient != null) 206 if (gradient != null)
154 result.add('${prefix}gradient: $gradient'); 207 result.add('${prefix}gradient: $gradient');
155 if (shape != Shape.rectangle) 208 if (shape != Shape.rectangle)
156 result.add('${prefix}shape: $shape'); 209 result.add('${prefix}shape: $shape');
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 245
193 if (_decoration.gradient != null) 246 if (_decoration.gradient != null)
194 paint.setShader(_decoration.gradient.createShader()); 247 paint.setShader(_decoration.gradient.createShader());
195 248
196 _cachedBackgroundPaint = paint; 249 _cachedBackgroundPaint = paint;
197 } 250 }
198 251
199 return _cachedBackgroundPaint; 252 return _cachedBackgroundPaint;
200 } 253 }
201 254
202 void paint(sky.Canvas canvas, Rect rect) { 255 void _paintBackgroundColor(sky.Canvas canvas, Rect rect) {
203 if (_decoration.backgroundColor != null || _decoration.boxShadow != null || 256 if (_decoration.backgroundColor != null || _decoration.boxShadow != null ||
204 _decoration.gradient != null) { 257 _decoration.gradient != null) {
205 switch (_decoration.shape) { 258 switch (_decoration.shape) {
206 case Shape.circle: 259 case Shape.circle:
207 assert(_decoration.borderRadius == null); 260 assert(_decoration.borderRadius == null);
208 Point center = rect.center; 261 Point center = rect.center;
209 double radius = rect.shortestSide / 2.0; 262 double radius = rect.shortestSide / 2.0;
210 canvas.drawCircle(center, radius, _backgroundPaint); 263 canvas.drawCircle(center, radius, _backgroundPaint);
211 break; 264 break;
212 case Shape.rectangle: 265 case Shape.rectangle:
213 if (_decoration.borderRadius == null) 266 if (_decoration.borderRadius == null)
214 canvas.drawRect(rect, _backgroundPaint); 267 canvas.drawRect(rect, _backgroundPaint);
215 else 268 else
216 canvas.drawRRect(new sky.RRect()..setRectXY(rect, _decoration.border Radius, _decoration.borderRadius), _backgroundPaint); 269 canvas.drawRRect(new sky.RRect()..setRectXY(rect, _decoration.border Radius, _decoration.borderRadius), _backgroundPaint);
217 break; 270 break;
218 } 271 }
219 } 272 }
273 }
220 274
221 if (_decoration.border != null) { 275 void _paintBackgroundImage(sky.Canvas canvas, Rect rect) {
222 assert(_decoration.borderRadius == null); // TODO(abarth): Implement borde rs with border radius. 276 if (_decoration.backgroundImage == null)
223 assert(_decoration.shape == Shape.rectangle); // TODO(ianh): Implement bor ders on circles. 277 return;
224 278 sky.Image image = _decoration.backgroundImage.image;
225 assert(_decoration.border.top != null); 279 if (image != null) {
226 assert(_decoration.border.right != null); 280 Size bounds = rect.size;
227 assert(_decoration.border.bottom != null); 281 Size imageSize = _decoration.backgroundImage._size;
228 assert(_decoration.border.left != null); 282 Size src;
229 283 Size dst;
230 Paint paint = new Paint(); 284 switch(_decoration.backgroundImage.fit) {
231 Path path; 285 case BackgroundFit.fill:
232 286 src = imageSize;
233 paint.color = _decoration.border.top.color; 287 dst = bounds;
234 path = new Path(); 288 break;
235 path.moveTo(rect.left, rect.top); 289 case BackgroundFit.contain:
236 path.lineTo(rect.left + _decoration.border.left.width, rect.top + _decorat ion.border.top.width); 290 src = imageSize;
237 path.lineTo(rect.right - _decoration.border.right.width, rect.top + _decor ation.border.top.width); 291 if (bounds.width / bounds.height > src.width / src.height) {
238 path.lineTo(rect.right, rect.top); 292 dst = new Size(bounds.width, src.height * bounds.width / src.width);
239 path.close(); 293 } else {
240 canvas.drawPath(path, paint); 294 dst = new Size(src.width * bounds.height / src.height, bounds.height );
241 295 }
242 paint.color = _decoration.border.right.color; 296 break;
243 path = new Path(); 297 case BackgroundFit.cover:
244 path.moveTo(rect.right, rect.top); 298 if (bounds.width / bounds.height > imageSize.width / imageSize.height) {
245 path.lineTo(rect.right - _decoration.border.right.width, rect.top + _decor ation.border.top.width); 299 src = new Size(imageSize.width, imageSize.width * bounds.height / bo unds.width);
246 path.lineTo(rect.right - _decoration.border.right.width, rect.bottom - _de coration.border.bottom.width); 300 } else {
247 path.lineTo(rect.right, rect.bottom); 301 src = new Size(imageSize.height * bounds.width / bounds.height, imag eSize.height);
248 path.close(); 302 }
249 canvas.drawPath(path, paint); 303 dst = bounds;
250 304 break;
251 paint.color = _decoration.border.bottom.color; 305 case BackgroundFit.none:
252 path = new Path(); 306 src = new Size(math.min(imageSize.width, bounds.width),
253 path.moveTo(rect.right, rect.bottom); 307 math.min(imageSize.height, bounds.height));
254 path.lineTo(rect.right - _decoration.border.right.width, rect.bottom - _de coration.border.bottom.width); 308 dst = src;
255 path.lineTo(rect.left + _decoration.border.left.width, rect.bottom - _deco ration.border.bottom.width); 309 break;
256 path.lineTo(rect.left, rect.bottom); 310 case BackgroundFit.scaleDown:
257 path.close(); 311 src = imageSize;
258 canvas.drawPath(path, paint); 312 dst = bounds;
259 313 if (src.height > dst.height) {
260 paint.color = _decoration.border.left.color; 314 dst = new Size(src.width * dst.height / src.height, src.height);
261 path = new Path(); 315 }
262 path.moveTo(rect.left, rect.bottom); 316 if (src.width > dst.width) {
263 path.lineTo(rect.left + _decoration.border.left.width, rect.bottom - _deco ration.border.bottom.width); 317 dst = new Size(dst.width, src.height * dst.width / src.width);
264 path.lineTo(rect.left + _decoration.border.left.width, rect.top + _decorat ion.border.top.width); 318 }
265 path.lineTo(rect.left, rect.top); 319 break;
266 path.close(); 320 }
267 canvas.drawPath(path, paint); 321 canvas.drawImageRect(image, Point.origin & src, rect.topLeft & dst, new Pa int());
268 } 322 }
269 } 323 }
324
325 void _paintBorder(sky.Canvas canvas, Rect rect) {
326 if (_decoration.border == null)
327 return;
328
329 assert(_decoration.borderRadius == null); // TODO(abarth): Implement borders with border radius.
330 assert(_decoration.shape == Shape.rectangle); // TODO(ianh): Implement borde rs on circles.
331
332 assert(_decoration.border.top != null);
333 assert(_decoration.border.right != null);
334 assert(_decoration.border.bottom != null);
335 assert(_decoration.border.left != null);
336
337 Paint paint = new Paint();
338 Path path;
339
340 paint.color = _decoration.border.top.color;
341 path = new Path();
342 path.moveTo(rect.left, rect.top);
343 path.lineTo(rect.left + _decoration.border.left.width, rect.top + _decoratio n.border.top.width);
344 path.lineTo(rect.right - _decoration.border.right.width, rect.top + _decorat ion.border.top.width);
345 path.lineTo(rect.right, rect.top);
346 path.close();
347 canvas.drawPath(path, paint);
348
349 paint.color = _decoration.border.right.color;
350 path = new Path();
351 path.moveTo(rect.right, rect.top);
352 path.lineTo(rect.right - _decoration.border.right.width, rect.top + _decorat ion.border.top.width);
353 path.lineTo(rect.right - _decoration.border.right.width, rect.bottom - _deco ration.border.bottom.width);
354 path.lineTo(rect.right, rect.bottom);
355 path.close();
356 canvas.drawPath(path, paint);
357
358 paint.color = _decoration.border.bottom.color;
359 path = new Path();
360 path.moveTo(rect.right, rect.bottom);
361 path.lineTo(rect.right - _decoration.border.right.width, rect.bottom - _deco ration.border.bottom.width);
362 path.lineTo(rect.left + _decoration.border.left.width, rect.bottom - _decora tion.border.bottom.width);
363 path.lineTo(rect.left, rect.bottom);
364 path.close();
365 canvas.drawPath(path, paint);
366
367 paint.color = _decoration.border.left.color;
368 path = new Path();
369 path.moveTo(rect.left, rect.bottom);
370 path.lineTo(rect.left + _decoration.border.left.width, rect.bottom - _decora tion.border.bottom.width);
371 path.lineTo(rect.left + _decoration.border.left.width, rect.top + _decoratio n.border.top.width);
372 path.lineTo(rect.left, rect.top);
373 path.close();
374 canvas.drawPath(path, paint);
375 }
376
377 void paint(sky.Canvas canvas, Rect rect) {
378 _paintBackgroundColor(canvas, rect);
379 _paintBackgroundImage(canvas, rect);
380 _paintBorder(canvas, rect);
381 }
270 } 382 }
OLDNEW
« no previous file with comments | « sky/sdk/home.dart ('k') | sky/sdk/lib/rendering/box.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698