1// Copyright 2013 The Flutter Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5part of engine; 6 7/// A canvas that renders to DOM elements and CSS properties. 8class DomCanvas extends EngineCanvas with SaveElementStackTracking { 9 @override 10 final html.Element rootElement = html.Element.tag('flt-dom-canvas'); 11 12 DomCanvas() { 13 rootElement.style 14 ..position = 'absolute' 15 ..top = '0' 16 ..right = '0' 17 ..bottom = '0' 18 ..left = '0'; 19 } 20 21 /// Prepare to reuse this canvas by clearing it's current contents. 22 @override 23 void clear() { 24 super.clear(); 25 // TODO(yjbanov): we should measure if reusing old elements is beneficial. 26 domRenderer.clearDom(rootElement); 27 } 28 29 @override 30 void clipRect(ui.Rect rect) { 31 throw UnimplementedError(); 32 } 33 34 @override 35 void clipRRect(ui.RRect rrect) { 36 throw UnimplementedError(); 37 } 38 39 @override 40 void clipPath(ui.Path path) { 41 throw UnimplementedError(); 42 } 43 44 @override 45 void drawColor(ui.Color color, ui.BlendMode blendMode) { 46 // TODO(yjbanov): implement blendMode 47 final html.Element box = html.Element.tag('draw-color'); 48 box.style 49 ..position = 'absolute' 50 ..top = '0' 51 ..right = '0' 52 ..bottom = '0' 53 ..left = '0' 54 ..backgroundColor = color.toCssString(); 55 currentElement.append(box); 56 } 57 58 @override 59 void drawLine(ui.Offset p1, ui.Offset p2, ui.PaintData paint) { 60 throw UnimplementedError(); 61 } 62 63 @override 64 void drawPaint(ui.PaintData paint) { 65 throw UnimplementedError(); 66 } 67 68 @override 69 void drawRect(ui.Rect rect, ui.PaintData paint) { 70 assert(paint.shader == null); 71 final html.Element rectangle = html.Element.tag('draw-rect'); 72 assert(() { 73 rectangle.setAttribute('flt-rect', '$rect'); 74 rectangle.setAttribute('flt-paint', '$paint'); 75 return true; 76 }()); 77 String effectiveTransform; 78 final bool isStroke = paint.style == ui.PaintingStyle.stroke; 79 final double left = math.min(rect.left, rect.right); 80 final double right = math.max(rect.left, rect.right); 81 final double top = math.min(rect.top, rect.bottom); 82 final double bottom = math.max(rect.top, rect.bottom); 83 if (currentTransform.isIdentity()) { 84 if (isStroke) { 85 effectiveTransform = 86 'translate(${left - (paint.strokeWidth / 2.0)}px, ${top - (paint.strokeWidth / 2.0)}px)'; 87 } else { 88 effectiveTransform = 'translate(${left}px, ${top}px)'; 89 } 90 } else { 91 // Clone to avoid mutating _transform. 92 final Matrix4 translated = currentTransform.clone(); 93 if (isStroke) { 94 translated.translate( 95 left - (paint.strokeWidth / 2.0), top - (paint.strokeWidth / 2.0)); 96 } else { 97 translated.translate(left, top); 98 } 99 effectiveTransform = matrix4ToCssTransform(translated); 100 } 101 final html.CssStyleDeclaration style = rectangle.style; 102 style 103 ..position = 'absolute' 104 ..transformOrigin = '0 0 0' 105 ..transform = effectiveTransform; 106 107 final String cssColor = paint.color?.toCssString() ?? '#000000'; 108 109 if (paint.maskFilter != null) { 110 style.filter = 'blur(${paint.maskFilter.webOnlySigma}px)'; 111 } 112 113 if (isStroke) { 114 style 115 ..width = '${right - left - paint.strokeWidth}px' 116 ..height = '${bottom - top - paint.strokeWidth}px' 117 ..border = '${paint.strokeWidth}px solid $cssColor'; 118 } else { 119 style 120 ..width = '${right - left}px' 121 ..height = '${bottom - top}px' 122 ..backgroundColor = cssColor; 123 } 124 125 currentElement.append(rectangle); 126 } 127 128 @override 129 void drawRRect(ui.RRect rrect, ui.PaintData paint) { 130 throw UnimplementedError(); 131 } 132 133 @override 134 void drawDRRect(ui.RRect outer, ui.RRect inner, ui.PaintData paint) { 135 throw UnimplementedError(); 136 } 137 138 @override 139 void drawOval(ui.Rect rect, ui.PaintData paint) { 140 throw UnimplementedError(); 141 } 142 143 @override 144 void drawCircle(ui.Offset c, double radius, ui.PaintData paint) { 145 throw UnimplementedError(); 146 } 147 148 @override 149 void drawPath(ui.Path path, ui.PaintData paint) { 150 throw UnimplementedError(); 151 } 152 153 @override 154 void drawShadow(ui.Path path, ui.Color color, double elevation, 155 bool transparentOccluder) { 156 throw UnimplementedError(); 157 } 158 159 @override 160 void drawImage(ui.Image image, ui.Offset p, ui.PaintData paint) { 161 throw UnimplementedError(); 162 } 163 164 @override 165 void drawImageRect( 166 ui.Image image, ui.Rect src, ui.Rect dst, ui.PaintData paint) { 167 throw UnimplementedError(); 168 } 169 170 @override 171 void drawParagraph(ui.Paragraph paragraph, ui.Offset offset) { 172 final html.Element paragraphElement = 173 _drawParagraphElement(paragraph, offset, transform: currentTransform); 174 currentElement.append(paragraphElement); 175 } 176} 177