1 #include "config.h"
2 #include "LayerAndroid.h"
3
4 #if USE(ACCELERATED_COMPOSITING)
5
6 #include "AndroidAnimation.h"
7 #include "DrawExtra.h"
8 #include "SkCanvas.h"
9 #include "SkDrawFilter.h"
10 #include "SkPaint.h"
11 #include "SkPicture.h"
12 #include <wtf/CurrentTime.h>
13
14 #define LAYER_DEBUG // Add diagonals for debugging
15 #undef LAYER_DEBUG
16
17 namespace WebCore {
18
19 static int gDebugLayerAndroidInstances;
20 static int gUniqueId;
21
instancesCount()22 inline int LayerAndroid::instancesCount()
23 {
24 return gDebugLayerAndroidInstances;
25 }
26
27 class OpacityDrawFilter : public SkDrawFilter {
28 public:
OpacityDrawFilter(int opacity)29 OpacityDrawFilter(int opacity) : m_opacity(opacity) { }
filter(SkCanvas * canvas,SkPaint * paint,Type)30 virtual bool filter(SkCanvas* canvas, SkPaint* paint, Type)
31 {
32 m_previousOpacity = paint->getAlpha();
33 paint->setAlpha(m_opacity);
34 return true;
35 }
restore(SkCanvas * canvas,SkPaint * paint,Type)36 virtual void restore(SkCanvas* canvas, SkPaint* paint, Type)
37 {
38 paint->setAlpha(m_previousOpacity);
39 }
40 private:
41 int m_opacity;
42 int m_previousOpacity;
43 };
44
45 ///////////////////////////////////////////////////////////////////////////////
46
LayerAndroid(bool isRootLayer)47 LayerAndroid::LayerAndroid(bool isRootLayer) : SkLayer(),
48 m_isRootLayer(isRootLayer),
49 m_haveClip(false),
50 m_doRotation(false),
51 m_isFixed(false),
52 m_recordingPicture(0),
53 m_extra(0),
54 m_uniqueId(++gUniqueId)
55 {
56 m_angleTransform = 0;
57 m_translation.set(0, 0);
58 m_scale.set(1, 1);
59 m_backgroundColor = 0;
60
61 gDebugLayerAndroidInstances++;
62 }
63
LayerAndroid(const LayerAndroid & layer)64 LayerAndroid::LayerAndroid(const LayerAndroid& layer) : SkLayer(layer),
65 m_isRootLayer(layer.m_isRootLayer),
66 m_haveClip(layer.m_haveClip),
67 m_extra(0), // deliberately not copied
68 m_uniqueId(layer.m_uniqueId)
69 {
70 m_doRotation = layer.m_doRotation;
71 m_isFixed = layer.m_isFixed;
72
73 m_angleTransform = layer.m_angleTransform;
74 m_translation = layer.m_translation;
75 m_scale = layer.m_scale;
76 m_backgroundColor = layer.m_backgroundColor;
77
78 m_fixedLeft = layer.m_fixedLeft;
79 m_fixedTop = layer.m_fixedTop;
80 m_fixedRight = layer.m_fixedRight;
81 m_fixedBottom = layer.m_fixedBottom;
82 m_fixedMarginLeft = layer.m_fixedMarginLeft;
83 m_fixedMarginTop = layer.m_fixedMarginTop;
84 m_fixedMarginRight = layer.m_fixedMarginRight;
85 m_fixedMarginBottom = layer.m_fixedMarginBottom;
86 m_fixedOffset = layer.m_fixedOffset;
87 m_fixedWidth = layer.m_fixedWidth;
88 m_fixedHeight = layer.m_fixedHeight;
89
90 m_recordingPicture = layer.m_recordingPicture;
91 SkSafeRef(m_recordingPicture);
92
93 for (int i = 0; i < layer.countChildren(); i++)
94 addChild(new LayerAndroid(*layer.getChild(i)))->unref();
95
96 KeyframesMap::const_iterator end = layer.m_animations.end();
97 for (KeyframesMap::const_iterator it = layer.m_animations.begin(); it != end; ++it)
98 m_animations.add((it->second)->name(), (it->second)->copy());
99
100 gDebugLayerAndroidInstances++;
101 }
102
LayerAndroid(SkPicture * picture)103 LayerAndroid::LayerAndroid(SkPicture* picture) : SkLayer(),
104 m_isRootLayer(true),
105 m_haveClip(false),
106 m_doRotation(false),
107 m_isFixed(false),
108 m_recordingPicture(picture),
109 m_extra(0),
110 m_uniqueId(-1)
111 {
112 m_angleTransform = 0;
113 m_translation.set(0, 0);
114 m_scale.set(1, 1);
115 m_backgroundColor = 0;
116 SkSafeRef(m_recordingPicture);
117 gDebugLayerAndroidInstances++;
118 }
119
~LayerAndroid()120 LayerAndroid::~LayerAndroid()
121 {
122 removeChildren();
123 m_recordingPicture->safeUnref();
124 m_animations.clear();
125 gDebugLayerAndroidInstances--;
126 }
127
128 static int gDebugNbAnims = 0;
129
evaluateAnimations() const130 bool LayerAndroid::evaluateAnimations() const
131 {
132 double time = WTF::currentTime();
133 gDebugNbAnims = 0;
134 return evaluateAnimations(time);
135 }
136
hasAnimations() const137 bool LayerAndroid::hasAnimations() const
138 {
139 for (int i = 0; i < countChildren(); i++) {
140 if (getChild(i)->hasAnimations())
141 return true;
142 }
143 return !!m_animations.size();
144 }
145
evaluateAnimations(double time) const146 bool LayerAndroid::evaluateAnimations(double time) const
147 {
148 bool hasRunningAnimations = false;
149 for (int i = 0; i < countChildren(); i++) {
150 if (getChild(i)->evaluateAnimations(time))
151 hasRunningAnimations = true;
152 }
153 KeyframesMap::const_iterator end = m_animations.end();
154 for (KeyframesMap::const_iterator it = m_animations.begin(); it != end; ++it) {
155 gDebugNbAnims++;
156 LayerAndroid* currentLayer = const_cast<LayerAndroid*>(this);
157 if ((it->second)->evaluate(currentLayer, time)) {
158 hasRunningAnimations = true;
159 }
160 }
161
162 return hasRunningAnimations;
163 }
164
addAnimation(PassRefPtr<AndroidAnimation> anim)165 void LayerAndroid::addAnimation(PassRefPtr<AndroidAnimation> anim)
166 {
167 m_animations.add(anim->name(), anim);
168 }
169
removeAnimation(const String & name)170 void LayerAndroid::removeAnimation(const String& name)
171 {
172 m_animations.remove(name);
173 }
174
175 // We only use the bounding rect of the layer as mask...
176 // TODO: use a real mask?
setMaskLayer(LayerAndroid * layer)177 void LayerAndroid::setMaskLayer(LayerAndroid* layer)
178 {
179 if (layer)
180 m_haveClip = true;
181 }
182
setMasksToBounds(bool masksToBounds)183 void LayerAndroid::setMasksToBounds(bool masksToBounds)
184 {
185 m_haveClip = masksToBounds;
186 }
187
setBackgroundColor(SkColor color)188 void LayerAndroid::setBackgroundColor(SkColor color)
189 {
190 m_backgroundColor = color;
191 }
192
193 static int gDebugChildLevel;
194
bounds(SkRect * rect) const195 void LayerAndroid::bounds(SkRect* rect) const
196 {
197 const SkPoint& pos = this->getPosition();
198 const SkSize& size = this->getSize();
199 rect->fLeft = pos.fX + m_translation.fX;
200 rect->fTop = pos.fY + m_translation.fY;
201 rect->fRight = rect->fLeft + size.width();
202 rect->fBottom = rect->fTop + size.height();
203 }
204
boundsIsUnique(const SkTDArray<SkRect> & region,const SkRect & local)205 static bool boundsIsUnique(const SkTDArray<SkRect>& region,
206 const SkRect& local)
207 {
208 for (int i = 0; i < region.count(); i++) {
209 if (region[i].contains(local))
210 return false;
211 }
212 return true;
213 }
214
clipArea(SkTDArray<SkRect> * region) const215 void LayerAndroid::clipArea(SkTDArray<SkRect>* region) const
216 {
217 SkRect local;
218 local.set(0, 0, std::numeric_limits<float>::max(),
219 std::numeric_limits<float>::max());
220 clipInner(region, local);
221 }
222
clipInner(SkTDArray<SkRect> * region,const SkRect & local) const223 void LayerAndroid::clipInner(SkTDArray<SkRect>* region,
224 const SkRect& local) const
225 {
226 SkRect localBounds;
227 bounds(&localBounds);
228 localBounds.intersect(local);
229 if (localBounds.isEmpty())
230 return;
231 if (m_recordingPicture && boundsIsUnique(*region, localBounds))
232 *region->append() = localBounds;
233 for (int i = 0; i < countChildren(); i++)
234 getChild(i)->clipInner(region, m_haveClip ? localBounds : local);
235 }
236
find(int x,int y) const237 const LayerAndroid* LayerAndroid::find(int x, int y) const
238 {
239 for (int i = 0; i < countChildren(); i++) {
240 const LayerAndroid* found = getChild(i)->find(x, y);
241 if (found)
242 return found;
243 }
244 SkRect localBounds;
245 bounds(&localBounds);
246 if (localBounds.contains(x, y))
247 return this;
248 return 0;
249 }
250
251 ///////////////////////////////////////////////////////////////////////////////
252
253 // The Layer bounds and the renderview bounds are not always indentical.
254 // We need to compute the intersection to correctly compute the
255 // positiong...
computeLayerRect(LayerAndroid * layer)256 static SkRect computeLayerRect(LayerAndroid* layer) {
257 SkRect layerRect, viewRect;
258 SkScalar fX, fY;
259 fX = layer->getOffset().fX;
260 fY = layer->getOffset().fY;
261 layerRect.set(0, 0, layer->getSize().width(), layer->getSize().height());
262 viewRect.set(-fX, -fY, -fX + layer->getFixedWidth(), -fY + layer->getFixedHeight());
263 layerRect.intersect(viewRect);
264 return layerRect;
265 }
266
updateFixedLayersPositions(const SkRect & viewport)267 void LayerAndroid::updateFixedLayersPositions(const SkRect& viewport)
268 {
269 if (m_isFixed) {
270 float w = viewport.width();
271 float h = viewport.height();
272 float dx = viewport.fLeft;
273 float dy = viewport.fTop;
274 float x = dx;
275 float y = dy;
276
277 SkRect layerRect = computeLayerRect(this);
278
279 if (m_fixedLeft.defined())
280 x += m_fixedMarginLeft.calcFloatValue(w) + m_fixedLeft.calcFloatValue(w) - layerRect.fLeft;
281 else if (m_fixedRight.defined())
282 x += w - m_fixedMarginRight.calcFloatValue(w) - m_fixedRight.calcFloatValue(w) - layerRect.width();
283
284 if (m_fixedTop.defined())
285 y += m_fixedMarginTop.calcFloatValue(h) + m_fixedTop.calcFloatValue(h) - layerRect.fTop;
286 else if (m_fixedBottom.defined())
287 y += h - m_fixedMarginBottom.calcFloatValue(h) - m_fixedBottom.calcFloatValue(h) - layerRect.fTop - layerRect.height();
288
289 this->setPosition(x, y);
290 }
291
292 int count = this->countChildren();
293 for (int i = 0; i < count; i++) {
294 this->getChild(i)->updateFixedLayersPositions(viewport);
295 }
296 }
297
updatePositions()298 void LayerAndroid::updatePositions() {
299 // apply the viewport to us
300 SkMatrix matrix;
301 if (!m_isFixed) {
302 // turn our fields into a matrix.
303 //
304 // TODO: this should happen in the caller, and we should remove these
305 // fields from our subclass
306 matrix.setTranslate(m_translation.fX, m_translation.fY);
307 if (m_doRotation) {
308 matrix.preRotate(m_angleTransform);
309 }
310 matrix.preScale(m_scale.fX, m_scale.fY);
311 this->setMatrix(matrix);
312 }
313
314 // now apply it to our children
315 int count = this->countChildren();
316 for (int i = 0; i < count; i++) {
317 this->getChild(i)->updatePositions();
318 }
319 }
320
onDraw(SkCanvas * canvas,SkScalar opacity)321 void LayerAndroid::onDraw(SkCanvas* canvas, SkScalar opacity) {
322 if (m_haveClip) {
323 SkRect r;
324 r.set(0, 0, getSize().width(), getSize().height());
325 canvas->clipRect(r);
326 }
327
328 if (!prepareContext())
329 return;
330
331 // we just have this save/restore for opacity...
332 SkAutoCanvasRestore restore(canvas, true);
333
334 int canvasOpacity = SkScalarRound(opacity * 255);
335 if (canvasOpacity < 255)
336 canvas->setDrawFilter(new OpacityDrawFilter(canvasOpacity));
337
338 canvas->drawPicture(*m_recordingPicture);
339 if (m_extra)
340 m_extra->draw(canvas, this);
341
342 #ifdef LAYER_DEBUG
343 float w = getSize().width();
344 float h = getSize().height();
345 SkPaint paint;
346 paint.setARGB(128, 255, 0, 0);
347 canvas->drawLine(0, 0, w, h, paint);
348 canvas->drawLine(0, h, w, 0, paint);
349 paint.setARGB(128, 0, 255, 0);
350 canvas->drawLine(0, 0, 0, h, paint);
351 canvas->drawLine(0, h, w, h, paint);
352 canvas->drawLine(w, h, w, 0, paint);
353 canvas->drawLine(w, 0, 0, 0, paint);
354
355 if (m_isFixed) {
356 SkRect layerRect = computeLayerRect(this);
357 SkPaint paint;
358 paint.setARGB(128, 0, 0, 255);
359 canvas->drawRect(layerRect, paint);
360 }
361 #endif
362 }
363
recordContext()364 SkPicture* LayerAndroid::recordContext()
365 {
366 if (prepareContext(true))
367 return m_recordingPicture;
368 return 0;
369 }
370
prepareContext(bool force)371 bool LayerAndroid::prepareContext(bool force)
372 {
373 if (!m_isRootLayer) {
374 if (force || !m_recordingPicture
375 || (m_recordingPicture
376 && ((m_recordingPicture->width() != (int) getSize().width())
377 || (m_recordingPicture->height() != (int) getSize().height())))) {
378 m_recordingPicture->safeUnref();
379 m_recordingPicture = new SkPicture();
380 }
381 } else if (m_recordingPicture) {
382 m_recordingPicture->safeUnref();
383 m_recordingPicture = 0;
384 }
385
386 return m_recordingPicture;
387 }
388
subtractLayers(const SkRect & visibleRect) const389 SkRect LayerAndroid::subtractLayers(const SkRect& visibleRect) const
390 {
391 SkRect result;
392 if (m_recordingPicture) {
393 SkRect globalRect = bounds();
394 globalRect.offset(-getPosition()); // localToGlobal adds in position
395 SkMatrix globalMatrix;
396 localToGlobal(&globalMatrix);
397 globalMatrix.mapRect(&globalRect);
398 SkIRect roundedGlobal;
399 globalRect.round(&roundedGlobal);
400 SkIRect iVisibleRect;
401 visibleRect.round(&iVisibleRect);
402 SkRegion visRegion(iVisibleRect);
403 visRegion.op(roundedGlobal, SkRegion::kDifference_Op);
404 result.set(visRegion.getBounds());
405 #if DEBUG_NAV_UI
406 SkDebugf("%s visibleRect=(%g,%g,r=%g,b=%g) globalRect=(%g,%g,r=%g,b=%g)"
407 "result=(%g,%g,r=%g,b=%g)", __FUNCTION__,
408 visibleRect.fLeft, visibleRect.fTop,
409 visibleRect.fRight, visibleRect.fBottom,
410 globalRect.fLeft, globalRect.fTop,
411 globalRect.fRight, globalRect.fBottom,
412 result.fLeft, result.fTop, result.fRight, result.fBottom);
413 #endif
414 } else
415 result = visibleRect;
416 for (int i = 0; i < countChildren(); i++)
417 result = getChild(i)->subtractLayers(result);
418 return result;
419 }
420
421 // Debug tools : dump the layers tree in a file.
422 // The format is simple:
423 // properties have the form: key = value;
424 // all statements are finished with a semi-colon.
425 // value can be:
426 // - int
427 // - float
428 // - array of elements
429 // - composed type
430 // a composed type enclose properties in { and }
431 // an array enclose composed types in { }, separated with a comma.
432 // exemple:
433 // {
434 // x = 3;
435 // y = 4;
436 // value = {
437 // x = 3;
438 // y = 4;
439 // };
440 // anarray = [
441 // { x = 3; },
442 // { y = 4; }
443 // ];
444 // }
445
lwrite(FILE * file,const char * str)446 void lwrite(FILE* file, const char* str)
447 {
448 fwrite(str, sizeof(char), strlen(str), file);
449 }
450
writeIndent(FILE * file,int indentLevel)451 void writeIndent(FILE* file, int indentLevel)
452 {
453 if (indentLevel)
454 fprintf(file, "%*s", indentLevel*2, " ");
455 }
456
writeln(FILE * file,int indentLevel,const char * str)457 void writeln(FILE* file, int indentLevel, const char* str)
458 {
459 writeIndent(file, indentLevel);
460 lwrite(file, str);
461 lwrite(file, "\n");
462 }
463
writeIntVal(FILE * file,int indentLevel,const char * str,int value)464 void writeIntVal(FILE* file, int indentLevel, const char* str, int value)
465 {
466 writeIndent(file, indentLevel);
467 fprintf(file, "%s = %d;\n", str, value);
468 }
469
writeHexVal(FILE * file,int indentLevel,const char * str,int value)470 void writeHexVal(FILE* file, int indentLevel, const char* str, int value)
471 {
472 writeIndent(file, indentLevel);
473 fprintf(file, "%s = %x;\n", str, value);
474 }
475
writeFloatVal(FILE * file,int indentLevel,const char * str,float value)476 void writeFloatVal(FILE* file, int indentLevel, const char* str, float value)
477 {
478 writeIndent(file, indentLevel);
479 fprintf(file, "%s = %.3f;\n", str, value);
480 }
481
writePoint(FILE * file,int indentLevel,const char * str,SkPoint point)482 void writePoint(FILE* file, int indentLevel, const char* str, SkPoint point)
483 {
484 writeIndent(file, indentLevel);
485 fprintf(file, "%s = { x = %.3f; y = %.3f; };\n", str, point.fX, point.fY);
486 }
487
writeSize(FILE * file,int indentLevel,const char * str,SkSize size)488 void writeSize(FILE* file, int indentLevel, const char* str, SkSize size)
489 {
490 writeIndent(file, indentLevel);
491 fprintf(file, "%s = { w = %.3f; h = %.3f; };\n", str, size.width(), size.height());
492 }
493
writeLength(FILE * file,int indentLevel,const char * str,SkLength length)494 void writeLength(FILE* file, int indentLevel, const char* str, SkLength length)
495 {
496 if (!length.defined()) return;
497 writeIndent(file, indentLevel);
498 fprintf(file, "%s = { type = %d; value = %.2f; };\n", str, length.type, length.value);
499 }
500
dumpLayers(FILE * file,int indentLevel) const501 void LayerAndroid::dumpLayers(FILE* file, int indentLevel) const
502 {
503 writeln(file, indentLevel, "{");
504
505 writeHexVal(file, indentLevel + 1, "layer", (int)this);
506 writeIntVal(file, indentLevel + 1, "layerId", m_uniqueId);
507 writeIntVal(file, indentLevel + 1, "haveClip", m_haveClip);
508 writeIntVal(file, indentLevel + 1, "isRootLayer", m_isRootLayer);
509 writeIntVal(file, indentLevel + 1, "isFixed", m_isFixed);
510
511 writeFloatVal(file, indentLevel + 1, "opacity", getOpacity());
512 writeSize(file, indentLevel + 1, "size", getSize());
513 writePoint(file, indentLevel + 1, "position", getPosition());
514 writePoint(file, indentLevel + 1, "translation", m_translation);
515 writePoint(file, indentLevel + 1, "anchor", getAnchorPoint());
516 writePoint(file, indentLevel + 1, "scale", m_scale);
517
518 if (m_doRotation)
519 writeFloatVal(file, indentLevel + 1, "angle", m_angleTransform);
520
521 if (m_isFixed) {
522 writeLength(file, indentLevel + 1, "fixedLeft", m_fixedLeft);
523 writeLength(file, indentLevel + 1, "fixedTop", m_fixedTop);
524 writeLength(file, indentLevel + 1, "fixedRight", m_fixedRight);
525 writeLength(file, indentLevel + 1, "fixedBottom", m_fixedBottom);
526 writeLength(file, indentLevel + 1, "fixedMarginLeft", m_fixedMarginLeft);
527 writeLength(file, indentLevel + 1, "fixedMarginTop", m_fixedMarginTop);
528 writeLength(file, indentLevel + 1, "fixedMarginRight", m_fixedMarginRight);
529 writeLength(file, indentLevel + 1, "fixedMarginBottom", m_fixedMarginBottom);
530 writePoint(file, indentLevel + 1, "fixedOffset", m_fixedOffset);
531 writeIntVal(file, indentLevel + 1, "fixedWidth", m_fixedWidth);
532 writeIntVal(file, indentLevel + 1, "fixedHeight", m_fixedHeight);
533 }
534
535 if (m_recordingPicture) {
536 writeIntVal(file, indentLevel + 1, "picture width", m_recordingPicture->width());
537 writeIntVal(file, indentLevel + 1, "picture height", m_recordingPicture->height());
538 }
539
540 if (countChildren()) {
541 writeln(file, indentLevel + 1, "children = [");
542 for (int i = 0; i < countChildren(); i++) {
543 if (i > 0)
544 writeln(file, indentLevel + 1, ", ");
545 getChild(i)->dumpLayers(file, indentLevel + 1);
546 }
547 writeln(file, indentLevel + 1, "];");
548 }
549 writeln(file, indentLevel, "}");
550 }
551
dumpToLog() const552 void LayerAndroid::dumpToLog() const
553 {
554 FILE* file = fopen("/data/data/com.android.browser/layertmp", "w");
555 dumpLayers(file, 0);
556 fclose(file);
557 file = fopen("/data/data/com.android.browser/layertmp", "r");
558 char buffer[512];
559 bzero(buffer, sizeof(buffer));
560 while (fgets(buffer, sizeof(buffer), file))
561 SkDebugf("%s", buffer);
562 fclose(file);
563 }
564
findById(int match) const565 const LayerAndroid* LayerAndroid::findById(int match) const
566 {
567 if (m_uniqueId == match)
568 return this;
569 for (int i = 0; i < countChildren(); i++) {
570 const LayerAndroid* result = getChild(i)->findById(match);
571 if (result)
572 return result;
573 }
574 return 0;
575 }
576
setExtra(DrawExtra * extra)577 void LayerAndroid::setExtra(DrawExtra* extra)
578 {
579 m_extra = extra;
580 for (int i = 0; i < countChildren(); i++)
581 getChild(i)->setExtra(extra);
582 }
583
584 } // namespace WebCore
585
586 #endif // USE(ACCELERATED_COMPOSITING)
587