|  | // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "chrome/browser/thumbnails/thumbnail_utils.h" | 
|  |  | 
|  | #include <algorithm> | 
|  |  | 
|  | #include "components/history/core/common/thumbnail_score.h" | 
|  | #include "content/public/browser/browser_thread.h" | 
|  | #include "ui/gfx/geometry/size_conversions.h" | 
|  |  | 
|  | namespace thumbnails { | 
|  |  | 
|  | bool IsGoodClipping(ClipResult clip_result) { | 
|  | return clip_result == CLIP_RESULT_WIDER_THAN_TALL || | 
|  | clip_result == CLIP_RESULT_TALLER_THAN_WIDE || | 
|  | clip_result == CLIP_RESULT_NOT_CLIPPED; | 
|  | } | 
|  |  | 
|  | ClipResult GetCanvasCopyInfo(const gfx::Size& source_size, | 
|  | ui::ScaleFactor scale_factor, | 
|  | const gfx::Size& target_size, | 
|  | gfx::Rect* clipping_rect, | 
|  | gfx::Size* copy_size) { | 
|  | DCHECK(!source_size.IsEmpty()); | 
|  | DCHECK(!target_size.IsEmpty()); | 
|  | ClipResult clip_result = thumbnails::CLIP_RESULT_NOT_CLIPPED; | 
|  | *clipping_rect = GetClippingRect(source_size, target_size, &clip_result); | 
|  | *copy_size = GetCopySizeForThumbnail(scale_factor, target_size); | 
|  | return clip_result; | 
|  | } | 
|  |  | 
|  | // RenderWidgetHostView::CopyFromSurface() can be costly especially when it is | 
|  | // necessary to read back the web contents image data from GPU. As the cost is | 
|  | // roughly proportional to the number of the copied pixels, the size of the | 
|  | // copied pixels should be as small as possible. | 
|  | gfx::Size GetCopySizeForThumbnail(ui::ScaleFactor scale_factor, | 
|  | const gfx::Size& thumbnail_size) { | 
|  | // The copy size returned is the pixel equivalent of |thumbnail_size|, which | 
|  | // is in DIPs. | 
|  | if (scale_factor == ui::SCALE_FACTOR_100P) { | 
|  | // In the case of 1x devices, we get a thumbnail twice as big and reduce | 
|  | // it at serve time to improve quality. | 
|  | scale_factor = ui::SCALE_FACTOR_200P; | 
|  | } | 
|  | float scale = GetScaleForScaleFactor(scale_factor); | 
|  | // Limit the scale factor to a maximum of 2x for privacy reasons; see | 
|  | // crbug.com/670488. | 
|  | scale = std::min(2.0f, scale); | 
|  | return gfx::ScaleToFlooredSize(thumbnail_size, scale); | 
|  | } | 
|  |  | 
|  | gfx::Rect GetClippingRect(const gfx::Size& source_size, | 
|  | const gfx::Size& desired_size, | 
|  | ClipResult* clip_result) { | 
|  | DCHECK(clip_result); | 
|  |  | 
|  | float desired_aspect = | 
|  | static_cast<float>(desired_size.width()) / desired_size.height(); | 
|  |  | 
|  | // Get the clipping rect so that we can preserve the aspect ratio while | 
|  | // filling the destination. | 
|  | gfx::Rect clipping_rect; | 
|  | if (source_size.width() < desired_size.width() || | 
|  | source_size.height() < desired_size.height()) { | 
|  | // Source image is smaller: we clip the part of source image within the | 
|  | // dest rect, and then stretch it to fill the dest rect. We don't respect | 
|  | // the aspect ratio in this case. | 
|  | clipping_rect = gfx::Rect(desired_size); | 
|  | *clip_result = thumbnails::CLIP_RESULT_SOURCE_IS_SMALLER; | 
|  | } else { | 
|  | float src_aspect = | 
|  | static_cast<float>(source_size.width()) / source_size.height(); | 
|  | if (src_aspect > desired_aspect) { | 
|  | // Wider than tall, clip horizontally: we center the smaller | 
|  | // thumbnail in the wider screen. | 
|  | int new_width = static_cast<int>(source_size.height() * desired_aspect); | 
|  | int x_offset = (source_size.width() - new_width) / 2; | 
|  | clipping_rect.SetRect(x_offset, 0, new_width, source_size.height()); | 
|  | *clip_result = | 
|  | (src_aspect >= history::ThumbnailScore::kTooWideAspectRatio) | 
|  | ? thumbnails::CLIP_RESULT_MUCH_WIDER_THAN_TALL | 
|  | : thumbnails::CLIP_RESULT_WIDER_THAN_TALL; | 
|  | } else if (src_aspect < desired_aspect) { | 
|  | clipping_rect = | 
|  | gfx::Rect(source_size.width(), source_size.width() / desired_aspect); | 
|  | *clip_result = thumbnails::CLIP_RESULT_TALLER_THAN_WIDE; | 
|  | } else { | 
|  | clipping_rect = gfx::Rect(source_size); | 
|  | *clip_result = thumbnails::CLIP_RESULT_NOT_CLIPPED; | 
|  | } | 
|  | } | 
|  | return clipping_rect; | 
|  | } | 
|  |  | 
|  | }  // namespace thumbnails |