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

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: layouttests Created 3 years, 7 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 | « cc/tiles/picture_layer_tiling.h ('k') | 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 358 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 } 369 }
370 370
371 PictureLayerTiling::CoverageIterator::CoverageIterator() = default; 371 PictureLayerTiling::CoverageIterator::CoverageIterator() = default;
372 372
373 PictureLayerTiling::CoverageIterator::CoverageIterator( 373 PictureLayerTiling::CoverageIterator::CoverageIterator(
374 const PictureLayerTiling* tiling, 374 const PictureLayerTiling* tiling,
375 float coverage_scale, 375 float coverage_scale,
376 const gfx::Rect& coverage_rect) 376 const gfx::Rect& coverage_rect)
377 : tiling_(tiling), 377 : tiling_(tiling),
378 coverage_rect_(coverage_rect), 378 coverage_rect_(coverage_rect),
379 coverage_to_content_( 379 coverage_to_content_(tiling->raster_transform().scale() / coverage_scale,
380 gfx::PreScaleAxisTransform2d(tiling->raster_transform(), 380 tiling->raster_transform().translation()) {
381 1.f / coverage_scale)) {
382 DCHECK(tiling_); 381 DCHECK(tiling_);
383 // In order to avoid artifacts in geometry_rect scaling and clamping to ints, 382 // In order to avoid artifacts in geometry_rect scaling and clamping to ints,
384 // the |coverage_scale| should always be at least as big as the tiling's 383 // the |coverage_scale| should always be at least as big as the tiling's
385 // raster scales. 384 // raster scales.
386 DCHECK_GE(coverage_scale, tiling_->raster_transform_.scale()); 385 DCHECK_GE(coverage_scale, tiling_->raster_transform_.scale());
387 386
388 // Clamp |coverage_rect| to the bounds of this tiling's raster source. 387 // Clamp |coverage_rect| to the bounds of this tiling's raster source.
389 coverage_rect_max_bounds_ = 388 coverage_rect_max_bounds_ =
390 gfx::ScaleToCeiledSize(tiling->raster_source_->GetSize(), coverage_scale); 389 gfx::ScaleToCeiledSize(tiling->raster_source_->GetSize(), coverage_scale);
391 coverage_rect_.Intersect(gfx::Rect(coverage_rect_max_bounds_)); 390 coverage_rect_.Intersect(gfx::Rect(coverage_rect_max_bounds_));
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
428 427
429 PictureLayerTiling::CoverageIterator::~CoverageIterator() { 428 PictureLayerTiling::CoverageIterator::~CoverageIterator() {
430 } 429 }
431 430
432 PictureLayerTiling::CoverageIterator& 431 PictureLayerTiling::CoverageIterator&
433 PictureLayerTiling::CoverageIterator::operator++() { 432 PictureLayerTiling::CoverageIterator::operator++() {
434 if (tile_j_ > bottom_) 433 if (tile_j_ > bottom_)
435 return *this; 434 return *this;
436 435
437 bool first_time = tile_i_ < left_; 436 bool first_time = tile_i_ < left_;
438 bool new_row = false; 437 while (true) {
439 tile_i_++; 438 bool new_row = false;
440 if (tile_i_ > right_) { 439 tile_i_++;
441 tile_i_ = left_; 440 if (tile_i_ > right_) {
442 tile_j_++; 441 tile_i_ = left_;
443 new_row = true; 442 tile_j_++;
444 if (tile_j_ > bottom_) { 443 new_row = true;
445 current_tile_ = NULL; 444 if (tile_j_ > bottom_) {
446 return *this; 445 current_tile_ = NULL;
446 break;
447 }
447 } 448 }
449
450 DCHECK_LT(tile_i_, tiling_->tiling_data_.num_tiles_x());
451 DCHECK_LT(tile_j_, tiling_->tiling_data_.num_tiles_y());
452 current_tile_ = tiling_->TileAt(tile_i_, tile_j_);
453
454 gfx::Rect geometry_rect_candidate = ComputeGeometryRect();
455
456 // This can happen due to floating point inprecision when calculating the
457 // |wanted_texels| area in the constructor.
458 if (geometry_rect_candidate.IsEmpty())
459 continue;
460
461 gfx::Rect last_geometry_rect = current_geometry_rect_;
462 current_geometry_rect_ = geometry_rect_candidate;
463
464 if (first_time)
465 break;
466
467 // Iteration happens left->right, top->bottom. Running off the bottom-right
468 // edge is handled by the intersection above with dest_rect_. Here we make
469 // sure that the new current geometry rect doesn't overlap with the last.
470 int min_left;
471 int min_top;
472 if (new_row) {
473 min_left = coverage_rect_.x();
474 min_top = last_geometry_rect.bottom();
475 } else {
476 min_left = last_geometry_rect.right();
477 min_top = last_geometry_rect.y();
478 }
479
480 int inset_left = std::max(0, min_left - current_geometry_rect_.x());
481 int inset_top = std::max(0, min_top - current_geometry_rect_.y());
482 current_geometry_rect_.Inset(inset_left, inset_top, 0, 0);
483
484 #if DCHECK_IS_ON()
485 if (!new_row) {
486 DCHECK_EQ(last_geometry_rect.right(), current_geometry_rect_.x());
487 DCHECK_EQ(last_geometry_rect.bottom(), current_geometry_rect_.bottom());
488 DCHECK_EQ(last_geometry_rect.y(), current_geometry_rect_.y());
489 }
490 #endif
491
492 break;
448 } 493 }
494 return *this;
495 }
449 496
450 current_tile_ = tiling_->TileAt(tile_i_, tile_j_); 497 gfx::Rect PictureLayerTiling::CoverageIterator::ComputeGeometryRect() const {
451
452 // Calculate the current geometry rect. As we reserved overlap between tiles 498 // Calculate the current geometry rect. As we reserved overlap between tiles
453 // to accommodate bilinear filtering and rounding errors in destination 499 // to accommodate bilinear filtering and rounding errors in destination
454 // space, the geometry rect might overlap on the edges. 500 // space, the geometry rect might overlap on the edges.
455 gfx::Rect last_geometry_rect = current_geometry_rect_;
456
457 gfx::RectF texel_extent = tiling_->tiling_data_.TexelExtent(tile_i_, tile_j_); 501 gfx::RectF texel_extent = tiling_->tiling_data_.TexelExtent(tile_i_, tile_j_);
458 { 502 {
459 // Adjust tile extent to accommodate numerical errors. 503 // Adjust tile extent to accommodate numerical errors.
460 // 504 //
461 // Allow the tile to overreach by 1/1024 texels to avoid seams between 505 // Allow the tile to overreach by 1/1024 texels to avoid seams between
462 // tiles. The constant 1/1024 is picked by the fact that with bilinear 506 // tiles. The constant 1/1024 is picked by the fact that with bilinear
463 // filtering, the maximum error in color value introduced by clamping 507 // filtering, the maximum error in color value introduced by clamping
464 // error in both u/v axis can't exceed 508 // error in both u/v axis can't exceed
465 // 255 * (1 - (1 - 1/1024) * (1 - 1/1024)) ~= 0.498 509 // 255 * (1 - (1 - 1/1024) * (1 - 1/1024)) ~= 0.498
466 // i.e. The color value can never flip over a rounding threshold. 510 // i.e. The color value can never flip over a rounding threshold.
467 constexpr float epsilon = 1.f / 1024.f; 511 constexpr float epsilon = 1.f / 1024.f;
468 texel_extent.Inset(-epsilon, -epsilon); 512 texel_extent.Inset(-epsilon, -epsilon);
469 } 513 }
470 514
471 // Convert texel_extent to coverage scale, which is what we have to report 515 // Convert texel_extent to coverage scale, which is what we have to report
472 // geometry_rect in. 516 // geometry_rect in.
473 current_geometry_rect_ = 517 gfx::Rect candidate =
474 gfx::ToEnclosedRect(coverage_to_content_.InverseMapRect(texel_extent)); 518 gfx::ToEnclosedRect(coverage_to_content_.InverseMapRect(texel_extent));
475 { 519 {
476 // Adjust external edges to cover the whole layer in dest space. 520 // Adjust external edges to cover the whole layer in dest space.
477 // 521 //
478 // For external edges, extend the tile to scaled layer bounds. This is 522 // For external edges, extend the tile to scaled layer bounds. This is
479 // needed to fully cover the coverage space because the sample extent 523 // needed to fully cover the coverage space because the sample extent
480 // doesn't cover the last 0.5 texel to layer edge, and also the coverage 524 // doesn't cover the last 0.5 texel to layer edge, and also the coverage
481 // space can be rounded up for up to 1 pixel. This overhang will never be 525 // space can be rounded up for up to 1 pixel. This overhang will never be
482 // sampled as the AA fragment shader clamps sample coordinate and 526 // sampled as the AA fragment shader clamps sample coordinate and
483 // antialiasing itself. 527 // antialiasing itself.
484 const TilingData& data = tiling_->tiling_data_; 528 const TilingData& data = tiling_->tiling_data_;
485 current_geometry_rect_.Inset(tile_i_ ? 0 : -current_geometry_rect_.x(), 529 candidate.Inset(
486 tile_j_ ? 0 : -current_geometry_rect_.y(), 530 tile_i_ ? 0 : -candidate.x(), tile_j_ ? 0 : -candidate.y(),
487 (tile_i_ != data.num_tiles_x() - 1) 531 (tile_i_ != data.num_tiles_x() - 1)
488 ? 0 532 ? 0
489 : current_geometry_rect_.right() - 533 : candidate.right() - coverage_rect_max_bounds_.width(),
490 coverage_rect_max_bounds_.width(), 534 (tile_j_ != data.num_tiles_y() - 1)
491 (tile_j_ != data.num_tiles_y() - 1) 535 ? 0
492 ? 0 536 : candidate.bottom() - coverage_rect_max_bounds_.height());
493 : current_geometry_rect_.bottom() -
494 coverage_rect_max_bounds_.height());
495 } 537 }
496 538
497 current_geometry_rect_.Intersect(coverage_rect_); 539 candidate.Intersect(coverage_rect_);
498 DCHECK(!current_geometry_rect_.IsEmpty()); 540 return candidate;
499
500 if (first_time)
501 return *this;
502
503 // Iteration happens left->right, top->bottom. Running off the bottom-right
504 // edge is handled by the intersection above with dest_rect_. Here we make
505 // sure that the new current geometry rect doesn't overlap with the last.
506 int min_left;
507 int min_top;
508 if (new_row) {
509 min_left = coverage_rect_.x();
510 min_top = last_geometry_rect.bottom();
511 } else {
512 min_left = last_geometry_rect.right();
513 min_top = last_geometry_rect.y();
514 }
515
516 int inset_left = std::max(0, min_left - current_geometry_rect_.x());
517 int inset_top = std::max(0, min_top - current_geometry_rect_.y());
518 current_geometry_rect_.Inset(inset_left, inset_top, 0, 0);
519
520 if (!new_row) {
521 DCHECK_EQ(last_geometry_rect.right(), current_geometry_rect_.x());
522 DCHECK_EQ(last_geometry_rect.bottom(), current_geometry_rect_.bottom());
523 DCHECK_EQ(last_geometry_rect.y(), current_geometry_rect_.y());
524 }
525
526 return *this;
527 } 541 }
528 542
529 gfx::Rect PictureLayerTiling::CoverageIterator::geometry_rect() const { 543 gfx::Rect PictureLayerTiling::CoverageIterator::geometry_rect() const {
530 return current_geometry_rect_; 544 return current_geometry_rect_;
531 } 545 }
532 546
533 gfx::RectF PictureLayerTiling::CoverageIterator::texture_rect() const { 547 gfx::RectF PictureLayerTiling::CoverageIterator::texture_rect() const {
534 auto tex_origin = gfx::PointF( 548 auto tex_origin = gfx::PointF(
535 tiling_->tiling_data_.TileBoundsWithBorder(tile_i_, tile_j_).origin()); 549 tiling_->tiling_data_.TileBoundsWithBorder(tile_i_, tile_j_).origin());
536 550
(...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after
979 return ToEnclosingRect(raster_transform_.MapRect(gfx::RectF(layer_rect))); 993 return ToEnclosingRect(raster_transform_.MapRect(gfx::RectF(layer_rect)));
980 } 994 }
981 995
982 gfx::Rect PictureLayerTiling::EnclosingLayerRectFromContentsRect( 996 gfx::Rect PictureLayerTiling::EnclosingLayerRectFromContentsRect(
983 const gfx::Rect& contents_rect) const { 997 const gfx::Rect& contents_rect) const {
984 return ToEnclosingRect( 998 return ToEnclosingRect(
985 raster_transform_.InverseMapRect(gfx::RectF(contents_rect))); 999 raster_transform_.InverseMapRect(gfx::RectF(contents_rect)));
986 } 1000 }
987 1001
988 } // namespace cc 1002 } // namespace cc
OLDNEW
« no previous file with comments | « cc/tiles/picture_layer_tiling.h ('k') | cc/tiles/picture_layer_tiling_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698