OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium 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 | |
5 #include "ui/gfx/compositor/layer.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/command_line.h" | |
10 #include "base/debug/trace_event.h" | |
11 #include "base/logging.h" | |
12 #include "base/memory/scoped_ptr.h" | |
13 #include "third_party/WebKit/Source/Platform/chromium/public/WebContentLayer.h" | |
14 #include "third_party/WebKit/Source/Platform/chromium/public/WebExternalTextureL
ayer.h" | |
15 #include "third_party/WebKit/Source/Platform/chromium/public/WebFilterOperation.
h" | |
16 #include "third_party/WebKit/Source/Platform/chromium/public/WebFilterOperations
.h" | |
17 #include "third_party/WebKit/Source/Platform/chromium/public/WebFloatPoint.h" | |
18 #include "third_party/WebKit/Source/Platform/chromium/public/WebFloatRect.h" | |
19 #include "third_party/WebKit/Source/Platform/chromium/public/WebSize.h" | |
20 #include "third_party/WebKit/Source/Platform/chromium/public/WebSolidColorLayer.
h" | |
21 #include "ui/base/animation/animation.h" | |
22 #include "ui/gfx/canvas.h" | |
23 #include "ui/gfx/compositor/compositor_switches.h" | |
24 #include "ui/gfx/compositor/layer_animator.h" | |
25 #include "ui/gfx/interpolated_transform.h" | |
26 #include "ui/gfx/point3.h" | |
27 | |
28 namespace { | |
29 | |
30 const float EPSILON = 1e-3f; | |
31 | |
32 bool IsApproximateMultipleOf(float value, float base) { | |
33 float remainder = fmod(fabs(value), base); | |
34 return remainder < EPSILON || base - remainder < EPSILON; | |
35 } | |
36 | |
37 const ui::Layer* GetRoot(const ui::Layer* layer) { | |
38 return layer->parent() ? GetRoot(layer->parent()) : layer; | |
39 } | |
40 | |
41 } // namespace | |
42 | |
43 namespace ui { | |
44 | |
45 Layer::Layer() | |
46 : type_(LAYER_TEXTURED), | |
47 compositor_(NULL), | |
48 parent_(NULL), | |
49 visible_(true), | |
50 fills_bounds_opaquely_(true), | |
51 layer_updated_externally_(false), | |
52 opacity_(1.0f), | |
53 delegate_(NULL) { | |
54 CreateWebLayer(); | |
55 } | |
56 | |
57 Layer::Layer(LayerType type) | |
58 : type_(type), | |
59 compositor_(NULL), | |
60 parent_(NULL), | |
61 visible_(true), | |
62 fills_bounds_opaquely_(true), | |
63 layer_updated_externally_(false), | |
64 opacity_(1.0f), | |
65 delegate_(NULL) { | |
66 CreateWebLayer(); | |
67 } | |
68 | |
69 Layer::~Layer() { | |
70 // Destroying the animator may cause observers to use the layer (and | |
71 // indirectly the WebLayer). Destroy the animator first so that the WebLayer | |
72 // is still around. | |
73 animator_.reset(); | |
74 if (compositor_) | |
75 compositor_->SetRootLayer(NULL); | |
76 if (parent_) | |
77 parent_->Remove(this); | |
78 for (size_t i = 0; i < children_.size(); ++i) | |
79 children_[i]->parent_ = NULL; | |
80 web_layer_.removeFromParent(); | |
81 } | |
82 | |
83 Compositor* Layer::GetCompositor() { | |
84 return GetRoot(this)->compositor_; | |
85 } | |
86 | |
87 void Layer::SetCompositor(Compositor* compositor) { | |
88 // This function must only be called to set the compositor on the root layer, | |
89 // or to reset it. | |
90 DCHECK(!compositor || !compositor_); | |
91 DCHECK(!compositor || compositor->root_layer() == this); | |
92 DCHECK(!parent_); | |
93 compositor_ = compositor; | |
94 } | |
95 | |
96 void Layer::Add(Layer* child) { | |
97 DCHECK(!child->compositor_); | |
98 if (child->parent_) | |
99 child->parent_->Remove(child); | |
100 child->parent_ = this; | |
101 children_.push_back(child); | |
102 web_layer_.addChild(child->web_layer_); | |
103 } | |
104 | |
105 void Layer::Remove(Layer* child) { | |
106 std::vector<Layer*>::iterator i = | |
107 std::find(children_.begin(), children_.end(), child); | |
108 DCHECK(i != children_.end()); | |
109 children_.erase(i); | |
110 child->parent_ = NULL; | |
111 child->web_layer_.removeFromParent(); | |
112 } | |
113 | |
114 void Layer::StackAtTop(Layer* child) { | |
115 if (children_.size() <= 1 || child == children_.back()) | |
116 return; // Already in front. | |
117 StackAbove(child, children_.back()); | |
118 } | |
119 | |
120 void Layer::StackAbove(Layer* child, Layer* other) { | |
121 StackRelativeTo(child, other, true); | |
122 } | |
123 | |
124 void Layer::StackAtBottom(Layer* child) { | |
125 if (children_.size() <= 1 || child == children_.front()) | |
126 return; // Already on bottom. | |
127 StackBelow(child, children_.front()); | |
128 } | |
129 | |
130 void Layer::StackBelow(Layer* child, Layer* other) { | |
131 StackRelativeTo(child, other, false); | |
132 } | |
133 | |
134 bool Layer::Contains(const Layer* other) const { | |
135 for (const Layer* parent = other; parent; parent = parent->parent()) { | |
136 if (parent == this) | |
137 return true; | |
138 } | |
139 return false; | |
140 } | |
141 | |
142 void Layer::SetAnimator(LayerAnimator* animator) { | |
143 if (animator) | |
144 animator->SetDelegate(this); | |
145 animator_.reset(animator); | |
146 } | |
147 | |
148 LayerAnimator* Layer::GetAnimator() { | |
149 if (!animator_.get()) | |
150 SetAnimator(LayerAnimator::CreateDefaultAnimator()); | |
151 return animator_.get(); | |
152 } | |
153 | |
154 void Layer::SetTransform(const ui::Transform& transform) { | |
155 GetAnimator()->SetTransform(transform); | |
156 } | |
157 | |
158 Transform Layer::GetTargetTransform() const { | |
159 if (animator_.get() && animator_->IsAnimatingProperty( | |
160 LayerAnimationElement::TRANSFORM)) | |
161 return animator_->GetTargetTransform(); | |
162 return transform_; | |
163 } | |
164 | |
165 void Layer::SetBounds(const gfx::Rect& bounds) { | |
166 GetAnimator()->SetBounds(bounds); | |
167 } | |
168 | |
169 gfx::Rect Layer::GetTargetBounds() const { | |
170 if (animator_.get() && animator_->IsAnimatingProperty( | |
171 LayerAnimationElement::BOUNDS)) | |
172 return animator_->GetTargetBounds(); | |
173 return bounds_; | |
174 } | |
175 | |
176 void Layer::SetMasksToBounds(bool masks_to_bounds) { | |
177 web_layer_.setMasksToBounds(masks_to_bounds); | |
178 } | |
179 | |
180 bool Layer::GetMasksToBounds() const { | |
181 return web_layer_.masksToBounds(); | |
182 } | |
183 | |
184 void Layer::SetOpacity(float opacity) { | |
185 GetAnimator()->SetOpacity(opacity); | |
186 } | |
187 | |
188 void Layer::SetBackgroundBlur(int blur_radius) | |
189 { | |
190 WebKit::WebFilterOperations filters; | |
191 if (blur_radius) | |
192 filters.append(WebKit::WebBlurFilterOperation(blur_radius)); | |
193 web_layer_.setBackgroundFilters(filters); | |
194 | |
195 background_blur_radius_ = blur_radius; | |
196 } | |
197 | |
198 float Layer::GetTargetOpacity() const { | |
199 if (animator_.get() && animator_->IsAnimatingProperty( | |
200 LayerAnimationElement::OPACITY)) | |
201 return animator_->GetTargetOpacity(); | |
202 return opacity_; | |
203 } | |
204 | |
205 void Layer::SetVisible(bool visible) { | |
206 GetAnimator()->SetVisibility(visible); | |
207 } | |
208 | |
209 bool Layer::GetTargetVisibility() const { | |
210 if (animator_.get() && animator_->IsAnimatingProperty( | |
211 LayerAnimationElement::VISIBILITY)) | |
212 return animator_->GetTargetVisibility(); | |
213 return visible_; | |
214 } | |
215 | |
216 bool Layer::IsDrawn() const { | |
217 const Layer* layer = this; | |
218 while (layer && layer->visible_) | |
219 layer = layer->parent_; | |
220 return layer == NULL; | |
221 } | |
222 | |
223 bool Layer::ShouldDraw() const { | |
224 return type_ != LAYER_NOT_DRAWN && GetCombinedOpacity() > 0.0f; | |
225 } | |
226 | |
227 // static | |
228 void Layer::ConvertPointToLayer(const Layer* source, | |
229 const Layer* target, | |
230 gfx::Point* point) { | |
231 if (source == target) | |
232 return; | |
233 | |
234 const Layer* root_layer = GetRoot(source); | |
235 CHECK_EQ(root_layer, GetRoot(target)); | |
236 | |
237 if (source != root_layer) | |
238 source->ConvertPointForAncestor(root_layer, point); | |
239 if (target != root_layer) | |
240 target->ConvertPointFromAncestor(root_layer, point); | |
241 } | |
242 | |
243 void Layer::SetFillsBoundsOpaquely(bool fills_bounds_opaquely) { | |
244 if (fills_bounds_opaquely_ == fills_bounds_opaquely) | |
245 return; | |
246 | |
247 fills_bounds_opaquely_ = fills_bounds_opaquely; | |
248 | |
249 web_layer_.setOpaque(fills_bounds_opaquely); | |
250 RecomputeDebugBorderColor(); | |
251 } | |
252 | |
253 void Layer::SetExternalTexture(Texture* texture) { | |
254 DCHECK_EQ(type_, LAYER_TEXTURED); | |
255 layer_updated_externally_ = !!texture; | |
256 texture_ = texture; | |
257 if (web_layer_is_accelerated_ != layer_updated_externally_) { | |
258 // Switch to a different type of layer. | |
259 web_layer_.removeAllChildren(); | |
260 WebKit::WebLayer new_layer; | |
261 if (layer_updated_externally_) { | |
262 WebKit::WebExternalTextureLayer texture_layer = | |
263 WebKit::WebExternalTextureLayer::create(); | |
264 texture_layer.setFlipped(texture_->flipped()); | |
265 new_layer = texture_layer; | |
266 } else { | |
267 new_layer = WebKit::WebContentLayer::create(this); | |
268 } | |
269 if (parent_) { | |
270 DCHECK(!parent_->web_layer_.isNull()); | |
271 parent_->web_layer_.replaceChild(web_layer_, new_layer); | |
272 } | |
273 web_layer_ = new_layer; | |
274 web_layer_is_accelerated_ = layer_updated_externally_; | |
275 for (size_t i = 0; i < children_.size(); ++i) { | |
276 DCHECK(!children_[i]->web_layer_.isNull()); | |
277 web_layer_.addChild(children_[i]->web_layer_); | |
278 } | |
279 web_layer_.setAnchorPoint(WebKit::WebFloatPoint(0.f, 0.f)); | |
280 web_layer_.setOpaque(fills_bounds_opaquely_); | |
281 web_layer_.setOpacity(visible_ ? opacity_ : 0.f); | |
282 web_layer_.setDebugBorderWidth(show_debug_borders_ ? 2 : 0); | |
283 RecomputeTransform(); | |
284 RecomputeDebugBorderColor(); | |
285 } | |
286 RecomputeDrawsContentAndUVRect(); | |
287 } | |
288 | |
289 void Layer::SetColor(SkColor color) { | |
290 DCHECK_EQ(type_, LAYER_SOLID_COLOR); | |
291 // WebColor is equivalent to SkColor, per WebColor.h. | |
292 web_layer_.to<WebKit::WebSolidColorLayer>().setBackgroundColor( | |
293 static_cast<WebKit::WebColor>(color)); | |
294 SetFillsBoundsOpaquely(SkColorGetA(color) == 0xFF); | |
295 } | |
296 | |
297 bool Layer::SchedulePaint(const gfx::Rect& invalid_rect) { | |
298 if (type_ == LAYER_SOLID_COLOR || !delegate_) | |
299 return false; | |
300 damaged_region_.op(invalid_rect.x(), | |
301 invalid_rect.y(), | |
302 invalid_rect.right(), | |
303 invalid_rect.bottom(), | |
304 SkRegion::kUnion_Op); | |
305 ScheduleDraw(); | |
306 return true; | |
307 } | |
308 | |
309 void Layer::ScheduleDraw() { | |
310 Compositor* compositor = GetCompositor(); | |
311 if (compositor) | |
312 compositor->ScheduleDraw(); | |
313 } | |
314 | |
315 void Layer::SendDamagedRects() { | |
316 if (delegate_ && !damaged_region_.isEmpty()) { | |
317 for (SkRegion::Iterator iter(damaged_region_); | |
318 !iter.done(); iter.next()) { | |
319 const SkIRect& damaged = iter.rect(); | |
320 WebKit::WebFloatRect web_rect( | |
321 damaged.x(), | |
322 damaged.y(), | |
323 damaged.width(), | |
324 damaged.height()); | |
325 if (!web_layer_is_accelerated_) | |
326 web_layer_.to<WebKit::WebContentLayer>().invalidateRect(web_rect); | |
327 else | |
328 web_layer_.to<WebKit::WebExternalTextureLayer>().invalidateRect( | |
329 web_rect); | |
330 } | |
331 damaged_region_.setEmpty(); | |
332 } | |
333 for (size_t i = 0; i < children_.size(); ++i) | |
334 children_[i]->SendDamagedRects(); | |
335 } | |
336 | |
337 void Layer::SuppressPaint() { | |
338 if (!delegate_) | |
339 return; | |
340 delegate_ = NULL; | |
341 for (size_t i = 0; i < children_.size(); ++i) | |
342 children_[i]->SuppressPaint(); | |
343 } | |
344 | |
345 void Layer::paintContents(WebKit::WebCanvas* web_canvas, | |
346 const WebKit::WebRect& clip) { | |
347 TRACE_EVENT0("ui", "Layer::paintContents"); | |
348 gfx::Canvas canvas(web_canvas); | |
349 if (delegate_) | |
350 delegate_->OnPaintLayer(&canvas); | |
351 } | |
352 | |
353 float Layer::GetCombinedOpacity() const { | |
354 float opacity = opacity_; | |
355 Layer* current = this->parent_; | |
356 while (current) { | |
357 opacity *= current->opacity_; | |
358 current = current->parent_; | |
359 } | |
360 return opacity; | |
361 } | |
362 | |
363 void Layer::StackRelativeTo(Layer* child, Layer* other, bool above) { | |
364 DCHECK_NE(child, other); | |
365 DCHECK_EQ(this, child->parent()); | |
366 DCHECK_EQ(this, other->parent()); | |
367 | |
368 const size_t child_i = | |
369 std::find(children_.begin(), children_.end(), child) - children_.begin(); | |
370 const size_t other_i = | |
371 std::find(children_.begin(), children_.end(), other) - children_.begin(); | |
372 if ((above && child_i == other_i + 1) || (!above && child_i + 1 == other_i)) | |
373 return; | |
374 | |
375 const size_t dest_i = | |
376 above ? | |
377 (child_i < other_i ? other_i : other_i + 1) : | |
378 (child_i < other_i ? other_i - 1 : other_i); | |
379 children_.erase(children_.begin() + child_i); | |
380 children_.insert(children_.begin() + dest_i, child); | |
381 | |
382 child->web_layer_.removeFromParent(); | |
383 web_layer_.insertChild(child->web_layer_, dest_i); | |
384 } | |
385 | |
386 bool Layer::ConvertPointForAncestor(const Layer* ancestor, | |
387 gfx::Point* point) const { | |
388 ui::Transform transform; | |
389 bool result = GetTransformRelativeTo(ancestor, &transform); | |
390 gfx::Point3f p(*point); | |
391 transform.TransformPoint(p); | |
392 *point = p.AsPoint(); | |
393 return result; | |
394 } | |
395 | |
396 bool Layer::ConvertPointFromAncestor(const Layer* ancestor, | |
397 gfx::Point* point) const { | |
398 ui::Transform transform; | |
399 bool result = GetTransformRelativeTo(ancestor, &transform); | |
400 gfx::Point3f p(*point); | |
401 transform.TransformPointReverse(p); | |
402 *point = p.AsPoint(); | |
403 return result; | |
404 } | |
405 | |
406 bool Layer::GetTransformRelativeTo(const Layer* ancestor, | |
407 ui::Transform* transform) const { | |
408 const Layer* p = this; | |
409 for (; p && p != ancestor; p = p->parent()) { | |
410 if (p->transform().HasChange()) | |
411 transform->ConcatTransform(p->transform()); | |
412 transform->ConcatTranslate(static_cast<float>(p->bounds().x()), | |
413 static_cast<float>(p->bounds().y())); | |
414 } | |
415 return p == ancestor; | |
416 } | |
417 | |
418 void Layer::SetBoundsImmediately(const gfx::Rect& bounds) { | |
419 if (bounds == bounds_) | |
420 return; | |
421 | |
422 bool was_move = bounds_.size() == bounds.size(); | |
423 bounds_ = bounds; | |
424 if (IsDrawn()) { | |
425 if (was_move) | |
426 ScheduleDraw(); | |
427 else | |
428 SchedulePaint(gfx::Rect(bounds.size())); | |
429 } | |
430 | |
431 RecomputeTransform(); | |
432 RecomputeDrawsContentAndUVRect(); | |
433 } | |
434 | |
435 void Layer::SetTransformImmediately(const ui::Transform& transform) { | |
436 transform_ = transform; | |
437 | |
438 RecomputeTransform(); | |
439 } | |
440 | |
441 void Layer::SetOpacityImmediately(float opacity) { | |
442 bool schedule_draw = (opacity != opacity_ && IsDrawn()); | |
443 opacity_ = opacity; | |
444 | |
445 if (visible_) | |
446 web_layer_.setOpacity(opacity); | |
447 RecomputeDebugBorderColor(); | |
448 if (schedule_draw) | |
449 ScheduleDraw(); | |
450 } | |
451 | |
452 void Layer::SetVisibilityImmediately(bool visible) { | |
453 if (visible_ == visible) | |
454 return; | |
455 | |
456 visible_ = visible; | |
457 // TODO(piman): Expose a visibility flag on WebLayer. | |
458 web_layer_.setOpacity(visible_ ? opacity_ : 0.f); | |
459 } | |
460 | |
461 void Layer::SetBoundsFromAnimation(const gfx::Rect& bounds) { | |
462 SetBoundsImmediately(bounds); | |
463 } | |
464 | |
465 void Layer::SetTransformFromAnimation(const Transform& transform) { | |
466 SetTransformImmediately(transform); | |
467 } | |
468 | |
469 void Layer::SetOpacityFromAnimation(float opacity) { | |
470 SetOpacityImmediately(opacity); | |
471 } | |
472 | |
473 void Layer::SetVisibilityFromAnimation(bool visibility) { | |
474 SetVisibilityImmediately(visibility); | |
475 } | |
476 | |
477 void Layer::ScheduleDrawForAnimation() { | |
478 ScheduleDraw(); | |
479 } | |
480 | |
481 const gfx::Rect& Layer::GetBoundsForAnimation() const { | |
482 return bounds(); | |
483 } | |
484 | |
485 const Transform& Layer::GetTransformForAnimation() const { | |
486 return transform(); | |
487 } | |
488 | |
489 float Layer::GetOpacityForAnimation() const { | |
490 return opacity(); | |
491 } | |
492 | |
493 bool Layer::GetVisibilityForAnimation() const { | |
494 return visible(); | |
495 } | |
496 | |
497 void Layer::CreateWebLayer() { | |
498 if (type_ == LAYER_SOLID_COLOR) | |
499 web_layer_ = WebKit::WebSolidColorLayer::create(); | |
500 else | |
501 web_layer_ = WebKit::WebContentLayer::create(this); | |
502 web_layer_.setAnchorPoint(WebKit::WebFloatPoint(0.f, 0.f)); | |
503 web_layer_.setOpaque(true); | |
504 web_layer_is_accelerated_ = false; | |
505 show_debug_borders_ = CommandLine::ForCurrentProcess()->HasSwitch( | |
506 switches::kUIShowLayerBorders); | |
507 web_layer_.setDebugBorderWidth(show_debug_borders_ ? 2 : 0); | |
508 RecomputeDrawsContentAndUVRect(); | |
509 RecomputeDebugBorderColor(); | |
510 } | |
511 | |
512 void Layer::RecomputeTransform() { | |
513 ui::Transform transform = transform_; | |
514 transform.ConcatTranslate(bounds_.x(), bounds_.y()); | |
515 web_layer_.setTransform(transform.matrix()); | |
516 } | |
517 | |
518 void Layer::RecomputeDrawsContentAndUVRect() { | |
519 DCHECK(!web_layer_.isNull()); | |
520 bool should_draw = type_ != LAYER_NOT_DRAWN; | |
521 if (!web_layer_is_accelerated_) { | |
522 if (type_ != LAYER_SOLID_COLOR) | |
523 web_layer_.to<WebKit::WebContentLayer>().setDrawsContent(should_draw); | |
524 web_layer_.setBounds(bounds_.size()); | |
525 } else { | |
526 DCHECK(texture_); | |
527 unsigned int texture_id = texture_->texture_id(); | |
528 WebKit::WebExternalTextureLayer texture_layer = | |
529 web_layer_.to<WebKit::WebExternalTextureLayer>(); | |
530 texture_layer.setTextureId(should_draw ? texture_id : 0); | |
531 gfx::Size texture_size = texture_->size(); | |
532 gfx::Size size(std::min(bounds_.width(), texture_size.width()), | |
533 std::min(bounds_.height(), texture_size.height())); | |
534 WebKit::WebFloatRect rect( | |
535 0, | |
536 0, | |
537 static_cast<float>(size.width())/texture_size.width(), | |
538 static_cast<float>(size.height())/texture_size.height()); | |
539 texture_layer.setUVRect(rect); | |
540 web_layer_.setBounds(size); | |
541 } | |
542 } | |
543 | |
544 void Layer::RecomputeDebugBorderColor() { | |
545 if (!show_debug_borders_) | |
546 return; | |
547 unsigned int color = 0xFF000000; | |
548 color |= web_layer_is_accelerated_ ? 0x0000FF00 : 0x00FF0000; | |
549 bool opaque = fills_bounds_opaquely_ && (GetCombinedOpacity() == 1.f); | |
550 if (!opaque) | |
551 color |= 0xFF; | |
552 web_layer_.setDebugBorderColor(color); | |
553 } | |
554 | |
555 } // namespace ui | |
OLD | NEW |