blob: bbbaa1eecdc0816dc38f054f061057f85302c64b [file] [log] [blame]
// Copyright 2010-2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef MOZC_RENDERER_WIN32_WIN32_IMAGE_UTIL_H_
#define MOZC_RENDERER_WIN32_WIN32_IMAGE_UTIL_H_
#include <windows.h>
#include <bitset>
#include <memory>
#include <string>
#include <vector>
#include "base/coordinates.h"
#include "base/port.h"
namespace mozc {
namespace renderer {
namespace win32 {
// A 24 bit-per-pixel format that is used in BalloonImage generator.
// When we enable Skia as a back-end of graphics system, we might want to
// migrate to Skia's pixel format instead of our own ones.
struct RGBColor {
typedef uint8 ValueType;
ValueType r;
ValueType g;
ValueType b;
RGBColor();
RGBColor(ValueType red, ValueType green, ValueType blue);
bool operator==(const RGBColor &that) const;
bool operator!=(const RGBColor &that) const;
static const RGBColor kBlack;
static const RGBColor kWhite;
};
// A 32 bit-per-pixel format that is used in BalloonImage generator.
// When we enable Skia as a back-end of graphics system, we might want to
// migrate to Skia's pixel format instead of our own ones.
struct ARGBColor {
typedef uint8 ValueType;
ValueType a;
ValueType r;
ValueType g;
ValueType b;
ARGBColor();
ARGBColor(ValueType alpha, ValueType red, ValueType green, ValueType blue);
ARGBColor(const RGBColor &color, ValueType alpha);
bool operator==(const ARGBColor &that) const;
bool operator!=(const ARGBColor &that) const;
static const ARGBColor kBlack;
static const ARGBColor kWhite;
};
// A utility class to generate balloon-like image based on various parameters.
// You can generate the following shapes with this class.
// - Rectangle w/ and w/o balloon tail
// - Rounded rectangle w/ and w/o balloon tail
// - Circle
// You can put text label inside the balloon.
// You can also put 2D Gaussian blur effect with arbitrary color and opacity.
// See the comments of BalloonImageInfo for details.
class BalloonImage {
public:
struct BalloonImageInfo {
enum TailDirection {
kTop = 0,
kRight,
kBottom,
kLeft,
};
BalloonImageInfo();
RGBColor frame_color;
RGBColor inside_color;
RGBColor label_color;
RGBColor blur_color;
// Factor to blur color as a factor in [0.0, 1.0].
double blur_alpha;
// Size of the label text in points.
int label_size;
// Font name of the label text.
string label_font;
// Label text in UTF-8.
string label;
// Width of the bounding box of the balloon except for its tail.
double rect_width;
// Height of the bounding box of the balloon except for its tail.
double rect_height;
// Frame thickness in pixels. Set 0.0 to render a frame-less balloon.
double frame_thickness;
// Corner radius in pixels. Set 0.0 to render a solid balloon.
double corner_radius;
// Height of the tail in pixels. This is vertical length if
// |tail_direction| is kTop or kBottom and horizontal length if
// that is kRight or kLeft. Set 0.0 to render a tail-less balloon.
double tail_height;
// Width of the tail in pixels. This is horizontal length if
// |tail_direction| is kTop or kBottom and vertical length if that is
// kRight or kLeft. Set 0.0 to render a tail-less balloon.
double tail_width;
TailDirection tail_direction;
// Sigma parameter in pixels of the 2D Gaussian function. Set 0 to disable
// blur effect.
double blur_sigma;
// Horizontal offset in pixels with which blur image is placed. A positive
// offset moves the blur rightward (positive way in X coordinate).
int blur_offset_x;
// Vertical offset in pixels with which blur image is placed. A positive
// offset moves the blur downward (positive way in Y coordinate).
int blur_offset_y;
};
// Returns a bitmap handle to a DIB section that contains generated balloon
// image. Returns nullptr if fails.
// |tail_offset| is an offset pixels from the top-left corner of the bitmap.
// Note that the returned image is premultiplied-alpha format because GDI APIs
// including Layered Window APIs expect this format.
static HBITMAP Create(const BalloonImageInfo &info, POINT *tail_offset);
protected:
// A variant of Create method only for unit test. You can specify the label
// font and retrieve the rendering result as ARGB image. Note that
// |arbg_buffer| is not premultiplied-alpha format so that we can compare
// the rendering result with expected ones more precisely than PBGRA format
// used in the returned bitmap handle.
static HBITMAP CreateInternal(
const BalloonImageInfo &info,
POINT *tail_offset,
SIZE *size,
vector<ARGBColor> *arbg_buffer);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(BalloonImage);
};
// Following types are declared in this header so that unit test can access
// them. You should not use these classes directly.
namespace internal {
// A container of pixels that is useful to implement over-sampling-based
// anti-aliasing, where this class can be used as a virtual pixel. Basic concept
// of the implementation is simple: each empty sub-pixel in this container is
// concidered as a *transparent" area. It means that the opacity of the entire
// region can be calculated as the ratio of non-empty pixels to all pixels.
// This interpretation is consistent with the typical alpha blending function
// C = (1 - a) Cb + a Cf,
// where Cb is background color and Cf is foreground color and a is the alpha
// factor and C is the final visible color. This class can calculate 'a' and
// 'Cf'
class SubdivisionalPixel {
public:
typedef RGBColor ColorType;
static const size_t kDivision = 16;
static const size_t kTotalPixels = kDivision * kDivision;
// A pair of indices to specify the coordinate of each sub-pixel. That is
// [0, SubdivisionalPixel::kDivision) x [0, SubdivisionalPixel::kDivision)
struct Fraction2D {
public:
Fraction2D();
Fraction2D(size_t x_frac, size_t y_frac);
static const size_t kDivision = SubdivisionalPixel::kDivision;
const size_t x;
const size_t y;
};
// An iterator to enumerate each sub-pixel in left-right, right-bottom order.
class SubdivisionalPixelIterator {
public:
// The pair of |base_x| and |base_y| is the position of (0, 0).
SubdivisionalPixelIterator(int base_x, int base_y);
// Returns the indices of the current sub-pixel.
Fraction2D GetFraction() const;
// Returns the center of the current sub-pixel.
double GetX() const;
double GetY() const;
size_t GetIndex() const;
void Next();
bool Done() const;
private:
const int base_x_;
const int base_y_;
size_t numerator_x_;
size_t numerator_y_;
};
SubdivisionalPixel();
// Returns the coverage of this entire region as [0.0, 1.0].
const double GetCoverage() const;
// Returns the pixel color as the mean of filled sub-pixels.
const ColorType GetPixelColor() const;
// Sets |color| to all the sub-pixels.
void SetPixel(const ColorType &color);
// Sets |color| to one sub-pixel specified by |frac|.
void SetSubdivisionalPixel(const Fraction2D &frac, const ColorType &color);
// Sets |color| to all the filled sub-pixels.
void SetColorToFilledPixels(const ColorType &color);
private:
enum FillType {
kEmpty,
kSingleColor,
kMultipleColors,
};
FillType GetFillType() const;
static size_t GetIndex(const Fraction2D &offset);
// A bit vector that indicates each sub-pixel is filled or not.
bitset<kTotalPixels> filled_;
std::unique_ptr<ColorType[]> colors_;
ColorType single_color_;
DISALLOW_COPY_AND_ASSIGN(SubdivisionalPixel);
};
// An implementation of Gaussian blur filter.
class GaussianBlur {
public:
// Sigma parameter in pixels of the 2D Gaussian function. Set 0 to disable
// blur effect.
explicit GaussianBlur(double sigma);
// Returns the cut-off length to construct the convolution matrix. If the
// returned value is x, (2 * x + 1)^2 matrix will be used.
int cutoff_length() const;
// Returns the blurred value of |f(x, y)|, where |f| can be any function-like
// object.
template <typename Function>
double Apply(int x, int y, const Function &f) const {
double sum = 0.0;
for (Matrix::const_iterator it = matrix_.begin();
it != matrix_.end(); ++it) {
sum += it->coefficient * f(x + it->offset_x, y + it->offset_y);
}
return sum;
}
private:
// An element type of convolution matrix.
struct MatrixElement {
int offset_x;
int offset_y;
double coefficient;
MatrixElement();
MatrixElement(int x, int y, double c);
};
typedef vector<MatrixElement> Matrix;
size_t GetMatrixLength() const;
const double sigma_;
const int cutoff_length_;
Matrix matrix_;
DISALLOW_COPY_AND_ASSIGN(GaussianBlur);
};
// A virtual 2D container of ARGB pixels where out-of-range pixels are treated
// as read-only and transparent.
class SafeFrameBuffer {
public:
// Initializes the frame buffer with real backing store as follows.
// [left, left + width) x [top, top + height)
explicit SafeFrameBuffer(const Rect &rect);
// Returns the color of the specified pixel. If the pixel is out-of-window,
// returns a transparent black.
ARGBColor GetPixel(int x, int y) const;
// Sets the color into the specified pixel. If it pixel out-of-window, does
// nothing.
void SetPixel(int x, int y, const ARGBColor &color);
private:
bool IsInWindow(int x, int y) const;
size_t GetIndex(int x, int y) const;
const Rect rect_;
std::unique_ptr<ARGBColor[]> buffer_;
DISALLOW_COPY_AND_ASSIGN(SafeFrameBuffer);
};
// A text rendering utility class that utilize sub-pixel rendering and can
// output the result to SubdivisionalPixel storage.
class TextLabel {
public:
typedef bitset<SubdivisionalPixel::kDivision * SubdivisionalPixel::kDivision>
BinarySubdivisionalPixel;
TextLabel(double left,
double top,
double width,
double height,
const string &text,
const string &font,
size_t font_point,
const RGBColor text_color);
~TextLabel();
// Copies the pixel specified by |x| and |y| to |dest|. Does nothing if the
// pixel is empty.
void RenderPixel(int x, int y, SubdivisionalPixel *dest) const;
// Returns bounding box.
const Rect &bounding_rect() const;
private:
const vector<BinarySubdivisionalPixel *> pixels_;
const Rect bounding_rect_;
const RGBColor text_color_;
DISALLOW_COPY_AND_ASSIGN(TextLabel);
};
} // namespace internal
} // namespace win32
} // namespace renderer
} // namespace mozc
#endif // MOZC_RENDERER_WIN32_WIN32_IMAGE_UTIL_H_