chromium/ui/gfx/skbitmap_operations.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/354829279): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "ui/gfx/skbitmap_operations.h"

#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <algorithm>

#include "base/check_op.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColorFilter.h"
#include "third_party/skia/include/core/SkColorPriv.h"
#include "third_party/skia/include/core/SkUnPreMultiply.h"
#include "third_party/skia/include/effects/SkImageFilters.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"

static bool IsUninitializedBitmap(const SkBitmap& bitmap) {}

// static
SkBitmap SkBitmapOperations::CreateInvertedBitmap(const SkBitmap& image) {}

// static
SkBitmap SkBitmapOperations::CreateBlendedBitmap(const SkBitmap& first,
                                                 const SkBitmap& second,
                                                 double alpha) {}

// static
SkBitmap SkBitmapOperations::CreateMaskedBitmap(const SkBitmap& rgb,
                                                const SkBitmap& alpha) {}

// static
SkBitmap SkBitmapOperations::CreateButtonBackground(SkColor color,
                                                    const SkBitmap& image,
                                                    const SkBitmap& mask) {}

namespace {
namespace HSLShift {

// TODO(viettrungluu): Some things have yet to be optimized at all.

// Notes on and conventions used in the following code
//
// Conventions:
//  - R, G, B, A = obvious; as variables: |r|, |g|, |b|, |a| (see also below)
//  - H, S, L = obvious; as variables: |h|, |s|, |l| (see also below)
//  - variables derived from S, L shift parameters: |sdec| and |sinc| for S
//    increase and decrease factors, |ldec| and |linc| for L (see also below)
//
// To try to optimize HSL shifts, we do several things:
//  - Avoid unpremultiplying (then processing) then premultiplying. This means
//    that R, G, B values (and also L, but not H and S) should be treated as
//    having a range of 0..A (where A is alpha).
//  - Do things in integer/fixed-point. This avoids costly conversions between
//    floating-point and integer, though I should study the tradeoff more
//    carefully (presumably, at some point of processing complexity, converting
//    and processing using simpler floating-point code will begin to win in
//    performance). Also to be studied is the speed/type of floating point
//    conversions; see, e.g., <http://www.stereopsis.com/sree/fpu2006.html>.
//
// Conventions for fixed-point arithmetic
//  - Each function has a constant denominator (called |den|, which should be a
//    power of 2), appropriate for the computations done in that function.
//  - A value |x| is then typically represented by a numerator, named |x_num|,
//    so that its actual value is |x_num / den| (casting to floating-point
//    before division).
//  - To obtain |x_num| from |x|, simply multiply by |den|, i.e., |x_num = x *
//    den| (casting appropriately).
//  - When necessary, a value |x| may also be represented as a numerator over
//    the denominator squared (set |den2 = den * den|). In such a case, the
//    corresponding variable is called |x_num2| (so that its actual value is
//    |x_num^2 / den2|.
//  - The representation of the product of |x| and |y| is be called |x_y_num| if
//    |x * y == x_y_num / den|, and |xy_num2| if |x * y == x_y_num2 / den2|. In
//    the latter case, notice that one can calculate |x_y_num2 = x_num * y_num|.

// Routine used to process a line; typically specialized for specific kinds of
// HSL shifts (to optimize).
LineProcessor;

enum OperationOnH {};
enum OperationOnS {};
enum OperationOnL {};

// Epsilon used to judge when shift values are close enough to various critical
// values (typically 0.5, which yields a no-op for S and L shifts. 1/256 should
// be small enough, but let's play it safe>
const double epsilon =;

// Line processor: default/universal (i.e., old-school).
void LineProcDefault(const color_utils::HSL& hsl_shift,
                     const SkPMColor* in,
                     SkPMColor* out,
                     int width) {}

// Line processor: no-op (i.e., copy).
void LineProcCopy(const color_utils::HSL& hsl_shift,
                  const SkPMColor* in,
                  SkPMColor* out,
                  int width) {}

// Line processor: H no-op, S no-op, L decrease.
void LineProcHnopSnopLdec(const color_utils::HSL& hsl_shift,
                          const SkPMColor* in,
                          SkPMColor* out,
                          int width) {}

// Line processor: H no-op, S no-op, L increase.
void LineProcHnopSnopLinc(const color_utils::HSL& hsl_shift,
                          const SkPMColor* in,
                          SkPMColor* out,
                          int width) {}

// Saturation changes modifications in RGB
//
// (Note that as a further complication, the values we deal in are
// premultiplied, so R/G/B values must be in the range 0..A. For mathematical
// purposes, one may as well use r=R/A, g=G/A, b=B/A. Without loss of
// generality, assume that R/G/B values are in the range 0..1.)
//
// Let Max = max(R,G,B), Min = min(R,G,B), and Med be the median value. Then L =
// (Max+Min)/2. If L is to remain constant, Max+Min must also remain constant.
//
// For H to remain constant, first, the (numerical) order of R/G/B (from
// smallest to largest) must remain the same. Second, all the ratios
// (R-G)/(Max-Min), (R-B)/(Max-Min), (G-B)/(Max-Min) must remain constant (of
// course, if Max = Min, then S = 0 and no saturation change is well-defined,
// since H is not well-defined).
//
// Let C_max be a colour with value Max, C_min be one with value Min, and C_med
// the remaining colour. Increasing saturation (to the maximum) is accomplished
// by increasing the value of C_max while simultaneously decreasing C_min and
// changing C_med so that the ratios are maintained; for the latter, it suffices
// to keep (C_med-C_min)/(C_max-C_min) constant (and equal to
// (Med-Min)/(Max-Min)).

// Line processor: H no-op, S decrease, L no-op.
void LineProcHnopSdecLnop(const color_utils::HSL& hsl_shift,
                          const SkPMColor* in,
                          SkPMColor* out,
                          int width) {}

// Line processor: H no-op, S decrease, L decrease.
void LineProcHnopSdecLdec(const color_utils::HSL& hsl_shift,
                          const SkPMColor* in,
                          SkPMColor* out,
                          int width) {}

// Line processor: H no-op, S decrease, L increase.
void LineProcHnopSdecLinc(const color_utils::HSL& hsl_shift,
                          const SkPMColor* in,
                          SkPMColor* out,
                          int width) {}

const LineProcessor kLineProcessors[kNumHOps][kNumSOps][kNumLOps] =;

}  // namespace HSLShift
}  // namespace

// static
SkBitmap SkBitmapOperations::CreateHSLShiftedBitmap(
    const SkBitmap& bitmap,
    const color_utils::HSL& hsl_shift) {}

// static
SkBitmap SkBitmapOperations::CreateTiledBitmap(const SkBitmap& source,
                                               int src_x, int src_y,
                                               int dst_w, int dst_h) {}

// static
SkBitmap SkBitmapOperations::DownsampleByTwoUntilSize(const SkBitmap& bitmap,
                                                      int min_w, int min_h) {}

// static
SkBitmap SkBitmapOperations::DownsampleByTwo(const SkBitmap& bitmap) {}

// static
SkBitmap SkBitmapOperations::UnPreMultiply(const SkBitmap& bitmap) {}

// static
SkBitmap SkBitmapOperations::CreateTransposedBitmap(const SkBitmap& image) {}

// static
SkBitmap SkBitmapOperations::CreateColorMask(const SkBitmap& bitmap,
                                             SkColor c) {}

// static
SkBitmap SkBitmapOperations::CreateDropShadow(
    const SkBitmap& bitmap,
    const gfx::ShadowValues& shadows) {}

// static
SkBitmap SkBitmapOperations::Rotate(const SkBitmap& source,
                                    RotationAmount rotation) {}