1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file.
4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/thumbnails/content_based_thumbnailing_algorithm.h"
6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/metrics/histogram.h"
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/threading/sequenced_worker_pool.h"
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/thumbnails/content_analysis.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/thumbnails/simple_thumbnail_crop.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ui/gfx/scrollbar_size.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ui/gfx/size_conversions.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ui/gfx/skbitmap_operations.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ui/gfx/skia_util.h"
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace {
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const char kThumbnailHistogramName[] = "Thumbnail.RetargetMS";
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const char kFailureHistogramName[] = "Thumbnail.FailedRetargetMS";
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const float kScoreBoostFromSuccessfulRetargeting = 1.1f;
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void CallbackInvocationAdapter(
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const thumbnails::ThumbnailingAlgorithm::ConsumerCallback& callback,
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    scoped_refptr<thumbnails::ThumbnailingContext> context,
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const SkBitmap& source_bitmap) {
287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  callback.Run(*context.get(), source_bitmap);
29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace
32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace thumbnails {
34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)using content::BrowserThread;
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)ContentBasedThumbnailingAlgorithm::ContentBasedThumbnailingAlgorithm(
38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const gfx::Size& target_size)
39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    : target_size_(target_size) {
40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!target_size.IsEmpty());
41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)ClipResult ContentBasedThumbnailingAlgorithm::GetCanvasCopyInfo(
44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const gfx::Size& source_size,
45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ui::ScaleFactor scale_factor,
46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    gfx::Rect* clipping_rect,
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    gfx::Size* target_size) const {
48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!source_size.IsEmpty());
49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::Size target_thumbnail_size =
50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      SimpleThumbnailCrop::GetCopySizeForThumbnail(scale_factor, target_size_);
51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ClipResult clipping_method = thumbnails::CLIP_RESULT_NOT_CLIPPED;
53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  *clipping_rect = GetClippingRect(
54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      source_size, target_thumbnail_size, target_size, &clipping_method);
55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return clipping_method;
56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void ContentBasedThumbnailingAlgorithm::ProcessBitmap(
59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    scoped_refptr<ThumbnailingContext> context,
60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const ConsumerCallback& callback,
61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const SkBitmap& bitmap) {
62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DCHECK(context.get());
64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (bitmap.isNull() || bitmap.empty())
65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::Size target_thumbnail_size =
68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      SimpleThumbnailCrop::ComputeTargetSizeAtMaximumScale(target_size_);
69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  SkBitmap source_bitmap =
717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      PrepareSourceBitmap(bitmap, target_thumbnail_size, context.get());
72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // If the source is same (or smaller) than the target, just return it as
74868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // the final result. Otherwise, send the shrinking task to the blocking
75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // thread pool.
76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (source_bitmap.width() <= target_thumbnail_size.width() ||
77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      source_bitmap.height() <= target_thumbnail_size.height()) {
78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    context->score.boring_score =
79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        SimpleThumbnailCrop::CalculateBoringScore(source_bitmap);
80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    context->score.good_clipping =
81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        (context->clip_result == CLIP_RESULT_WIDER_THAN_TALL ||
82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)         context->clip_result == CLIP_RESULT_TALLER_THAN_WIDE ||
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)         context->clip_result == CLIP_RESULT_NOT_CLIPPED ||
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)         context->clip_result == CLIP_RESULT_SOURCE_SAME_AS_TARGET);
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    callback.Run(*context.get(), source_bitmap);
87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior(
91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          FROM_HERE,
92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          base::Bind(&CreateRetargetedThumbnail,
93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                     source_bitmap,
94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                     target_thumbnail_size,
95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                     context,
96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                     callback),
97868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)) {
98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    LOG(WARNING) << "PostSequencedWorkerTask failed. The thumbnail for "
99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                 << context->url << " will not be created.";
100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// static
104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)SkBitmap ContentBasedThumbnailingAlgorithm::PrepareSourceBitmap(
105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const SkBitmap& received_bitmap,
106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const gfx::Size& thumbnail_size,
107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ThumbnailingContext* context) {
108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::Size resize_target;
109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  SkBitmap clipped_bitmap;
110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (context->clip_result == CLIP_RESULT_UNPROCESSED) {
111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // This case will require extracting a fragment from the retrieved bitmap.
112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int scrollbar_size = gfx::scrollbar_size();
113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    gfx::Size scrollbarless(
114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        std::max(1, received_bitmap.width() - scrollbar_size),
115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        std::max(1, received_bitmap.height() - scrollbar_size));
116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    gfx::Rect clipping_rect = GetClippingRect(
118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        scrollbarless,
119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        thumbnail_size,
120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        &resize_target,
121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        &context->clip_result);
122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    received_bitmap.extractSubset(&clipped_bitmap,
124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                  gfx::RectToSkIRect(clipping_rect));
125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else {
126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // This means that the source bitmap has been requested and at least
127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // clipped. Upstream code in same cases seems opportunistic and it may
128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // not perform actual resizing if copying with resize is not supported.
129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // In this case we will resize to the orignally requested copy size.
130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    resize_target = context->requested_copy_size;
131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    clipped_bitmap = received_bitmap;
132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  SkBitmap result_bitmap = SkBitmapOperations::DownsampleByTwoUntilSize(
135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      clipped_bitmap, resize_target.width(), resize_target.height());
136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#if !defined(USE_AURA)
137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // If the bitmap has not been indeed resized, it has to be copied. In that
138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // case resampler simply returns a reference to the original bitmap, sitting
139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // in PlatformCanvas. One does not simply assign these 'magic' bitmaps to
140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // SkBitmap. They cannot be refcounted.
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  //
142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // With Aura, this does not happen since PlatformCanvas is platform
143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // idependent.
144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (clipped_bitmap.width() == result_bitmap.width() &&
145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      clipped_bitmap.height() == result_bitmap.height()) {
146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    clipped_bitmap.copyTo(&result_bitmap, kN32_SkColorType);
147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#endif
149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return result_bitmap;
151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// static
154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void ContentBasedThumbnailingAlgorithm::CreateRetargetedThumbnail(
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const SkBitmap& source_bitmap,
156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const gfx::Size& thumbnail_size,
157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    scoped_refptr<ThumbnailingContext> context,
158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const ConsumerCallback& callback) {
159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now();
160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  float kernel_sigma =
161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      context->clip_result == CLIP_RESULT_SOURCE_SAME_AS_TARGET ? 5.0f : 2.5f;
162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  SkBitmap thumbnail = thumbnailing_utils::CreateRetargetedThumbnailImage(
163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      source_bitmap, thumbnail_size, kernel_sigma);
164868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bool processing_failed = thumbnail.empty();
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (processing_failed) {
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Log and apply the method very much like in SimpleThumbnailCrop (except
167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // that some clipping and copying is not required).
168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    LOG(WARNING) << "CreateRetargetedThumbnailImage failed. "
169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                 << "The thumbnail for " << context->url
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                 << " will be created the old-fashioned way.";
171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
172868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ClipResult clip_result;
173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    gfx::Rect clipping_rect = SimpleThumbnailCrop::GetClippingRect(
174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        gfx::Size(source_bitmap.width(), source_bitmap.height()),
175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        thumbnail_size,
176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        &clip_result);
177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    source_bitmap.extractSubset(&thumbnail, gfx::RectToSkIRect(clipping_rect));
178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    thumbnail = SkBitmapOperations::DownsampleByTwoUntilSize(
179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        thumbnail, thumbnail_size.width(), thumbnail_size.height());
180868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
181868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (processing_failed) {
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    LOCAL_HISTOGRAM_TIMES(kFailureHistogramName,
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                          base::TimeTicks::Now() - begin_compute_thumbnail);
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else {
1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    LOCAL_HISTOGRAM_TIMES(kThumbnailHistogramName,
1871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                          base::TimeTicks::Now() - begin_compute_thumbnail);
1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
189868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  context->score.boring_score =
190868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        SimpleThumbnailCrop::CalculateBoringScore(source_bitmap);
191868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!processing_failed)
192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    context->score.boring_score *= kScoreBoostFromSuccessfulRetargeting;
193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  context->score.good_clipping =
194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      (context->clip_result == CLIP_RESULT_WIDER_THAN_TALL ||
195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       context->clip_result == CLIP_RESULT_TALLER_THAN_WIDE ||
196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       context->clip_result == CLIP_RESULT_NOT_CLIPPED ||
197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       context->clip_result == CLIP_RESULT_SOURCE_SAME_AS_TARGET);
198868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Post the result (the bitmap) back to the callback.
199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  BrowserThread::PostTask(
200868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      BrowserThread::UI,
201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      FROM_HERE,
202868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      base::Bind(&CallbackInvocationAdapter, callback, context, thumbnail));
203868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
204868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
205868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)ContentBasedThumbnailingAlgorithm::~ContentBasedThumbnailingAlgorithm() {
206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
207868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
208868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)//  static
209868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)gfx::Rect ContentBasedThumbnailingAlgorithm::GetClippingRect(
210868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const gfx::Size& source_size,
211868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const gfx::Size& thumbnail_size,
212868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    gfx::Size* target_size,
213868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ClipResult* clip_result) {
214868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Compute and return the clipping rectagle of the source image and the
215868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // size of the target bitmap which will be used for the further processing.
216868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // This function in 'general case' is trivial (don't clip, halve the source)
217868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // but it is needed for handling edge cases (source smaller than the target
218868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // thumbnail size).
219868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(target_size);
220868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(clip_result);
221868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::Rect clipping_rect;
222868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (source_size.width() < thumbnail_size.width() ||
223868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      source_size.height() < thumbnail_size.height()) {
224868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    clipping_rect = gfx::Rect(thumbnail_size);
225868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    *target_size = thumbnail_size;
226868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    *clip_result = CLIP_RESULT_SOURCE_IS_SMALLER;
227868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else if (source_size.width() < thumbnail_size.width() * 4 ||
228868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)             source_size.height() < thumbnail_size.height() * 4) {
229868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    clipping_rect = gfx::Rect(source_size);
230868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    *target_size = source_size;
231868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    *clip_result = CLIP_RESULT_SOURCE_SAME_AS_TARGET;
232868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else {
233868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    clipping_rect = gfx::Rect(source_size);
234868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    target_size->SetSize(source_size.width() / 2, source_size.height() / 2);
235868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    *clip_result = CLIP_RESULT_NOT_CLIPPED;
236868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
237868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
238868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return clipping_rect;
239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
240868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
241868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace thumbnails
242