OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 #include "ui/gfx/compositor/layer.h" | 5 #include "ui/gfx/compositor/layer.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
(...skipping 18 matching lines...) Expand all Loading... | |
29 } // namespace | 29 } // namespace |
30 | 30 |
31 namespace ui { | 31 namespace ui { |
32 | 32 |
33 Layer::Layer(Compositor* compositor) | 33 Layer::Layer(Compositor* compositor) |
34 : type_(LAYER_HAS_TEXTURE), | 34 : type_(LAYER_HAS_TEXTURE), |
35 compositor_(compositor), | 35 compositor_(compositor), |
36 parent_(NULL), | 36 parent_(NULL), |
37 visible_(true), | 37 visible_(true), |
38 fills_bounds_opaquely_(true), | 38 fills_bounds_opaquely_(true), |
39 recompute_hole_(false), | |
39 layer_updated_externally_(false), | 40 layer_updated_externally_(false), |
40 opacity_(1.0f), | 41 opacity_(1.0f), |
41 delegate_(NULL) { | 42 delegate_(NULL) { |
42 #if defined(USE_WEBKIT_COMPOSITOR) | 43 #if defined(USE_WEBKIT_COMPOSITOR) |
43 CreateWebLayer(); | 44 CreateWebLayer(); |
44 #endif | 45 #endif |
45 } | 46 } |
46 | 47 |
47 Layer::Layer(Compositor* compositor, LayerType type) | 48 Layer::Layer(Compositor* compositor, LayerType type) |
48 : type_(type), | 49 : type_(type), |
49 compositor_(compositor), | 50 compositor_(compositor), |
50 parent_(NULL), | 51 parent_(NULL), |
51 visible_(true), | 52 visible_(true), |
52 fills_bounds_opaquely_(true), | 53 fills_bounds_opaquely_(true), |
54 recompute_hole_(false), | |
53 layer_updated_externally_(false), | 55 layer_updated_externally_(false), |
54 opacity_(1.0f), | 56 opacity_(1.0f), |
55 delegate_(NULL) { | 57 delegate_(NULL) { |
56 #if defined(USE_WEBKIT_COMPOSITOR) | 58 #if defined(USE_WEBKIT_COMPOSITOR) |
57 CreateWebLayer(); | 59 CreateWebLayer(); |
58 #endif | 60 #endif |
59 } | 61 } |
60 | 62 |
61 Layer::~Layer() { | 63 Layer::~Layer() { |
62 if (parent_) | 64 if (parent_) |
(...skipping 20 matching lines...) Expand all Loading... | |
83 | 85 |
84 void Layer::Add(Layer* child) { | 86 void Layer::Add(Layer* child) { |
85 if (child->parent_) | 87 if (child->parent_) |
86 child->parent_->Remove(child); | 88 child->parent_->Remove(child); |
87 child->parent_ = this; | 89 child->parent_ = this; |
88 children_.push_back(child); | 90 children_.push_back(child); |
89 #if defined(USE_WEBKIT_COMPOSITOR) | 91 #if defined(USE_WEBKIT_COMPOSITOR) |
90 web_layer_.addChild(child->web_layer_); | 92 web_layer_.addChild(child->web_layer_); |
91 #endif | 93 #endif |
92 | 94 |
93 RecomputeHole(); | 95 SetNeedsToRecomputeHole(); |
94 } | 96 } |
95 | 97 |
96 void Layer::Remove(Layer* child) { | 98 void Layer::Remove(Layer* child) { |
97 std::vector<Layer*>::iterator i = | 99 std::vector<Layer*>::iterator i = |
98 std::find(children_.begin(), children_.end(), child); | 100 std::find(children_.begin(), children_.end(), child); |
99 DCHECK(i != children_.end()); | 101 DCHECK(i != children_.end()); |
100 children_.erase(i); | 102 children_.erase(i); |
101 child->parent_ = NULL; | 103 child->parent_ = NULL; |
102 #if defined(USE_WEBKIT_COMPOSITOR) | 104 #if defined(USE_WEBKIT_COMPOSITOR) |
103 child->web_layer_.removeFromParent(); | 105 child->web_layer_.removeFromParent(); |
104 #endif | 106 #endif |
105 | 107 |
106 RecomputeHole(); | 108 SetNeedsToRecomputeHole(); |
107 | 109 |
108 child->DropTextures(); | 110 child->DropTextures(); |
109 } | 111 } |
110 | 112 |
111 void Layer::MoveToFront(Layer* child) { | 113 void Layer::MoveToFront(Layer* child) { |
112 std::vector<Layer*>::iterator i = | 114 std::vector<Layer*>::iterator i = |
113 std::find(children_.begin(), children_.end(), child); | 115 std::find(children_.begin(), children_.end(), child); |
114 DCHECK(i != children_.end()); | 116 DCHECK(i != children_.end()); |
115 children_.erase(i); | 117 children_.erase(i); |
116 children_.push_back(child); | 118 children_.push_back(child); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
178 return; | 180 return; |
179 | 181 |
180 bool was_drawn = IsDrawn(); | 182 bool was_drawn = IsDrawn(); |
181 visible_ = visible; | 183 visible_ = visible; |
182 bool is_drawn = IsDrawn(); | 184 bool is_drawn = IsDrawn(); |
183 if (was_drawn == is_drawn) | 185 if (was_drawn == is_drawn) |
184 return; | 186 return; |
185 | 187 |
186 if (!is_drawn) | 188 if (!is_drawn) |
187 DropTextures(); | 189 DropTextures(); |
188 if (parent_) | 190 SetNeedsToRecomputeHole(); |
189 parent_->RecomputeHole(); | |
190 #if defined(USE_WEBKIT_COMPOSITOR) | 191 #if defined(USE_WEBKIT_COMPOSITOR) |
191 // TODO(piman): Expose a visibility flag on WebLayer. | 192 // TODO(piman): Expose a visibility flag on WebLayer. |
192 web_layer_.setOpacity(visible_ ? opacity_ : 0.f); | 193 web_layer_.setOpacity(visible_ ? opacity_ : 0.f); |
193 #endif | 194 #endif |
194 } | 195 } |
195 | 196 |
196 bool Layer::IsDrawn() const { | 197 bool Layer::IsDrawn() const { |
197 const Layer* layer = this; | 198 const Layer* layer = this; |
198 while (layer && layer->visible_) | 199 while (layer && layer->visible_) |
199 layer = layer->parent_; | 200 layer = layer->parent_; |
(...skipping 23 matching lines...) Expand all Loading... | |
223 NOTREACHED(); // |source| and |target| are in unrelated hierarchies. | 224 NOTREACHED(); // |source| and |target| are in unrelated hierarchies. |
224 } | 225 } |
225 } | 226 } |
226 | 227 |
227 void Layer::SetFillsBoundsOpaquely(bool fills_bounds_opaquely) { | 228 void Layer::SetFillsBoundsOpaquely(bool fills_bounds_opaquely) { |
228 if (fills_bounds_opaquely_ == fills_bounds_opaquely) | 229 if (fills_bounds_opaquely_ == fills_bounds_opaquely) |
229 return; | 230 return; |
230 | 231 |
231 fills_bounds_opaquely_ = fills_bounds_opaquely; | 232 fills_bounds_opaquely_ = fills_bounds_opaquely; |
232 | 233 |
233 if (parent()) | 234 SetNeedsToRecomputeHole(); |
234 parent()->RecomputeHole(); | |
235 #if defined(USE_WEBKIT_COMPOSITOR) | 235 #if defined(USE_WEBKIT_COMPOSITOR) |
236 web_layer_.setOpaque(fills_bounds_opaquely); | 236 web_layer_.setOpaque(fills_bounds_opaquely); |
237 #endif | 237 #endif |
238 } | 238 } |
239 | 239 |
240 void Layer::SetExternalTexture(ui::Texture* texture) { | 240 void Layer::SetExternalTexture(ui::Texture* texture) { |
241 DCHECK(texture); | 241 DCHECK(texture); |
242 layer_updated_externally_ = true; | 242 layer_updated_externally_ = true; |
243 texture_ = texture; | 243 texture_ = texture; |
244 } | 244 } |
(...skipping 29 matching lines...) Expand all Loading... | |
274 Compositor* compositor = GetCompositor(); | 274 Compositor* compositor = GetCompositor(); |
275 if (compositor) | 275 if (compositor) |
276 compositor->ScheduleDraw(); | 276 compositor->ScheduleDraw(); |
277 } | 277 } |
278 | 278 |
279 void Layer::Draw() { | 279 void Layer::Draw() { |
280 #if defined(USE_WEBKIT_COMPOSITOR) | 280 #if defined(USE_WEBKIT_COMPOSITOR) |
281 NOTREACHED(); | 281 NOTREACHED(); |
282 #else | 282 #else |
283 DCHECK(GetCompositor()); | 283 DCHECK(GetCompositor()); |
284 | |
285 if (recompute_hole_ && !parent_) | |
286 RecomputeHole(); | |
287 | |
284 if (!ShouldDraw()) | 288 if (!ShouldDraw()) |
285 return; | 289 return; |
286 | 290 |
287 UpdateLayerCanvas(); | 291 UpdateLayerCanvas(); |
288 | 292 |
289 // Layer drew nothing, no texture was created. | 293 // Layer drew nothing, no texture was created. |
290 if (!texture_.get()) | 294 if (!texture_.get()) |
291 return; | 295 return; |
292 | 296 |
293 ui::TextureDrawParams texture_draw_params; | 297 ui::TextureDrawParams texture_draw_params; |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
379 return; | 383 return; |
380 } | 384 } |
381 scoped_ptr<gfx::Canvas> canvas(gfx::Canvas::CreateCanvas( | 385 scoped_ptr<gfx::Canvas> canvas(gfx::Canvas::CreateCanvas( |
382 draw_rect.width(), draw_rect.height(), false)); | 386 draw_rect.width(), draw_rect.height(), false)); |
383 canvas->TranslateInt(-draw_rect.x(), -draw_rect.y()); | 387 canvas->TranslateInt(-draw_rect.x(), -draw_rect.y()); |
384 delegate_->OnPaintLayer(canvas.get()); | 388 delegate_->OnPaintLayer(canvas.get()); |
385 SetCanvas(*canvas->GetSkCanvas(), draw_rect.origin()); | 389 SetCanvas(*canvas->GetSkCanvas(), draw_rect.origin()); |
386 #endif | 390 #endif |
387 } | 391 } |
388 | 392 |
389 void Layer::RecomputeHole() { | 393 void Layer::SetNeedsToRecomputeHole() { |
390 if (type_ == LAYER_HAS_NO_TEXTURE) | 394 Layer* root_layer = this; |
395 while (root_layer->parent_) | |
396 root_layer = root_layer->parent_; | |
397 | |
398 root_layer->recompute_hole_ = true; | |
399 } | |
400 | |
401 void Layer::ClearHoleRects() { | |
402 hole_rect_ = gfx::Rect(); | |
403 | |
404 for (size_t i = 0; i < children_.size(); i++) | |
405 children_[i]->ClearHoleRects(); | |
406 } | |
407 | |
408 void Layer::GeneratePreorderTraversal( | |
409 std::vector<ui::Layer*>* layer_traversal) { | |
410 if (!visible_) | |
391 return; | 411 return; |
392 | 412 |
393 // Reset to default. | 413 if (fills_bounds_opaquely_ && type_ == LAYER_HAS_TEXTURE) |
394 hole_rect_ = gfx::Rect(); | 414 layer_traversal->push_back(this); |
395 | 415 |
396 // Find the largest hole | 416 for (size_t i = 0; i < children_.size(); i++) |
397 for (size_t i = 0; i < children_.size(); ++i) { | 417 children_[i]->GeneratePreorderTraversal(layer_traversal); |
398 // Ignore non-opaque and hidden children. | 418 } |
399 if (!children_[i]->IsCompletelyOpaque() || !children_[i]->visible_) | |
400 continue; | |
401 | 419 |
402 // Ignore children that aren't rotated by multiples of 90 degrees. | 420 void Layer::RecomputeHole() { |
403 float degrees; | 421 std::vector<ui::Layer*> layer_traversal; |
404 if (!InterpolatedTransform::FactorTRS(children_[i]->transform(), | 422 std::vector<ui::Transform> transforms_relative_to_root; |
405 NULL, °rees, NULL) || | 423 std::vector<float> opacities; |
406 !IsApproximateMultilpleOf(degrees, 90.0f)) | |
407 continue; | |
408 | 424 |
409 // The reason why we don't just take the bounds and apply the transform is | 425 ClearHoleRects(); |
410 // that the bounds encodes a position, too, so the effective transformation | 426 GeneratePreorderTraversal(&layer_traversal); |
411 // matrix is actually different that the one reported. As well, the bounds | |
412 // will not necessarily be at the origin. | |
413 gfx::Rect candidate_hole(children_[i]->bounds_.size()); | |
414 ui::Transform transform = children_[i]->transform(); | |
415 transform.ConcatTranslate(static_cast<float>(children_[i]->bounds_.x()), | |
416 static_cast<float>(children_[i]->bounds_.y())); | |
417 transform.TransformRect(&candidate_hole); | |
418 | 427 |
419 // This layer might not contain the child (e.g., a portion of the child may | 428 for (size_t i = 0; i < layer_traversal.size(); i++) { |
sky
2011/10/24 23:25:50
Seems a lot better to have GeneratePreorderTravers
| |
420 // be offscreen). Only the portion of the child that overlaps this layer is | 429 Layer* layer = layer_traversal[i]; |
421 // of any importance, so take the intersection. | 430 ui::Transform layer_transform; |
422 candidate_hole = gfx::Rect(bounds().size()).Intersect(candidate_hole); | 431 layer->GetTransformRelativeTo(this, &layer_transform); |
423 | 432 transforms_relative_to_root.push_back(layer_transform); |
424 // Ensure we have the largest hole. | 433 opacities.push_back(layer->GetCombinedOpacity()); |
425 if (candidate_hole.size().GetArea() > hole_rect_.size().GetArea()) | |
426 hole_rect_ = candidate_hole; | |
427 } | 434 } |
428 | 435 |
429 // Free up texture memory if the hole fills bounds of layer. | 436 for (size_t i = 0; i < layer_traversal.size(); i++) { |
430 if (!ShouldDraw() && !layer_updated_externally_) | 437 Layer* layer = layer_traversal[i]; |
431 texture_ = NULL; | 438 gfx::Rect bounds = gfx::Rect(layer->bounds().size()); |
439 | |
440 // Iterate through layers which are after layer_traversal[i] in draw order | |
441 // and find the largest candidate hole. | |
442 for (size_t j = i + 1; j < layer_traversal.size(); j++) { | |
443 gfx::Rect candidate_hole = gfx::Rect(layer_traversal[j]->bounds().size()); | |
444 | |
445 // Compute transform to go from bounds of layer |j| to local bounds of | |
446 // layer |i|. | |
447 ui::Transform candidate_hole_transform; | |
448 ui::Transform inverted; | |
449 | |
450 candidate_hole_transform.ConcatTransform(transforms_relative_to_root[j]); | |
451 | |
452 if (!transforms_relative_to_root[i].GetInverse(&inverted)) | |
453 continue; | |
454 | |
455 candidate_hole_transform.ConcatTransform(inverted); | |
456 | |
457 // cannot punch a hole if the relative transform between the two layers | |
458 // is not multiple of 90. | |
459 float degrees; | |
460 gfx::Point p; | |
461 if (!InterpolatedTransform::FactorTRS(candidate_hole_transform, &p, | |
462 °rees, NULL) || !IsApproximateMultilpleOf(degrees, 90.0f)) | |
463 continue; | |
464 | |
465 // can only punch a hole if the two layers have 1.0f opacity. | |
466 if (opacities[i] != 1.0f || opacities[j] != 1.0f) | |
sky
2011/10/24 23:25:50
This check is cheap. We should do it first.
| |
467 continue; | |
468 | |
469 candidate_hole_transform.TransformRect(&candidate_hole); | |
470 candidate_hole = candidate_hole.Intersect(bounds); | |
471 | |
472 if (candidate_hole.size().GetArea() > layer->hole_rect().size().GetArea()) | |
473 layer->set_hole_rect(candidate_hole); | |
474 } | |
475 // Free up texture memory if the hole fills bounds of layer. | |
476 if (!layer->ShouldDraw() && !layer_updated_externally()) | |
477 layer->DropTexture(); | |
432 | 478 |
433 #if defined(USE_WEBKIT_COMPOSITOR) | 479 #if defined(USE_WEBKIT_COMPOSITOR) |
434 RecomputeDrawsContent(); | 480 RecomputeDrawsContent(); |
sky
2011/10/24 23:25:50
Shouldn't this be outside the for loop?
| |
435 #endif | 481 #endif |
436 } | |
437 | 482 |
438 bool Layer::IsCompletelyOpaque() const { | 483 recompute_hole_ = false; |
sky
2011/10/24 23:25:50
Shouldn't this be outside the for loop?
| |
439 return fills_bounds_opaquely() && GetCombinedOpacity() == 1.0f; | 484 } |
440 } | 485 } |
441 | 486 |
442 // static | 487 // static |
443 void Layer::PunchHole(const gfx::Rect& rect, | 488 void Layer::PunchHole(const gfx::Rect& rect, |
444 const gfx::Rect& region_to_punch_out, | 489 const gfx::Rect& region_to_punch_out, |
445 std::vector<gfx::Rect>* sides) { | 490 std::vector<gfx::Rect>* sides) { |
446 gfx::Rect trimmed_rect = rect.Intersect(region_to_punch_out); | 491 gfx::Rect trimmed_rect = rect.Intersect(region_to_punch_out); |
447 | 492 |
448 if (trimmed_rect.IsEmpty()) { | 493 if (trimmed_rect.IsEmpty()) { |
449 sides->push_back(rect); | 494 sides->push_back(rect); |
(...skipping 18 matching lines...) Expand all Loading... | |
468 rect.right() - trimmed_rect.right(), | 513 rect.right() - trimmed_rect.right(), |
469 trimmed_rect.height())); | 514 trimmed_rect.height())); |
470 | 515 |
471 // Bottom (below the hole). | 516 // Bottom (below the hole). |
472 sides->push_back(gfx::Rect(rect.x(), | 517 sides->push_back(gfx::Rect(rect.x(), |
473 trimmed_rect.bottom(), | 518 trimmed_rect.bottom(), |
474 rect.width(), | 519 rect.width(), |
475 rect.bottom() - trimmed_rect.bottom())); | 520 rect.bottom() - trimmed_rect.bottom())); |
476 } | 521 } |
477 | 522 |
523 void Layer::DropTexture() { | |
524 if (!layer_updated_externally_) | |
525 texture_ = NULL; | |
526 } | |
527 | |
478 void Layer::DropTextures() { | 528 void Layer::DropTextures() { |
479 if (!layer_updated_externally_) | 529 if (!layer_updated_externally_) |
sky
2011/10/24 23:25:50
Change this to call DropTexture.
| |
480 texture_ = NULL; | 530 texture_ = NULL; |
481 for (size_t i = 0; i < children_.size(); ++i) | 531 for (size_t i = 0; i < children_.size(); ++i) |
482 children_[i]->DropTextures(); | 532 children_[i]->DropTextures(); |
483 } | 533 } |
484 | 534 |
485 bool Layer::ConvertPointForAncestor(const Layer* ancestor, | 535 bool Layer::ConvertPointForAncestor(const Layer* ancestor, |
486 gfx::Point* point) const { | 536 gfx::Point* point) const { |
487 ui::Transform transform; | 537 ui::Transform transform; |
488 bool result = GetTransformRelativeTo(ancestor, &transform); | 538 bool result = GetTransformRelativeTo(ancestor, &transform); |
489 gfx::Point3f p(*point); | 539 gfx::Point3f p(*point); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
533 if (property != LayerAnimationManager::TRANSFORM && | 583 if (property != LayerAnimationManager::TRANSFORM && |
534 animator_->IsAnimating(LayerAnimationManager::TRANSFORM)) { | 584 animator_->IsAnimating(LayerAnimationManager::TRANSFORM)) { |
535 SetTransformImmediately(animator_->GetTargetTransform()); | 585 SetTransformImmediately(animator_->GetTargetTransform()); |
536 } | 586 } |
537 animator_.reset(); | 587 animator_.reset(); |
538 } | 588 } |
539 | 589 |
540 void Layer::SetBoundsImmediately(const gfx::Rect& bounds) { | 590 void Layer::SetBoundsImmediately(const gfx::Rect& bounds) { |
541 bounds_ = bounds; | 591 bounds_ = bounds; |
542 | 592 |
543 if (parent()) | 593 SetNeedsToRecomputeHole(); |
544 parent()->RecomputeHole(); | |
545 #if defined(USE_WEBKIT_COMPOSITOR) | 594 #if defined(USE_WEBKIT_COMPOSITOR) |
546 web_layer_.setBounds(bounds.size()); | 595 web_layer_.setBounds(bounds.size()); |
547 RecomputeTransform(); | 596 RecomputeTransform(); |
548 RecomputeDrawsContent(); | 597 RecomputeDrawsContent(); |
549 #endif | 598 #endif |
550 } | 599 } |
551 | 600 |
552 void Layer::SetTransformImmediately(const ui::Transform& transform) { | 601 void Layer::SetTransformImmediately(const ui::Transform& transform) { |
553 transform_ = transform; | 602 transform_ = transform; |
554 | 603 |
555 if (parent()) | 604 SetNeedsToRecomputeHole(); |
556 parent()->RecomputeHole(); | |
557 #if defined(USE_WEBKIT_COMPOSITOR) | 605 #if defined(USE_WEBKIT_COMPOSITOR) |
558 RecomputeTransform(); | 606 RecomputeTransform(); |
559 #endif | 607 #endif |
560 } | 608 } |
561 | 609 |
562 void Layer::SetOpacityImmediately(float opacity) { | 610 void Layer::SetOpacityImmediately(float opacity) { |
563 bool was_opaque = GetCombinedOpacity() == 1.0f; | |
564 opacity_ = opacity; | 611 opacity_ = opacity; |
565 bool is_opaque = GetCombinedOpacity() == 1.0f; | 612 SetNeedsToRecomputeHole(); |
566 | |
567 // If our opacity has changed we need to recompute our hole, our parent's hole | |
568 // and the holes of all our descendants. | |
569 if (was_opaque != is_opaque) { | |
570 if (parent_) | |
571 parent_->RecomputeHole(); | |
572 std::queue<Layer*> to_process; | |
573 to_process.push(this); | |
574 while (!to_process.empty()) { | |
575 Layer* current = to_process.front(); | |
576 to_process.pop(); | |
577 current->RecomputeHole(); | |
578 for (size_t i = 0; i < current->children_.size(); ++i) | |
579 to_process.push(current->children_.at(i)); | |
580 } | |
581 } | |
582 #if defined(USE_WEBKIT_COMPOSITOR) | 613 #if defined(USE_WEBKIT_COMPOSITOR) |
583 if (visible_) | 614 if (visible_) |
584 web_layer_.setOpacity(opacity); | 615 web_layer_.setOpacity(opacity); |
585 RecomputeDrawsContent(); | 616 RecomputeDrawsContent(); |
586 #endif | 617 #endif |
587 } | 618 } |
588 | 619 |
589 void Layer::SetBoundsFromAnimator(const gfx::Rect& bounds) { | 620 void Layer::SetBoundsFromAnimator(const gfx::Rect& bounds) { |
590 SetBoundsImmediately(bounds); | 621 SetBoundsImmediately(bounds); |
591 } | 622 } |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
680 result.append(", color=red"); | 711 result.append(", color=red"); |
681 | 712 |
682 if (fills_bounds_opaquely()) | 713 if (fills_bounds_opaquely()) |
683 result.append(", style=filled"); | 714 result.append(", style=filled"); |
684 | 715 |
685 return result; | 716 return result; |
686 } | 717 } |
687 | 718 |
688 #endif | 719 #endif |
689 | 720 |
690 //////////////////////////////////////////////////////////////////////////////// | |
691 | |
692 } // namespace ui | 721 } // namespace ui |
OLD | NEW |