1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/tiles/mipmap_util.h"
7 #include "base/numerics/safe_math.h"
11 // Calculates the size of |axis_base_size| at the given |mip_level|. Note that
12 // the calculation here rounds up for consistency with size calculations in the
13 // JPEG decoder. This allows us to decode images to the mip size directly.
14 int ScaleAxisToMipLevel(int axis_base_size, int mip_level) {
15 DCHECK_GE(mip_level, 0);
16 DCHECK_LT(mip_level, 32);
19 return axis_base_size;
21 // Increment the size by (2^mip_level - 1) so we round on when dividing it
23 base::CheckedNumeric<int> base_size = axis_base_size;
24 base_size += (1 << mip_level) - 1;
25 axis_base_size = base_size.ValueOrDefault(std::numeric_limits<int>::max());
26 return std::max(1, axis_base_size >> mip_level);
31 int MipMapUtil::GetLevelForSize(const gfx::Size& src_size,
32 const gfx::Size& target_size) {
33 int src_height = src_size.height();
34 int src_width = src_size.width();
35 int target_height = target_size.height();
36 int target_width = target_size.width();
37 DCHECK_GT(target_height, 0);
38 DCHECK_GT(target_width, 0);
39 DCHECK_GT(src_width, 0);
40 DCHECK_GT(src_height, 0);
42 int next_mip_height = src_height;
43 int next_mip_width = src_width;
44 for (int current_mip_level = 0;; current_mip_level++) {
45 int mip_height = next_mip_height;
46 int mip_width = next_mip_width;
48 next_mip_height = ScaleAxisToMipLevel(src_height, current_mip_level + 1);
49 next_mip_width = ScaleAxisToMipLevel(src_width, current_mip_level + 1);
51 // Check if an axis on the next mip level would be smaller than the target.
52 // If so, use the current mip level.
53 // This effectively always uses the larger image and always scales down.
54 if (next_mip_height < target_height || next_mip_width < target_width) {
55 return current_mip_level;
58 if (mip_height == 1 && mip_width == 1) {
59 // We have reached the final mip level
60 return current_mip_level;
65 SkSize MipMapUtil::GetScaleAdjustmentForLevel(const gfx::Size& src_size,
67 DCHECK_GT(src_size.width(), 0);
68 DCHECK_GT(src_size.height(), 0);
69 DCHECK_GE(mip_level, 0);
71 gfx::Size target_size = GetSizeForLevel(src_size, mip_level);
74 static_cast<float>(target_size.width()) / src_size.width(),
75 static_cast<float>(target_size.height()) / src_size.height());
78 gfx::Size MipMapUtil::GetSizeForLevel(const gfx::Size& src_size,
80 DCHECK_GT(src_size.width(), 0);
81 DCHECK_GT(src_size.height(), 0);
82 DCHECK_GE(mip_level, 0);
84 return gfx::Size(ScaleAxisToMipLevel(src_size.width(), mip_level),
85 ScaleAxisToMipLevel(src_size.height(), mip_level));
88 SkSize MipMapUtil::GetScaleAdjustmentForSize(const gfx::Size& src_size,
89 const gfx::Size& target_size) {
90 int target_mip_level = GetLevelForSize(src_size, target_size);
91 return GetScaleAdjustmentForLevel(src_size, target_mip_level);