| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 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 "cc/resources/picture_layer_tiling.h" | 5 #include "cc/resources/picture_layer_tiling.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 #include <limits> | 9 #include <limits> |
| 10 #include <set> | 10 #include <set> |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 50 int skewport_extrapolation_limit_in_content_pixels) | 50 int skewport_extrapolation_limit_in_content_pixels) |
| 51 : max_tiles_for_interest_area_(max_tiles_for_interest_area), | 51 : max_tiles_for_interest_area_(max_tiles_for_interest_area), |
| 52 skewport_target_time_in_seconds_(skewport_target_time_in_seconds), | 52 skewport_target_time_in_seconds_(skewport_target_time_in_seconds), |
| 53 skewport_extrapolation_limit_in_content_pixels_( | 53 skewport_extrapolation_limit_in_content_pixels_( |
| 54 skewport_extrapolation_limit_in_content_pixels), | 54 skewport_extrapolation_limit_in_content_pixels), |
| 55 contents_scale_(contents_scale), | 55 contents_scale_(contents_scale), |
| 56 client_(client), | 56 client_(client), |
| 57 raster_source_(raster_source), | 57 raster_source_(raster_source), |
| 58 resolution_(NON_IDEAL_RESOLUTION), | 58 resolution_(NON_IDEAL_RESOLUTION), |
| 59 tiling_data_(gfx::Size(), gfx::Size(), kBorderTexels), | 59 tiling_data_(gfx::Size(), gfx::Size(), kBorderTexels), |
| 60 last_impl_frame_time_in_seconds_(0.0), | |
| 61 can_require_tiles_for_activation_(false), | 60 can_require_tiles_for_activation_(false), |
| 62 current_content_to_screen_scale_(0.f), | 61 current_content_to_screen_scale_(0.f), |
| 63 has_visible_rect_tiles_(false), | 62 has_visible_rect_tiles_(false), |
| 64 has_skewport_rect_tiles_(false), | 63 has_skewport_rect_tiles_(false), |
| 65 has_soon_border_rect_tiles_(false), | 64 has_soon_border_rect_tiles_(false), |
| 66 has_eventually_rect_tiles_(false) { | 65 has_eventually_rect_tiles_(false) { |
| 67 DCHECK(!raster_source->IsSolidColor()); | 66 DCHECK(!raster_source->IsSolidColor()); |
| 68 gfx::Size content_bounds = gfx::ToCeiledSize( | 67 gfx::Size content_bounds = gfx::ToCeiledSize( |
| 69 gfx::ScaleSize(raster_source_->GetSize(), contents_scale)); | 68 gfx::ScaleSize(raster_source_->GetSize(), contents_scale)); |
| 70 gfx::Size tile_size = client_->CalculateTileSize(content_bounds); | 69 gfx::Size tile_size = client_->CalculateTileSize(content_bounds); |
| (...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 523 if (recycled_twin) | 522 if (recycled_twin) |
| 524 recycled_twin->RemoveTileAt(it->first.first, it->first.second, nullptr); | 523 recycled_twin->RemoveTileAt(it->first.first, it->first.second, nullptr); |
| 525 } | 524 } |
| 526 tiles_.clear(); | 525 tiles_.clear(); |
| 527 } | 526 } |
| 528 | 527 |
| 529 gfx::Rect PictureLayerTiling::ComputeSkewport( | 528 gfx::Rect PictureLayerTiling::ComputeSkewport( |
| 530 double current_frame_time_in_seconds, | 529 double current_frame_time_in_seconds, |
| 531 const gfx::Rect& visible_rect_in_content_space) const { | 530 const gfx::Rect& visible_rect_in_content_space) const { |
| 532 gfx::Rect skewport = visible_rect_in_content_space; | 531 gfx::Rect skewport = visible_rect_in_content_space; |
| 533 if (last_impl_frame_time_in_seconds_ == 0.0) | 532 if (skewport.IsEmpty()) |
| 534 return skewport; | 533 return skewport; |
| 535 | 534 |
| 536 double time_delta = | 535 if (visible_rect_history_[1].frame_time_in_seconds == 0.0) |
| 537 current_frame_time_in_seconds - last_impl_frame_time_in_seconds_; | 536 return skewport; |
| 537 |
| 538 double time_delta = current_frame_time_in_seconds - |
| 539 visible_rect_history_[1].frame_time_in_seconds; |
| 538 if (time_delta == 0.0) | 540 if (time_delta == 0.0) |
| 539 return skewport; | 541 return skewport; |
| 540 | 542 |
| 541 double extrapolation_multiplier = | 543 double extrapolation_multiplier = |
| 542 skewport_target_time_in_seconds_ / time_delta; | 544 skewport_target_time_in_seconds_ / time_delta; |
| 543 | 545 |
| 544 int old_x = last_visible_rect_in_content_space_.x(); | 546 int old_x = visible_rect_history_[1].visible_rect_in_content_space.x(); |
| 545 int old_y = last_visible_rect_in_content_space_.y(); | 547 int old_y = visible_rect_history_[1].visible_rect_in_content_space.y(); |
| 546 int old_right = last_visible_rect_in_content_space_.right(); | 548 int old_right = |
| 547 int old_bottom = last_visible_rect_in_content_space_.bottom(); | 549 visible_rect_history_[1].visible_rect_in_content_space.right(); |
| 550 int old_bottom = |
| 551 visible_rect_history_[1].visible_rect_in_content_space.bottom(); |
| 548 | 552 |
| 549 int new_x = visible_rect_in_content_space.x(); | 553 int new_x = visible_rect_in_content_space.x(); |
| 550 int new_y = visible_rect_in_content_space.y(); | 554 int new_y = visible_rect_in_content_space.y(); |
| 551 int new_right = visible_rect_in_content_space.right(); | 555 int new_right = visible_rect_in_content_space.right(); |
| 552 int new_bottom = visible_rect_in_content_space.bottom(); | 556 int new_bottom = visible_rect_in_content_space.bottom(); |
| 553 | 557 |
| 554 // Compute the maximum skewport based on | 558 // Compute the maximum skewport based on |
| 555 // |skewport_extrapolation_limit_in_content_pixels_|. | 559 // |skewport_extrapolation_limit_in_content_pixels_|. |
| 556 gfx::Rect max_skewport = skewport; | 560 gfx::Rect max_skewport = skewport; |
| 557 max_skewport.Inset(-skewport_extrapolation_limit_in_content_pixels_, | 561 max_skewport.Inset(-skewport_extrapolation_limit_in_content_pixels_, |
| 558 -skewport_extrapolation_limit_in_content_pixels_); | 562 -skewport_extrapolation_limit_in_content_pixels_); |
| 559 | 563 |
| 560 // Inset the skewport by the needed adjustment. | 564 // Inset the skewport by the needed adjustment. |
| 561 skewport.Inset(extrapolation_multiplier * (new_x - old_x), | 565 skewport.Inset(extrapolation_multiplier * (new_x - old_x), |
| 562 extrapolation_multiplier * (new_y - old_y), | 566 extrapolation_multiplier * (new_y - old_y), |
| 563 extrapolation_multiplier * (old_right - new_right), | 567 extrapolation_multiplier * (old_right - new_right), |
| 564 extrapolation_multiplier * (old_bottom - new_bottom)); | 568 extrapolation_multiplier * (old_bottom - new_bottom)); |
| 565 | 569 |
| 566 // Clip the skewport to |max_skewport|. | 570 // Ensure that visible rect is contained in the skewport. |
| 571 skewport.Union(visible_rect_in_content_space); |
| 572 |
| 573 // Clip the skewport to |max_skewport|. This needs to happen after the |
| 574 // union in case intersecting would have left the empty rect. |
| 567 skewport.Intersect(max_skewport); | 575 skewport.Intersect(max_skewport); |
| 568 | 576 |
| 569 // Finally, ensure that visible rect is contained in the skewport. | |
| 570 skewport.Union(visible_rect_in_content_space); | |
| 571 return skewport; | 577 return skewport; |
| 572 } | 578 } |
| 573 | 579 |
| 574 bool PictureLayerTiling::ComputeTilePriorityRects( | 580 bool PictureLayerTiling::ComputeTilePriorityRects( |
| 575 const gfx::Rect& viewport_in_layer_space, | 581 const gfx::Rect& viewport_in_layer_space, |
| 576 float ideal_contents_scale, | 582 float ideal_contents_scale, |
| 577 double current_frame_time_in_seconds, | 583 double current_frame_time_in_seconds, |
| 578 const Occlusion& occlusion_in_layer_space) { | 584 const Occlusion& occlusion_in_layer_space) { |
| 579 if (!NeedsUpdateForFrameAtTimeAndViewport(current_frame_time_in_seconds, | 585 if (!NeedsUpdateForFrameAtTimeAndViewport(current_frame_time_in_seconds, |
| 580 viewport_in_layer_space)) { | 586 viewport_in_layer_space)) { |
| 581 // This should never be zero for the purposes of has_ever_been_updated(). | 587 // This should never be zero for the purposes of has_ever_been_updated(). |
| 582 DCHECK_NE(current_frame_time_in_seconds, 0.0); | 588 DCHECK_NE(current_frame_time_in_seconds, 0.0); |
| 583 return false; | 589 return false; |
| 584 } | 590 } |
| 585 | 591 |
| 586 gfx::Rect visible_rect_in_content_space = | 592 gfx::Rect visible_rect_in_content_space = |
| 587 gfx::ScaleToEnclosingRect(viewport_in_layer_space, contents_scale_); | 593 gfx::ScaleToEnclosingRect(viewport_in_layer_space, contents_scale_); |
| 588 | 594 |
| 589 if (tiling_size().IsEmpty()) { | 595 if (tiling_size().IsEmpty()) { |
| 590 last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds; | 596 UpdateVisibleRectHistory(current_frame_time_in_seconds, |
| 597 visible_rect_in_content_space); |
| 591 last_viewport_in_layer_space_ = viewport_in_layer_space; | 598 last_viewport_in_layer_space_ = viewport_in_layer_space; |
| 592 last_visible_rect_in_content_space_ = visible_rect_in_content_space; | |
| 593 return false; | 599 return false; |
| 594 } | 600 } |
| 595 | 601 |
| 596 // Calculate the skewport. | 602 // Calculate the skewport. |
| 597 gfx::Rect skewport = ComputeSkewport(current_frame_time_in_seconds, | 603 gfx::Rect skewport = ComputeSkewport(current_frame_time_in_seconds, |
| 598 visible_rect_in_content_space); | 604 visible_rect_in_content_space); |
| 599 DCHECK(skewport.Contains(visible_rect_in_content_space)); | 605 DCHECK(skewport.Contains(visible_rect_in_content_space)); |
| 600 | 606 |
| 601 // Calculate the eventually/live tiles rect. | 607 // Calculate the eventually/live tiles rect. |
| 602 gfx::Size tile_size = tiling_data_.max_texture_size(); | 608 gfx::Size tile_size = tiling_data_.max_texture_size(); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 614 << "tiling_size: " << tiling_size().ToString() | 620 << "tiling_size: " << tiling_size().ToString() |
| 615 << " eventually_rect: " << eventually_rect.ToString(); | 621 << " eventually_rect: " << eventually_rect.ToString(); |
| 616 | 622 |
| 617 // Calculate the soon border rect. | 623 // Calculate the soon border rect. |
| 618 float content_to_screen_scale = ideal_contents_scale / contents_scale_; | 624 float content_to_screen_scale = ideal_contents_scale / contents_scale_; |
| 619 gfx::Rect soon_border_rect = visible_rect_in_content_space; | 625 gfx::Rect soon_border_rect = visible_rect_in_content_space; |
| 620 float border = CalculateSoonBorderDistance(visible_rect_in_content_space, | 626 float border = CalculateSoonBorderDistance(visible_rect_in_content_space, |
| 621 content_to_screen_scale); | 627 content_to_screen_scale); |
| 622 soon_border_rect.Inset(-border, -border, -border, -border); | 628 soon_border_rect.Inset(-border, -border, -border, -border); |
| 623 | 629 |
| 624 last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds; | 630 UpdateVisibleRectHistory(current_frame_time_in_seconds, |
| 631 visible_rect_in_content_space); |
| 625 last_viewport_in_layer_space_ = viewport_in_layer_space; | 632 last_viewport_in_layer_space_ = viewport_in_layer_space; |
| 626 last_visible_rect_in_content_space_ = visible_rect_in_content_space; | |
| 627 | 633 |
| 628 SetLiveTilesRect(eventually_rect); | 634 SetLiveTilesRect(eventually_rect); |
| 629 UpdateTilePriorityRects( | 635 UpdateTilePriorityRects( |
| 630 content_to_screen_scale, visible_rect_in_content_space, skewport, | 636 content_to_screen_scale, visible_rect_in_content_space, skewport, |
| 631 soon_border_rect, eventually_rect, occlusion_in_layer_space); | 637 soon_border_rect, eventually_rect, occlusion_in_layer_space); |
| 632 return true; | 638 return true; |
| 633 } | 639 } |
| 634 | 640 |
| 635 void PictureLayerTiling::UpdateTilePriorityRects( | 641 void PictureLayerTiling::UpdateTilePriorityRects( |
| 636 float content_to_screen_scale, | 642 float content_to_screen_scale, |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 799 if (IsTileOccluded(tile)) | 805 if (IsTileOccluded(tile)) |
| 800 return false; | 806 return false; |
| 801 | 807 |
| 802 return true; | 808 return true; |
| 803 } | 809 } |
| 804 | 810 |
| 805 void PictureLayerTiling::UpdateTileAndTwinPriority(Tile* tile) const { | 811 void PictureLayerTiling::UpdateTileAndTwinPriority(Tile* tile) const { |
| 806 WhichTree tree = client_->GetTree(); | 812 WhichTree tree = client_->GetTree(); |
| 807 WhichTree twin_tree = tree == ACTIVE_TREE ? PENDING_TREE : ACTIVE_TREE; | 813 WhichTree twin_tree = tree == ACTIVE_TREE ? PENDING_TREE : ACTIVE_TREE; |
| 808 | 814 |
| 809 UpdateTilePriorityForTree(tile, tree); | 815 tile->SetPriority(tree, ComputePriorityForTile(tile)); |
| 816 UpdateRequiredStateForTile(tile, tree); |
| 810 | 817 |
| 811 const PictureLayerTiling* twin_tiling = | 818 const PictureLayerTiling* twin_tiling = |
| 812 client_->GetPendingOrActiveTwinTiling(this); | 819 client_->GetPendingOrActiveTwinTiling(this); |
| 813 if (!tile->is_shared() || !twin_tiling) { | 820 if (!tile->is_shared() || !twin_tiling) { |
| 814 tile->SetPriority(twin_tree, TilePriority()); | 821 tile->SetPriority(twin_tree, TilePriority()); |
| 815 tile->set_is_occluded(twin_tree, false); | 822 tile->set_is_occluded(twin_tree, false); |
| 816 if (twin_tree == PENDING_TREE) | 823 if (twin_tree == PENDING_TREE) |
| 817 tile->set_required_for_activation(false); | 824 tile->set_required_for_activation(false); |
| 818 else | 825 else |
| 819 tile->set_required_for_draw(false); | 826 tile->set_required_for_draw(false); |
| 820 return; | 827 return; |
| 821 } | 828 } |
| 822 | 829 |
| 823 twin_tiling->UpdateTilePriorityForTree(tile, twin_tree); | 830 tile->SetPriority(twin_tree, twin_tiling->ComputePriorityForTile(tile)); |
| 831 twin_tiling->UpdateRequiredStateForTile(tile, twin_tree); |
| 824 } | 832 } |
| 825 | 833 |
| 826 void PictureLayerTiling::UpdateTilePriorityForTree(Tile* tile, | 834 void PictureLayerTiling::UpdateRequiredStateForTile(Tile* tile, |
| 827 WhichTree tree) const { | 835 WhichTree tree) const { |
| 828 // TODO(vmpstr): This code should return the priority instead of setting it on | 836 if (tile->priority(tree).priority_bin == TilePriority::NOW) { |
| 829 // the tile. This should be a part of the change to move tile priority from | |
| 830 // tiles into iterators. | |
| 831 TilePriority::PriorityBin max_tile_priority_bin = | |
| 832 client_->GetMaxTilePriorityBin(); | |
| 833 | |
| 834 DCHECK_EQ(TileAt(tile->tiling_i_index(), tile->tiling_j_index()), tile); | |
| 835 gfx::Rect tile_bounds = | |
| 836 tiling_data_.TileBounds(tile->tiling_i_index(), tile->tiling_j_index()); | |
| 837 | |
| 838 if (max_tile_priority_bin <= TilePriority::NOW && | |
| 839 current_visible_rect_.Intersects(tile_bounds)) { | |
| 840 tile->SetPriority(tree, TilePriority(resolution_, TilePriority::NOW, 0)); | |
| 841 if (tree == PENDING_TREE) { | 837 if (tree == PENDING_TREE) { |
| 842 tile->set_required_for_activation( | 838 tile->set_required_for_activation( |
| 843 IsTileRequiredForActivationIfVisible(tile)); | 839 IsTileRequiredForActivationIfVisible(tile)); |
| 844 } else { | 840 } else { |
| 845 tile->set_required_for_draw(IsTileRequiredForDrawIfVisible(tile)); | 841 tile->set_required_for_draw(IsTileRequiredForDrawIfVisible(tile)); |
| 846 } | 842 } |
| 847 tile->set_is_occluded(tree, IsTileOccluded(tile)); | 843 tile->set_is_occluded(tree, IsTileOccluded(tile)); |
| 848 return; | 844 return; |
| 849 } | 845 } |
| 850 | 846 |
| 847 // Non-NOW bin tiles are not required or occluded. |
| 851 if (tree == PENDING_TREE) | 848 if (tree == PENDING_TREE) |
| 852 tile->set_required_for_activation(false); | 849 tile->set_required_for_activation(false); |
| 853 else | 850 else |
| 854 tile->set_required_for_draw(false); | 851 tile->set_required_for_draw(false); |
| 855 tile->set_is_occluded(tree, false); | 852 tile->set_is_occluded(tree, false); |
| 853 } |
| 854 |
| 855 TilePriority PictureLayerTiling::ComputePriorityForTile( |
| 856 const Tile* tile) const { |
| 857 // TODO(vmpstr): See if this can be moved to iterators. |
| 858 TilePriority::PriorityBin max_tile_priority_bin = |
| 859 client_->GetMaxTilePriorityBin(); |
| 860 |
| 861 DCHECK_EQ(TileAt(tile->tiling_i_index(), tile->tiling_j_index()), tile); |
| 862 gfx::Rect tile_bounds = |
| 863 tiling_data_.TileBounds(tile->tiling_i_index(), tile->tiling_j_index()); |
| 864 |
| 865 if (max_tile_priority_bin <= TilePriority::NOW && |
| 866 current_visible_rect_.Intersects(tile_bounds)) { |
| 867 return TilePriority(resolution_, TilePriority::NOW, 0); |
| 868 } |
| 856 | 869 |
| 857 DCHECK_GT(current_content_to_screen_scale_, 0.f); | 870 DCHECK_GT(current_content_to_screen_scale_, 0.f); |
| 858 float distance_to_visible = | 871 float distance_to_visible = |
| 859 current_visible_rect_.ManhattanInternalDistance(tile_bounds) * | 872 current_visible_rect_.ManhattanInternalDistance(tile_bounds) * |
| 860 current_content_to_screen_scale_; | 873 current_content_to_screen_scale_; |
| 861 | 874 |
| 862 if (max_tile_priority_bin <= TilePriority::SOON && | 875 if (max_tile_priority_bin <= TilePriority::SOON && |
| 863 (current_soon_border_rect_.Intersects(tile_bounds) || | 876 (current_soon_border_rect_.Intersects(tile_bounds) || |
| 864 current_skewport_rect_.Intersects(tile_bounds))) { | 877 current_skewport_rect_.Intersects(tile_bounds))) { |
| 865 tile->SetPriority( | 878 return TilePriority(resolution_, TilePriority::SOON, distance_to_visible); |
| 866 tree, | |
| 867 TilePriority(resolution_, TilePriority::SOON, distance_to_visible)); | |
| 868 return; | |
| 869 } | 879 } |
| 870 | 880 |
| 871 tile->SetPriority( | 881 return TilePriority(resolution_, TilePriority::EVENTUALLY, |
| 872 tree, | 882 distance_to_visible); |
| 873 TilePriority(resolution_, TilePriority::EVENTUALLY, distance_to_visible)); | |
| 874 } | 883 } |
| 875 | 884 |
| 876 void PictureLayerTiling::GetAllTilesForTracing( | 885 void PictureLayerTiling::GetAllTilesAndPrioritiesForTracing( |
| 877 std::set<const Tile*>* tiles) const { | 886 std::map<const Tile*, TilePriority>* tile_map) const { |
| 878 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) | 887 const PictureLayerTiling* twin_tiling = |
| 879 tiles->insert(it->second.get()); | 888 client_->GetPendingOrActiveTwinTiling(this); |
| 889 for (const auto& tile_pair : tiles_) { |
| 890 const Tile* tile = tile_pair.second.get(); |
| 891 const TilePriority& priority = ComputePriorityForTile(tile); |
| 892 const TilePriority& twin_priority = |
| 893 twin_tiling ? twin_tiling->ComputePriorityForTile(tile) |
| 894 : TilePriority(); |
| 895 |
| 896 // Store combined priority. |
| 897 (*tile_map)[tile] = TilePriority(priority, twin_priority); |
| 898 } |
| 880 } | 899 } |
| 881 | 900 |
| 882 void PictureLayerTiling::AsValueInto( | 901 void PictureLayerTiling::AsValueInto( |
| 883 base::trace_event::TracedValue* state) const { | 902 base::trace_event::TracedValue* state) const { |
| 884 state->SetInteger("num_tiles", tiles_.size()); | 903 state->SetInteger("num_tiles", tiles_.size()); |
| 885 state->SetDouble("content_scale", contents_scale_); | 904 state->SetDouble("content_scale", contents_scale_); |
| 905 MathUtil::AddToTracedValue("visible_rect", current_visible_rect_, state); |
| 906 MathUtil::AddToTracedValue("skewport_rect", current_skewport_rect_, state); |
| 907 MathUtil::AddToTracedValue("soon_rect", current_soon_border_rect_, state); |
| 908 MathUtil::AddToTracedValue("eventually_rect", current_eventually_rect_, |
| 909 state); |
| 886 MathUtil::AddToTracedValue("tiling_size", tiling_size(), state); | 910 MathUtil::AddToTracedValue("tiling_size", tiling_size(), state); |
| 887 } | 911 } |
| 888 | 912 |
| 889 size_t PictureLayerTiling::GPUMemoryUsageInBytes() const { | 913 size_t PictureLayerTiling::GPUMemoryUsageInBytes() const { |
| 890 size_t amount = 0; | 914 size_t amount = 0; |
| 891 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) { | 915 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) { |
| 892 const Tile* tile = it->second.get(); | 916 const Tile* tile = it->second.get(); |
| 893 amount += tile->GPUMemoryUsageInBytes(); | 917 amount += tile->GPUMemoryUsageInBytes(); |
| 894 } | 918 } |
| 895 return amount; | 919 return amount; |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1040 break; | 1064 break; |
| 1041 } | 1065 } |
| 1042 | 1066 |
| 1043 gfx::Rect result(origin_x, origin_y, width, height); | 1067 gfx::Rect result(origin_x, origin_y, width, height); |
| 1044 if (cache) | 1068 if (cache) |
| 1045 cache->previous_result = result; | 1069 cache->previous_result = result; |
| 1046 return result; | 1070 return result; |
| 1047 } | 1071 } |
| 1048 | 1072 |
| 1049 } // namespace cc | 1073 } // namespace cc |
| OLD | NEW |