Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(253)

Side by Side Diff: cc/tiles/picture_layer_tiling.cc

Issue 2816943004: cc: Fix bugs found by fuzzer due to floating point imprecision. (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | cc/tiles/picture_layer_tiling_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/tiles/picture_layer_tiling.h" 5 #include "cc/tiles/picture_layer_tiling.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 #include <cmath> 10 #include <cmath>
(...skipping 12 matching lines...) Expand all
23 #include "cc/tiles/tile.h" 23 #include "cc/tiles/tile.h"
24 #include "cc/tiles/tile_priority.h" 24 #include "cc/tiles/tile_priority.h"
25 #include "ui/gfx/geometry/point_conversions.h" 25 #include "ui/gfx/geometry/point_conversions.h"
26 #include "ui/gfx/geometry/rect_conversions.h" 26 #include "ui/gfx/geometry/rect_conversions.h"
27 #include "ui/gfx/geometry/rect_f.h" 27 #include "ui/gfx/geometry/rect_f.h"
28 #include "ui/gfx/geometry/safe_integer_conversions.h" 28 #include "ui/gfx/geometry/safe_integer_conversions.h"
29 #include "ui/gfx/geometry/size_conversions.h" 29 #include "ui/gfx/geometry/size_conversions.h"
30 30
31 namespace cc { 31 namespace cc {
32 32
33 namespace {
34 float SnapToOne(float n) {
35 return (std::abs(1.f - n) < std::numeric_limits<float>::epsilon()) ? 1.f : n;
36 }
trchen 2017/04/14 22:07:33 I doubt this function works as intended... By def
vmpstr 2017/04/14 23:36:26 The definition of epsilon is the difference betwee
trchen 2017/04/14 23:53:43 You're right. I forgot (1-epsilon) contains only 2
vmpstr 2017/04/15 00:31:24 It just happens that when coverage scale is 7352.3
trchen 2017/04/18 21:13:46 Does this helps with the bug you're fixing? I seem
37 }
38
33 PictureLayerTiling::PictureLayerTiling( 39 PictureLayerTiling::PictureLayerTiling(
34 WhichTree tree, 40 WhichTree tree,
35 const gfx::AxisTransform2d& raster_transform, 41 const gfx::AxisTransform2d& raster_transform,
36 scoped_refptr<RasterSource> raster_source, 42 scoped_refptr<RasterSource> raster_source,
37 PictureLayerTilingClient* client, 43 PictureLayerTilingClient* client,
38 float min_preraster_distance, 44 float min_preraster_distance,
39 float max_preraster_distance) 45 float max_preraster_distance)
40 : raster_transform_(raster_transform), 46 : raster_transform_(raster_transform),
41 client_(client), 47 client_(client),
42 tree_(tree), 48 tree_(tree),
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after
373 } 379 }
374 380
375 PictureLayerTiling::CoverageIterator::CoverageIterator() = default; 381 PictureLayerTiling::CoverageIterator::CoverageIterator() = default;
376 382
377 PictureLayerTiling::CoverageIterator::CoverageIterator( 383 PictureLayerTiling::CoverageIterator::CoverageIterator(
378 const PictureLayerTiling* tiling, 384 const PictureLayerTiling* tiling,
379 float coverage_scale, 385 float coverage_scale,
380 const gfx::Rect& coverage_rect) 386 const gfx::Rect& coverage_rect)
381 : tiling_(tiling), 387 : tiling_(tiling),
382 coverage_rect_(coverage_rect), 388 coverage_rect_(coverage_rect),
389 // Note that since this iterator will map possibly large numbers, it's
390 // very sensitive to small differences in scale (even less than epsilon).
391 // It is also very likely that this coverage iterator would be used with a
392 // scale that matches the contents scale (since majority of the time,
393 // we're rasterizing high res content. As a result, snap the scale to one
394 // if it's within the epsilon.
383 coverage_to_content_( 395 coverage_to_content_(
384 gfx::PreScaleAxisTransform2d(tiling->raster_transform(), 396 SnapToOne(tiling->raster_transform().scale() / coverage_scale),
385 1.f / coverage_scale)) { 397 tiling->raster_transform().translation()) {
386 DCHECK(tiling_); 398 DCHECK(tiling_);
387 // In order to avoid artifacts in geometry_rect scaling and clamping to ints, 399 // In order to avoid artifacts in geometry_rect scaling and clamping to ints,
388 // the |coverage_scale| should always be at least as big as the tiling's 400 // the |coverage_scale| should always be at least as big as the tiling's
389 // raster scales. 401 // raster scales.
390 DCHECK_GE(coverage_scale, tiling_->raster_transform_.scale()); 402 DCHECK_GE(coverage_scale, tiling_->raster_transform_.scale());
391 403
392 // Clamp |coverage_rect| to the bounds of this tiling's raster source. 404 // Clamp |coverage_rect| to the bounds of this tiling's raster source.
393 coverage_rect_max_bounds_ = 405 coverage_rect_max_bounds_ =
394 gfx::ScaleToCeiledSize(tiling->raster_source_->GetSize(), coverage_scale); 406 gfx::ScaleToCeiledSize(tiling->raster_source_->GetSize(), coverage_scale);
395 coverage_rect_.Intersect(gfx::Rect(coverage_rect_max_bounds_)); 407 coverage_rect_.Intersect(gfx::Rect(coverage_rect_max_bounds_));
(...skipping 17 matching lines...) Expand all
413 // Or in integer index: 425 // Or in integer index:
414 // wanted_texels(integer index) = (l:99, t:189, r:280, b:371) 426 // wanted_texels(integer index) = (l:99, t:189, r:280, b:371)
415 gfx::RectF content_rect = 427 gfx::RectF content_rect =
416 coverage_to_content_.MapRect(gfx::RectF(coverage_rect_)); 428 coverage_to_content_.MapRect(gfx::RectF(coverage_rect_));
417 content_rect.Offset(-0.5f, -0.5f); 429 content_rect.Offset(-0.5f, -0.5f);
418 gfx::Rect wanted_texels = gfx::ToEnclosingRect(content_rect); 430 gfx::Rect wanted_texels = gfx::ToEnclosingRect(content_rect);
419 431
420 const TilingData& data = tiling_->tiling_data_; 432 const TilingData& data = tiling_->tiling_data_;
421 left_ = data.LastBorderTileXIndexFromSrcCoord(wanted_texels.x()); 433 left_ = data.LastBorderTileXIndexFromSrcCoord(wanted_texels.x());
422 top_ = data.LastBorderTileYIndexFromSrcCoord(wanted_texels.y()); 434 top_ = data.LastBorderTileYIndexFromSrcCoord(wanted_texels.y());
435
423 right_ = std::max( 436 right_ = std::max(
424 left_, data.FirstBorderTileXIndexFromSrcCoord(wanted_texels.right())); 437 left_, data.FirstBorderTileXIndexFromSrcCoord(wanted_texels.right()));
425 bottom_ = std::max( 438 bottom_ = std::max(
426 top_, data.FirstBorderTileYIndexFromSrcCoord(wanted_texels.bottom())); 439 top_, data.FirstBorderTileYIndexFromSrcCoord(wanted_texels.bottom()));
427 440
441 // Unfortunately due to floating point math in ToEnclosingRect, wanted_texels
442 // could be lying about its dimensions. For example, consider the following:
443 //
444 // float a = 192.f;
445 // float b = 2104670720.f;
446 // output("%.0f\n", static_cast<double>(a + b) - b);
447 //
448 // This code prints out 256. So if that happens to be our coverage rect
449 // position and dimension, then the texel extent would try to grab something
450 // outside of it, resulting in a DCHECK later (or empty geometry rect with
451 // DCHECks disabled), which is undesirable. The solution is to simply
452 // backtrack the value until the content rect actually intersects the texel
453 // extent for the values we generated. Note this only happens with
454 // right/bottom values.
455 while (!content_rect.Intersects(data.TexelExtent(right_, top_)) &&
enne (OOO) 2017/04/14 05:35:56 Hmmm, do you think that FirstBorderTileXIndexFromS
vmpstr 2017/04/14 18:17:42 The problem is that FirstBorderTileXIndexFromSrcCo
trchen 2017/04/14 22:07:33 Just double checked FirstBorderTileXIndexFromSrcCo
vmpstr 2017/04/14 23:36:26 Yes, I meant the access to right/bottom in enclosi
trchen 2017/04/18 21:13:46 Just sync'd up with enne@ offline. We agreed that
456 right_ > left_) {
457 --right_;
458 }
459 while (!content_rect.Intersects(data.TexelExtent(left_, bottom_)) &&
460 bottom_ > top_) {
461 --bottom_;
462 }
463
428 tile_i_ = left_ - 1; 464 tile_i_ = left_ - 1;
429 tile_j_ = top_; 465 tile_j_ = top_;
430 ++(*this); 466 ++(*this);
431 } 467 }
432 468
433 PictureLayerTiling::CoverageIterator::~CoverageIterator() { 469 PictureLayerTiling::CoverageIterator::~CoverageIterator() {
434 } 470 }
435 471
436 PictureLayerTiling::CoverageIterator& 472 PictureLayerTiling::CoverageIterator&
437 PictureLayerTiling::CoverageIterator::operator++() { 473 PictureLayerTiling::CoverageIterator::operator++() {
438 if (tile_j_ > bottom_) 474 if (tile_j_ > bottom_)
439 return *this; 475 return *this;
440 476
441 bool first_time = tile_i_ < left_; 477 bool first_time = tile_i_ < left_;
442 bool new_row = false; 478 bool new_row = false;
443 tile_i_++; 479 tile_i_++;
444 if (tile_i_ > right_) { 480 if (tile_i_ > right_) {
445 tile_i_ = left_; 481 tile_i_ = left_;
446 tile_j_++; 482 tile_j_++;
447 new_row = true; 483 new_row = true;
448 if (tile_j_ > bottom_) { 484 if (tile_j_ > bottom_) {
449 current_tile_ = NULL; 485 current_tile_ = NULL;
450 return *this; 486 return *this;
451 } 487 }
452 } 488 }
453 489
490 DCHECK_LT(tile_i_, tiling_->tiling_data_.num_tiles_x());
491 DCHECK_LT(tile_j_, tiling_->tiling_data_.num_tiles_y());
454 current_tile_ = tiling_->TileAt(tile_i_, tile_j_); 492 current_tile_ = tiling_->TileAt(tile_i_, tile_j_);
455 493
456 // Calculate the current geometry rect. As we reserved overlap between tiles 494 // Calculate the current geometry rect. As we reserved overlap between tiles
457 // to accommodate bilinear filtering and rounding errors in destination 495 // to accommodate bilinear filtering and rounding errors in destination
458 // space, the geometry rect might overlap on the edges. 496 // space, the geometry rect might overlap on the edges.
459 gfx::Rect last_geometry_rect = current_geometry_rect_; 497 gfx::Rect last_geometry_rect = current_geometry_rect_;
460 498
461 gfx::RectF texel_extent = tiling_->tiling_data_.TexelExtent(tile_i_, tile_j_); 499 gfx::RectF texel_extent = tiling_->tiling_data_.TexelExtent(tile_i_, tile_j_);
462 { 500 {
463 // Adjust tile extent to accommodate numerical errors. 501 // Adjust tile extent to accommodate numerical errors.
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
514 min_top = last_geometry_rect.bottom(); 552 min_top = last_geometry_rect.bottom();
515 } else { 553 } else {
516 min_left = last_geometry_rect.right(); 554 min_left = last_geometry_rect.right();
517 min_top = last_geometry_rect.y(); 555 min_top = last_geometry_rect.y();
518 } 556 }
519 557
520 int inset_left = std::max(0, min_left - current_geometry_rect_.x()); 558 int inset_left = std::max(0, min_left - current_geometry_rect_.x());
521 int inset_top = std::max(0, min_top - current_geometry_rect_.y()); 559 int inset_top = std::max(0, min_top - current_geometry_rect_.y());
522 current_geometry_rect_.Inset(inset_left, inset_top, 0, 0); 560 current_geometry_rect_.Inset(inset_left, inset_top, 0, 0);
523 561
562 #if DCHECK_IS_ON()
enne (OOO) 2017/04/14 05:35:56 Do you need these extra #ifs?
vmpstr 2017/04/14 18:17:42 Not really, it's just everything is DCHECK in ther
524 if (!new_row) { 563 if (!new_row) {
525 DCHECK_EQ(last_geometry_rect.right(), current_geometry_rect_.x()); 564 DCHECK_EQ(last_geometry_rect.right(), current_geometry_rect_.x());
526 DCHECK_EQ(last_geometry_rect.bottom(), current_geometry_rect_.bottom()); 565 DCHECK_EQ(last_geometry_rect.bottom(), current_geometry_rect_.bottom());
527 DCHECK_EQ(last_geometry_rect.y(), current_geometry_rect_.y()); 566 DCHECK_EQ(last_geometry_rect.y(), current_geometry_rect_.y());
528 } 567 }
568 #endif
529 569
530 return *this; 570 return *this;
531 } 571 }
532 572
533 gfx::Rect PictureLayerTiling::CoverageIterator::geometry_rect() const { 573 gfx::Rect PictureLayerTiling::CoverageIterator::geometry_rect() const {
534 return current_geometry_rect_; 574 return current_geometry_rect_;
535 } 575 }
536 576
537 gfx::RectF PictureLayerTiling::CoverageIterator::texture_rect() const { 577 gfx::RectF PictureLayerTiling::CoverageIterator::texture_rect() const {
538 auto tex_origin = gfx::PointF( 578 auto tex_origin = gfx::PointF(
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
577 float ideal_contents_scale, 617 float ideal_contents_scale,
578 const Occlusion& occlusion_in_layer_space) { 618 const Occlusion& occlusion_in_layer_space) {
579 // If we have, or had occlusions, mark the tiles as 'not done' to ensure that 619 // If we have, or had occlusions, mark the tiles as 'not done' to ensure that
580 // we reiterate the tiles for rasterization. 620 // we reiterate the tiles for rasterization.
581 if (occlusion_in_layer_space.HasOcclusion() || 621 if (occlusion_in_layer_space.HasOcclusion() ||
582 current_occlusion_in_layer_space_.HasOcclusion()) { 622 current_occlusion_in_layer_space_.HasOcclusion()) {
583 set_all_tiles_done(false); 623 set_all_tiles_done(false);
584 } 624 }
585 625
586 const float content_to_screen_scale = 626 const float content_to_screen_scale =
587 ideal_contents_scale / raster_transform_.scale(); 627 SnapToOne(ideal_contents_scale / raster_transform_.scale());
588 628
589 const gfx::Rect* input_rects[] = { 629 const gfx::Rect* input_rects[] = {
590 &visible_rect_in_layer_space, &skewport_in_layer_space, 630 &visible_rect_in_layer_space, &skewport_in_layer_space,
591 &soon_border_rect_in_layer_space, &eventually_rect_in_layer_space}; 631 &soon_border_rect_in_layer_space, &eventually_rect_in_layer_space};
592 gfx::Rect output_rects[4]; 632 gfx::Rect output_rects[4];
593 for (size_t i = 0; i < arraysize(input_rects); ++i) 633 for (size_t i = 0; i < arraysize(input_rects); ++i)
594 output_rects[i] = EnclosingContentsRectFromLayerRect(*input_rects[i]); 634 output_rects[i] = EnclosingContentsRectFromLayerRect(*input_rects[i]);
595 // Make sure the eventually rect is aligned to tile bounds. 635 // Make sure the eventually rect is aligned to tile bounds.
596 output_rects[3] = 636 output_rects[3] =
597 tiling_data_.ExpandRectIgnoringBordersToTileBounds(output_rects[3]); 637 tiling_data_.ExpandRectIgnoringBordersToTileBounds(output_rects[3]);
(...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after
958 return ToEnclosingRect(raster_transform_.MapRect(gfx::RectF(layer_rect))); 998 return ToEnclosingRect(raster_transform_.MapRect(gfx::RectF(layer_rect)));
959 } 999 }
960 1000
961 gfx::Rect PictureLayerTiling::EnclosingLayerRectFromContentsRect( 1001 gfx::Rect PictureLayerTiling::EnclosingLayerRectFromContentsRect(
962 const gfx::Rect& contents_rect) const { 1002 const gfx::Rect& contents_rect) const {
963 return ToEnclosingRect( 1003 return ToEnclosingRect(
964 raster_transform_.InverseMapRect(gfx::RectF(contents_rect))); 1004 raster_transform_.InverseMapRect(gfx::RectF(contents_rect)));
965 } 1005 }
966 1006
967 } // namespace cc 1007 } // namespace cc
OLDNEW
« no previous file with comments | « no previous file | cc/tiles/picture_layer_tiling_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698