blob: c6908178543e634ae241bd1737f482a74861be13 [file] [log] [blame]
// 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 >= 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