bug 853682 - remove most of the chromium gfx stuff since it isn't used we need to keep a few headers because they're included, but we don't even need to define the functions they declare. r=bsmedberg

This commit is contained in:
Trevor Saunders 2013-03-19 18:34:23 -04:00
parent 7c08c309ff
commit dd41b4580f
27 changed files with 0 additions and 3884 deletions

View File

@ -1,79 +0,0 @@
// Copyright (c) 2006-2008 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 "base/gfx/gdi_util.h"
namespace gfx {
void CreateBitmapHeader(int width, int height, BITMAPINFOHEADER* hdr) {
CreateBitmapHeaderWithColorDepth(width, height, 32, hdr);
}
void CreateBitmapHeaderWithColorDepth(int width, int height, int color_depth,
BITMAPINFOHEADER* hdr) {
// These values are shared with gfx::PlatformDevice
hdr->biSize = sizeof(BITMAPINFOHEADER);
hdr->biWidth = width;
hdr->biHeight = -height; // minus means top-down bitmap
hdr->biPlanes = 1;
hdr->biBitCount = color_depth;
hdr->biCompression = BI_RGB; // no compression
hdr->biSizeImage = 0;
hdr->biXPelsPerMeter = 1;
hdr->biYPelsPerMeter = 1;
hdr->biClrUsed = 0;
hdr->biClrImportant = 0;
}
void CreateBitmapV4Header(int width, int height, BITMAPV4HEADER* hdr) {
// Because bmp v4 header is just an extension, we just create a v3 header and
// copy the bits over to the v4 header.
BITMAPINFOHEADER header_v3;
CreateBitmapHeader(width, height, &header_v3);
memset(hdr, 0, sizeof(BITMAPV4HEADER));
memcpy(hdr, &header_v3, sizeof(BITMAPINFOHEADER));
// Correct the size of the header and fill in the mask values.
hdr->bV4Size = sizeof(BITMAPV4HEADER);
hdr->bV4RedMask = 0x00ff0000;
hdr->bV4GreenMask = 0x0000ff00;
hdr->bV4BlueMask = 0x000000ff;
hdr->bV4AlphaMask = 0xff000000;
}
// Creates a monochrome bitmap header.
void CreateMonochromeBitmapHeader(int width,
int height,
BITMAPINFOHEADER* hdr) {
hdr->biSize = sizeof(BITMAPINFOHEADER);
hdr->biWidth = width;
hdr->biHeight = -height;
hdr->biPlanes = 1;
hdr->biBitCount = 1;
hdr->biCompression = BI_RGB;
hdr->biSizeImage = 0;
hdr->biXPelsPerMeter = 1;
hdr->biYPelsPerMeter = 1;
hdr->biClrUsed = 0;
hdr->biClrImportant = 0;
}
void SubtractRectanglesFromRegion(HRGN hrgn,
const std::vector<gfx::Rect>& cutouts) {
if (cutouts.size()) {
HRGN cutout = ::CreateRectRgn(0, 0, 0, 0);
for (size_t i = 0; i < cutouts.size(); i++) {
::SetRectRgn(cutout,
cutouts[i].x(),
cutouts[i].y(),
cutouts[i].right(),
cutouts[i].bottom());
::CombineRgn(hrgn, hrgn, cutout, RGN_DIFF);
}
::DeleteObject(cutout);
}
}
} // namespace gfx

View File

@ -1,145 +0,0 @@
// Copyright (c) 2009 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 "base/gfx/gtk_native_view_id_manager.h"
#include "base/gfx/rect.h"
#include "base/logging.h"
#include "base/rand_util.h"
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
// -----------------------------------------------------------------------------
// Bounce functions for GTK to callback into a C++ object...
static void OnRealize(gfx::NativeView widget, void* arg) {
GtkNativeViewManager* manager = reinterpret_cast<GtkNativeViewManager*>(arg);
manager->OnRealize(widget);
}
static void OnUnrealize(gfx::NativeView widget, void *arg) {
GtkNativeViewManager* manager = reinterpret_cast<GtkNativeViewManager*>(arg);
manager->OnUnrealize(widget);
}
static void OnDestroy(GtkObject* obj, void* arg) {
GtkNativeViewManager* manager = reinterpret_cast<GtkNativeViewManager*>(arg);
manager->OnDestroy(reinterpret_cast<GtkWidget*>(obj));
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// Public functions...
GtkNativeViewManager::GtkNativeViewManager() {
}
gfx::NativeViewId GtkNativeViewManager::GetIdForWidget(gfx::NativeView widget) {
// This is just for unit tests:
if (!widget)
return 0;
AutoLock locked(lock_);
std::map<gfx::NativeView, gfx::NativeViewId>::const_iterator i =
native_view_to_id_.find(widget);
if (i != native_view_to_id_.end())
return i->second;
gfx::NativeViewId new_id =
static_cast<gfx::NativeViewId>(base::RandUint64());
while (id_to_info_.find(new_id) != id_to_info_.end())
new_id = static_cast<gfx::NativeViewId>(base::RandUint64());
NativeViewInfo info;
if (GTK_WIDGET_REALIZED(widget)) {
GdkWindow *gdk_window = widget->window;
CHECK(gdk_window);
info.x_window_id = GDK_WINDOW_XID(gdk_window);
}
native_view_to_id_[widget] = new_id;
id_to_info_[new_id] = info;
g_signal_connect(widget, "realize", G_CALLBACK(::OnRealize), this);
g_signal_connect(widget, "unrealize", G_CALLBACK(::OnUnrealize), this);
g_signal_connect(widget, "destroy", G_CALLBACK(::OnDestroy), this);
return new_id;
}
bool GtkNativeViewManager::GetXIDForId(XID* output, gfx::NativeViewId id) {
AutoLock locked(lock_);
std::map<gfx::NativeViewId, NativeViewInfo>::const_iterator i =
id_to_info_.find(id);
if (i == id_to_info_.end())
return false;
*output = i->second.x_window_id;
return true;
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// Private functions...
gfx::NativeViewId GtkNativeViewManager::GetWidgetId(gfx::NativeView widget) {
lock_.AssertAcquired();
std::map<gfx::NativeView, gfx::NativeViewId>::const_iterator i =
native_view_to_id_.find(widget);
CHECK(i != native_view_to_id_.end());
return i->second;
}
void GtkNativeViewManager::OnRealize(gfx::NativeView widget) {
AutoLock locked(lock_);
const gfx::NativeViewId id = GetWidgetId(widget);
std::map<gfx::NativeViewId, NativeViewInfo>::iterator i =
id_to_info_.find(id);
CHECK(i != id_to_info_.end());
CHECK(widget->window);
i->second.x_window_id = GDK_WINDOW_XID(widget->window);
}
void GtkNativeViewManager::OnUnrealize(gfx::NativeView widget) {
AutoLock locked(lock_);
const gfx::NativeViewId id = GetWidgetId(widget);
std::map<gfx::NativeViewId, NativeViewInfo>::iterator i =
id_to_info_.find(id);
CHECK(i != id_to_info_.end());
i->second.x_window_id = 0;
}
void GtkNativeViewManager::OnDestroy(gfx::NativeView widget) {
AutoLock locked(lock_);
std::map<gfx::NativeView, gfx::NativeViewId>::iterator i =
native_view_to_id_.find(widget);
CHECK(i != native_view_to_id_.end());
std::map<gfx::NativeViewId, NativeViewInfo>::iterator j =
id_to_info_.find(i->second);
CHECK(j != id_to_info_.end());
native_view_to_id_.erase(i);
id_to_info_.erase(j);
}
// -----------------------------------------------------------------------------

View File

@ -1,91 +0,0 @@
// Copyright (c) 2009 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.
#ifndef BASE_GFX_GTK_NATIVE_VIEW_ID_MANAGER_H_
#define BASE_GFX_GTK_NATIVE_VIEW_ID_MANAGER_H_
#include <map>
#include "base/singleton.h"
#include "base/gfx/native_widget_types.h"
typedef unsigned long XID;
// NativeViewIds are the opaque values which the renderer holds as a reference
// to a window. These ids are often used in sync calls from the renderer and
// one cannot terminate sync calls on the UI thread as that can lead to
// deadlocks.
//
// Because of this, we have the BACKGROUND_X11 thread for these calls and this
// thread has a separate X connection in order to answer them. But one cannot
// use GTK on multiple threads, so the BACKGROUND_X11 thread deals only in Xlib
// calls and, thus, XIDs.
//
// So we could make NativeViewIds be the X id of the window. However, at the
// time when we need to tell the renderer about its NativeViewId, an XID isn't
// availible and it goes very much against the grain of the code to make it so.
// Also, we worry that GTK might choose to change the underlying X window id
// when, say, the widget is hidden or repacked. Finally, if we used XIDs then a
// compromised renderer could start asking questions about any X windows on the
// system.
//
// Thus, we have this object. It produces random NativeViewIds from GtkWidget
// pointers and observes the various signals from the widget for when an X
// window is created, destroyed etc. Thus it provides a thread safe mapping
// from NativeViewIds to the current XID for that widget.
//
// You get a reference to the global instance with:
// Singleton<GtkNativeViewManager>()
class GtkNativeViewManager {
public:
// Must be called from the UI thread:
//
// Return a NativeViewId for the given widget and attach to the various
// signals emitted by that widget. The NativeViewId is pseudo-randomly
// allocated so that a compromised renderer trying to guess values will fail
// with high probability. The NativeViewId will not be reused for the
// lifetime of the GtkWidget.
gfx::NativeViewId GetIdForWidget(gfx::NativeView widget);
// May be called from any thread:
//
// xid: (output) the resulting X window ID, or 0
// id: a value previously returned from GetIdForWidget
// returns: true if |id| is a valid id, false otherwise.
//
// If the widget referenced by |id| does not current have an X window id,
// |*xid| is set to 0.
bool GetXIDForId(XID* xid, gfx::NativeViewId id);
// These are actually private functions, but need to be called from statics.
void OnRealize(gfx::NativeView widget);
void OnUnrealize(gfx::NativeView widget);
void OnDestroy(gfx::NativeView widget);
private:
// This object is a singleton:
GtkNativeViewManager();
friend struct DefaultSingletonTraits<GtkNativeViewManager>;
struct NativeViewInfo {
NativeViewInfo()
: x_window_id(0) {
}
XID x_window_id;
};
gfx::NativeViewId GetWidgetId(gfx::NativeView id);
// protects native_view_to_id_ and id_to_info_
Lock lock_;
// If asked for an id for the same widget twice, we want to return the same
// id. So this records the current mapping.
std::map<gfx::NativeView, gfx::NativeViewId> native_view_to_id_;
std::map<gfx::NativeViewId, NativeViewInfo> id_to_info_;
DISALLOW_COPY_AND_ASSIGN(GtkNativeViewManager);
};
#endif // BASE_GFX_GTK_NATIVE_VIEW_ID_MANAGER_H_

View File

@ -1,30 +0,0 @@
// Copyright (c) 2009 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 "base/gfx/gtk_util.h"
#include <gdk/gdk.h>
#include <gtk/gtk.h>
#include <stdlib.h>
#include "base/gfx/rect.h"
namespace gfx {
const GdkColor kGdkWhite = GDK_COLOR_RGB(0xff, 0xff, 0xff);
const GdkColor kGdkBlack = GDK_COLOR_RGB(0x00, 0x00, 0x00);
const GdkColor kGdkGreen = GDK_COLOR_RGB(0x00, 0xff, 0x00);
void SubtractRectanglesFromRegion(GdkRegion* region,
const std::vector<Rect>& cutouts) {
for (size_t i = 0; i < cutouts.size(); ++i) {
GdkRectangle rect = cutouts[i].ToGdkRectangle();
GdkRegion* rect_region = gdk_region_rectangle(&rect);
gdk_region_subtract(region, rect_region);
// TODO(deanm): It would be nice to be able to reuse the GdkRegion here.
gdk_region_destroy(rect_region);
}
}
} // namespace gfx

View File

@ -1,57 +0,0 @@
// Copyright (c) 2009 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.
#ifndef BASE_GFX_GTK_UTIL_H_
#define BASE_GFX_GTK_UTIL_H_
#include <stdint.h>
#include <vector>
#include <glib-object.h>
#include "base/scoped_ptr.h"
typedef struct _GdkColor GdkColor;
typedef struct _GdkRegion GdkRegion;
// Define a macro for creating GdkColors from RGB values. This is a macro to
// allow static construction of literals, etc. Use this like:
// GdkColor white = GDK_COLOR_RGB(0xff, 0xff, 0xff);
#define GDK_COLOR_RGB(r, g, b) {0, r * 257, g * 257, b * 257}
namespace gfx {
class Rect;
extern const GdkColor kGdkWhite;
extern const GdkColor kGdkBlack;
extern const GdkColor kGdkGreen;
// Modify the given region by subtracting the given rectangles.
void SubtractRectanglesFromRegion(GdkRegion* region,
const std::vector<Rect>& cutouts);
} // namespace gfx
namespace {
// A helper class that will g_object_unref |p| when it goes out of scope.
// This never adds a ref, it only unrefs.
template <typename Type>
struct GObjectUnrefer {
void operator()(Type* ptr) const {
if (ptr)
g_object_unref(ptr);
}
};
} // namespace
// It's not legal C++ to have a templatized typedefs, so we wrap it in a
// struct. When using this, you need to include ::Type. E.g.,
// ScopedGObject<GdkPixbufLoader>::Type loader(gdk_pixbuf_loader_new());
template<class T>
struct ScopedGObject {
typedef scoped_ptr_malloc<T, GObjectUnrefer<T> > Type;
};
#endif // BASE_GFX_GTK_UTIL_H_

View File

@ -1,523 +0,0 @@
// Copyright (c) 2006-2008 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 "base/gfx/jpeg_codec.h"
#include <setjmp.h>
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "skia/include/SkBitmap.h"
extern "C" {
#include "third_party/libjpeg/jpeglib.h"
}
// Encoder/decoder shared stuff ------------------------------------------------
namespace {
// used to pass error info through the JPEG library
struct CoderErrorMgr {
jpeg_error_mgr pub;
jmp_buf setjmp_buffer;
};
void ErrorExit(jpeg_common_struct* cinfo) {
CoderErrorMgr *err = reinterpret_cast<CoderErrorMgr*>(cinfo->err);
// Return control to the setjmp point.
longjmp(err->setjmp_buffer, false);
}
} // namespace
// Encoder ---------------------------------------------------------------------
//
// This code is based on nsJPEGEncoder from Mozilla.
// Copyright 2005 Google Inc. (Brett Wilson, contributor)
namespace {
// Initial size for the output buffer in the JpegEncoderState below.
const static int initial_output_buffer_size = 8192;
struct JpegEncoderState {
JpegEncoderState(std::vector<unsigned char>* o)
: out(o),
image_buffer_used(0) {
}
// Output buffer, of which 'image_buffer_used' bytes are actually used (this
// will often be less than the actual size of the vector because we size it
// so that libjpeg can write directly into it.
std::vector<unsigned char>* out;
// Number of bytes in the 'out' buffer that are actually used (see above).
size_t image_buffer_used;
};
// Initializes the JpegEncoderState for encoding, and tells libjpeg about where
// the output buffer is.
//
// From the JPEG library:
// "Initialize destination. This is called by jpeg_start_compress() before
// any data is actually written. It must initialize next_output_byte and
// free_in_buffer. free_in_buffer must be initialized to a positive value."
void InitDestination(jpeg_compress_struct* cinfo) {
JpegEncoderState* state = static_cast<JpegEncoderState*>(cinfo->client_data);
DCHECK(state->image_buffer_used == 0) << "initializing after use";
state->out->resize(initial_output_buffer_size);
state->image_buffer_used = 0;
cinfo->dest->next_output_byte = &(*state->out)[0];
cinfo->dest->free_in_buffer = initial_output_buffer_size;
}
// Resize the buffer that we give to libjpeg and update our and its state.
//
// From the JPEG library:
// "Callback used by libjpeg whenever the buffer has filled (free_in_buffer
// reaches zero). In typical applications, it should write out the *entire*
// buffer (use the saved start address and buffer length; ignore the current
// state of next_output_byte and free_in_buffer). Then reset the pointer &
// count to the start of the buffer, and return TRUE indicating that the
// buffer has been dumped. free_in_buffer must be set to a positive value
// when TRUE is returned. A FALSE return should only be used when I/O
// suspension is desired (this operating mode is discussed in the next
// section)."
boolean EmptyOutputBuffer(jpeg_compress_struct* cinfo) {
JpegEncoderState* state = static_cast<JpegEncoderState*>(cinfo->client_data);
// note the new size, the buffer is full
state->image_buffer_used = state->out->size();
// expand buffer, just double size each time
state->out->resize(state->out->size() * 2);
// tell libjpeg where to write the next data
cinfo->dest->next_output_byte = &(*state->out)[state->image_buffer_used];
cinfo->dest->free_in_buffer = state->out->size() - state->image_buffer_used;
return 1;
}
// Cleans up the JpegEncoderState to prepare for returning in the final form.
//
// From the JPEG library:
// "Terminate destination --- called by jpeg_finish_compress() after all data
// has been written. In most applications, this must flush any data
// remaining in the buffer. Use either next_output_byte or free_in_buffer to
// determine how much data is in the buffer."
void TermDestination(jpeg_compress_struct* cinfo) {
JpegEncoderState* state = static_cast<JpegEncoderState*>(cinfo->client_data);
DCHECK(state->out->size() >= state->image_buffer_used);
// update the used byte based on the next byte libjpeg would write to
state->image_buffer_used = cinfo->dest->next_output_byte - &(*state->out)[0];
DCHECK(state->image_buffer_used < state->out->size()) <<
"JPEG library busted, got a bad image buffer size";
// update our buffer so that it exactly encompases the desired data
state->out->resize(state->image_buffer_used);
}
// Converts RGBA to RGB (removing the alpha values) to prepare to send data to
// libjpeg. This converts one row of data in rgba with the given width in
// pixels the the given rgb destination buffer (which should have enough space
// reserved for the final data).
void StripAlpha(const unsigned char* rgba, int pixel_width, unsigned char* rgb)
{
for (int x = 0; x < pixel_width; x++) {
const unsigned char* pixel_in = &rgba[x * 4];
unsigned char* pixel_out = &rgb[x * 3];
pixel_out[0] = pixel_in[0];
pixel_out[1] = pixel_in[1];
pixel_out[2] = pixel_in[2];
}
}
// Converts BGRA to RGB by reordering the color components and dropping the
// alpha. This converts one row of data in rgba with the given width in
// pixels the the given rgb destination buffer (which should have enough space
// reserved for the final data).
void BGRAtoRGB(const unsigned char* bgra, int pixel_width, unsigned char* rgb)
{
for (int x = 0; x < pixel_width; x++) {
const unsigned char* pixel_in = &bgra[x * 4];
unsigned char* pixel_out = &rgb[x * 3];
pixel_out[0] = pixel_in[2];
pixel_out[1] = pixel_in[1];
pixel_out[2] = pixel_in[0];
}
}
// This class destroys the given jpeg_compress object when it goes out of
// scope. It simplifies the error handling in Encode (and even applies to the
// success case).
class CompressDestroyer {
public:
CompressDestroyer() : cinfo_(NULL) {
}
~CompressDestroyer() {
DestroyManagedObject();
}
void SetManagedObject(jpeg_compress_struct* ci) {
DestroyManagedObject();
cinfo_ = ci;
}
void DestroyManagedObject() {
if (cinfo_) {
jpeg_destroy_compress(cinfo_);
cinfo_ = NULL;
}
}
private:
jpeg_compress_struct* cinfo_;
};
} // namespace
bool JPEGCodec::Encode(const unsigned char* input, ColorFormat format,
int w, int h, int row_byte_width,
int quality, std::vector<unsigned char>* output) {
jpeg_compress_struct cinfo;
CompressDestroyer destroyer;
output->clear();
// We set up the normal JPEG error routines, then override error_exit.
// This must be done before the call to create_compress.
CoderErrorMgr errmgr;
cinfo.err = jpeg_std_error(&errmgr.pub);
errmgr.pub.error_exit = ErrorExit;
// Establish the setjmp return context for ErrorExit to use.
if (setjmp(errmgr.setjmp_buffer)) {
// If we get here, the JPEG code has signaled an error.
// MSDN notes: "if you intend your code to be portable, do not rely on
// correct destruction of frame-based objects when executing a nonlocal
// goto using a call to longjmp." So we delete the CompressDestroyer's
// object manually instead.
destroyer.DestroyManagedObject();
return false;
}
// The destroyer will destroy() cinfo on exit.
jpeg_create_compress(&cinfo);
destroyer.SetManagedObject(&cinfo);
cinfo.image_width = w;
cinfo.image_height = h;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
cinfo.data_precision = 8;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, quality, 1); // quality here is 0-100
// set up the destination manager
jpeg_destination_mgr destmgr;
destmgr.init_destination = InitDestination;
destmgr.empty_output_buffer = EmptyOutputBuffer;
destmgr.term_destination = TermDestination;
cinfo.dest = &destmgr;
JpegEncoderState state(output);
cinfo.client_data = &state;
jpeg_start_compress(&cinfo, 1);
// feed it the rows, doing necessary conversions for the color format
if (format == FORMAT_RGB) {
// no conversion necessary
while (cinfo.next_scanline < cinfo.image_height) {
const unsigned char* row = &input[cinfo.next_scanline * row_byte_width];
jpeg_write_scanlines(&cinfo, const_cast<unsigned char**>(&row), 1);
}
} else {
// get the correct format converter
void (*converter)(const unsigned char* in, int w, unsigned char* rgb);
if (format == FORMAT_RGBA) {
converter = StripAlpha;
} else if (format == FORMAT_BGRA) {
converter = BGRAtoRGB;
} else {
NOTREACHED() << "Invalid pixel format";
return false;
}
// output row after converting
unsigned char* row = new unsigned char[w * 3];
while (cinfo.next_scanline < cinfo.image_height) {
converter(&input[cinfo.next_scanline * row_byte_width], w, row);
jpeg_write_scanlines(&cinfo, &row, 1);
}
delete[] row;
}
jpeg_finish_compress(&cinfo);
return true;
}
// Decoder --------------------------------------------------------------------
namespace {
struct JpegDecoderState {
JpegDecoderState(const unsigned char* in, size_t len)
: input_buffer(in), input_buffer_length(len) {
}
const unsigned char* input_buffer;
size_t input_buffer_length;
};
// Callback to initialize the source.
//
// From the JPEG library:
// "Initialize source. This is called by jpeg_read_header() before any data is
// actually read. May leave bytes_in_buffer set to 0 (in which case a
// fill_input_buffer() call will occur immediately)."
void InitSource(j_decompress_ptr cinfo) {
JpegDecoderState* state = static_cast<JpegDecoderState*>(cinfo->client_data);
cinfo->src->next_input_byte = state->input_buffer;
cinfo->src->bytes_in_buffer = state->input_buffer_length;
}
// Callback to fill the buffer. Since our buffer already contains all the data,
// we should never need to provide more data. If libjpeg thinks it needs more
// data, our input is probably corrupt.
//
// From the JPEG library:
// "This is called whenever bytes_in_buffer has reached zero and more data is
// wanted. In typical applications, it should read fresh data into the buffer
// (ignoring the current state of next_input_byte and bytes_in_buffer), reset
// the pointer & count to the start of the buffer, and return TRUE indicating
// that the buffer has been reloaded. It is not necessary to fill the buffer
// entirely, only to obtain at least one more byte. bytes_in_buffer MUST be
// set to a positive value if TRUE is returned. A FALSE return should only
// be used when I/O suspension is desired."
boolean FillInputBuffer(j_decompress_ptr cinfo) {
return false;
}
// Skip data in the buffer. Since we have all the data at once, this operation
// is easy. It is not clear if this ever gets called because the JPEG library
// should be able to do the skip itself (it has all the data).
//
// From the JPEG library:
// "Skip num_bytes worth of data. The buffer pointer and count should be
// advanced over num_bytes input bytes, refilling the buffer as needed. This
// is used to skip over a potentially large amount of uninteresting data
// (such as an APPn marker). In some applications it may be possible to
// optimize away the reading of the skipped data, but it's not clear that
// being smart is worth much trouble; large skips are uncommon.
// bytes_in_buffer may be zero on return. A zero or negative skip count
// should be treated as a no-op."
void SkipInputData(j_decompress_ptr cinfo, long num_bytes) {
if (num_bytes > static_cast<long>(cinfo->src->bytes_in_buffer)) {
// Since all our data should be in the buffer, trying to skip beyond it
// means that there is some kind of error or corrupt input data. A 0 for
// bytes left means it will call FillInputBuffer which will then fail.
cinfo->src->next_input_byte += cinfo->src->bytes_in_buffer;
cinfo->src->bytes_in_buffer = 0;
} else if (num_bytes > 0) {
cinfo->src->bytes_in_buffer -= static_cast<size_t>(num_bytes);
cinfo->src->next_input_byte += num_bytes;
}
}
// Our source doesn't need any cleanup, so this is a NOP.
//
// From the JPEG library:
// "Terminate source --- called by jpeg_finish_decompress() after all data has
// been read to clean up JPEG source manager. NOT called by jpeg_abort() or
// jpeg_destroy()."
void TermSource(j_decompress_ptr cinfo) {
}
// Converts one row of rgb data to rgba data by adding a fully-opaque alpha
// value.
void AddAlpha(const unsigned char* rgb, int pixel_width, unsigned char* rgba) {
for (int x = 0; x < pixel_width; x++) {
const unsigned char* pixel_in = &rgb[x * 3];
unsigned char* pixel_out = &rgba[x * 4];
pixel_out[0] = pixel_in[0];
pixel_out[1] = pixel_in[1];
pixel_out[2] = pixel_in[2];
pixel_out[3] = 0xff;
}
}
// Converts one row of RGB data to BGRA by reordering the color components and
// adding alpha values of 0xff.
void RGBtoBGRA(const unsigned char* bgra, int pixel_width, unsigned char* rgb)
{
for (int x = 0; x < pixel_width; x++) {
const unsigned char* pixel_in = &bgra[x * 3];
unsigned char* pixel_out = &rgb[x * 4];
pixel_out[0] = pixel_in[2];
pixel_out[1] = pixel_in[1];
pixel_out[2] = pixel_in[0];
pixel_out[3] = 0xff;
}
}
// This class destroys the given jpeg_decompress object when it goes out of
// scope. It simplifies the error handling in Decode (and even applies to the
// success case).
class DecompressDestroyer {
public:
DecompressDestroyer() : cinfo_(NULL) {
}
~DecompressDestroyer() {
DestroyManagedObject();
}
void SetManagedObject(jpeg_decompress_struct* ci) {
DestroyManagedObject();
cinfo_ = ci;
}
void DestroyManagedObject() {
if (cinfo_) {
jpeg_destroy_decompress(cinfo_);
cinfo_ = NULL;
}
}
private:
jpeg_decompress_struct* cinfo_;
};
} // namespace
bool JPEGCodec::Decode(const unsigned char* input, size_t input_size,
ColorFormat format, std::vector<unsigned char>* output,
int* w, int* h) {
jpeg_decompress_struct cinfo;
DecompressDestroyer destroyer;
output->clear();
// We set up the normal JPEG error routines, then override error_exit.
// This must be done before the call to create_decompress.
CoderErrorMgr errmgr;
cinfo.err = jpeg_std_error(&errmgr.pub);
errmgr.pub.error_exit = ErrorExit;
// Establish the setjmp return context for ErrorExit to use.
if (setjmp(errmgr.setjmp_buffer)) {
// If we get here, the JPEG code has signaled an error.
// See note in JPEGCodec::Encode() for why we need to destroy the cinfo
// manually here.
destroyer.DestroyManagedObject();
return false;
}
// The destroyer will destroy() cinfo on exit. We don't want to set the
// destroyer's object until cinfo is initialized.
jpeg_create_decompress(&cinfo);
destroyer.SetManagedObject(&cinfo);
// set up the source manager
jpeg_source_mgr srcmgr;
srcmgr.init_source = InitSource;
srcmgr.fill_input_buffer = FillInputBuffer;
srcmgr.skip_input_data = SkipInputData;
srcmgr.resync_to_restart = jpeg_resync_to_restart; // use default routine
srcmgr.term_source = TermSource;
cinfo.src = &srcmgr;
JpegDecoderState state(input, input_size);
cinfo.client_data = &state;
// fill the file metadata into our buffer
if (jpeg_read_header(&cinfo, true) != JPEG_HEADER_OK)
return false;
// we want to always get RGB data out
switch (cinfo.jpeg_color_space) {
case JCS_GRAYSCALE:
case JCS_RGB:
case JCS_YCbCr:
cinfo.out_color_space = JCS_RGB;
break;
case JCS_CMYK:
case JCS_YCCK:
default:
// Mozilla errors out on these color spaces, so I presume that the jpeg
// library can't do automatic color space conversion for them. We don't
// care about these anyway.
return false;
}
cinfo.output_components = 3;
jpeg_calc_output_dimensions(&cinfo);
*w = cinfo.output_width;
*h = cinfo.output_height;
jpeg_start_decompress(&cinfo);
// FIXME(brettw) we may want to allow the capability for callers to request
// how to align row lengths as we do for the compressor.
int row_read_stride = cinfo.output_width * cinfo.output_components;
if (format == FORMAT_RGB) {
// easy case, row needs no conversion
int row_write_stride = row_read_stride;
output->resize(row_write_stride * cinfo.output_height);
for (int row = 0; row < static_cast<int>(cinfo.output_height); row++) {
unsigned char* rowptr = &(*output)[row * row_write_stride];
if (!jpeg_read_scanlines(&cinfo, &rowptr, 1))
return false;
}
} else {
// Rows need conversion to output format: read into a temporary buffer and
// expand to the final one. Performance: we could avoid the extra
// allocation by doing the expansion in-place.
int row_write_stride;
void (*converter)(const unsigned char* rgb, int w, unsigned char* out);
if (format == FORMAT_RGBA) {
row_write_stride = cinfo.output_width * 4;
converter = AddAlpha;
} else if (format == FORMAT_BGRA) {
row_write_stride = cinfo.output_width * 4;
converter = RGBtoBGRA;
} else {
NOTREACHED() << "Invalid pixel format";
jpeg_destroy_decompress(&cinfo);
return false;
}
output->resize(row_write_stride * cinfo.output_height);
scoped_array<unsigned char> row_data(new unsigned char[row_read_stride]);
unsigned char* rowptr = row_data.get();
for (int row = 0; row < static_cast<int>(cinfo.output_height); row++) {
if (!jpeg_read_scanlines(&cinfo, &rowptr, 1))
return false;
converter(rowptr, *w, &(*output)[row * row_write_stride]);
}
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
return true;
}
// static
SkBitmap* JPEGCodec::Decode(const unsigned char* input, size_t input_size) {
int w, h;
std::vector<unsigned char> data_vector;
// Use FORMAT_BGRA as that maps to Skia's 32 bit (kARGB_8888_Config) format.
if (!Decode(input, input_size, FORMAT_BGRA, &data_vector, &w, &h))
return NULL;
// Skia only handles 32 bit images.
int data_length = w * h * 4;
SkBitmap* bitmap = new SkBitmap();
bitmap->setConfig(SkBitmap::kARGB_8888_Config, w, h);
bitmap->allocPixels();
memcpy(bitmap->getAddr32(0, 0), &data_vector[0], data_length);
return bitmap;
}

View File

@ -1,59 +0,0 @@
// Copyright (c) 2006-2008 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.
#ifndef BASE_GFX_JPEG_CODEC_H_
#define BASE_GFX_JPEG_CODEC_H_
#include <vector>
class SkBitmap;
// Interface for encoding/decoding JPEG data. This is a wrapper around libjpeg,
// which has an inconvenient interface for callers. This is only used for UI
// elements, WebKit has its own more complicated JPEG decoder which handles,
// among other things, partially downloaded data.
class JPEGCodec {
public:
enum ColorFormat {
// 3 bytes per pixel (packed), in RGB order regardless of endianness.
// This is the native JPEG format.
FORMAT_RGB,
// 4 bytes per pixel, in RGBA order in mem regardless of endianness.
FORMAT_RGBA,
// 4 bytes per pixel, in BGRA order in mem regardless of endianness.
// This is the default Windows DIB order.
FORMAT_BGRA
};
// Encodes the given raw 'input' data, with each pixel being represented as
// given in 'format'. The encoded JPEG data will be written into the supplied
// vector and true will be returned on success. On failure (false), the
// contents of the output buffer are undefined.
//
// w, h: dimensions of the image
// row_byte_width: the width in bytes of each row. This may be greater than
// w * bytes_per_pixel if there is extra padding at the end of each row
// (often, each row is padded to the next machine word).
// quality: an integer in the range 0-100, where 100 is the highest quality.
static bool Encode(const unsigned char* input, ColorFormat format,
int w, int h, int row_byte_width,
int quality, std::vector<unsigned char>* output);
// Decodes the JPEG data contained in input of length input_size. The
// decoded data will be placed in *output with the dimensions in *w and *h
// on success (returns true). This data will be written in the'format'
// format. On failure, the values of these output variables is undefined.
static bool Decode(const unsigned char* input, size_t input_size,
ColorFormat format, std::vector<unsigned char>* output,
int* w, int* h);
// Decodes the JPEG data contained in input of length input_size. If
// successful, a SkBitmap is created and returned. It is up to the caller
// to delete the returned bitmap.
static SkBitmap* Decode(const unsigned char* input, size_t input_size);
};
#endif // BASE_GFX_JPEG_CODEC_H_

View File

@ -1,147 +0,0 @@
// Copyright (c) 2006-2008 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 <math.h>
#include "base/gfx/jpeg_codec.h"
#include "testing/gtest/include/gtest/gtest.h"
// out of 100, this indicates how compressed it will be, this should be changed
// with jpeg equality threshold
// static int jpeg_quality = 75; // FIXME(brettw)
static int jpeg_quality = 100;
// The threshold of average color differences where we consider two images
// equal. This number was picked to be a little above the observed difference
// using the above quality.
static double jpeg_equality_threshold = 1.0;
// Computes the average difference between each value in a and b. A and b
// should be the same size. Used to see if two images are approximately equal
// in the presence of compression.
static double AveragePixelDelta(const std::vector<unsigned char>& a,
const std::vector<unsigned char>& b) {
// if the sizes are different, say the average difference is the maximum
if (a.size() != b.size())
return 255.0;
if (a.size() == 0)
return 0; // prevent divide by 0 below
double acc = 0.0;
for (size_t i = 0; i < a.size(); i++)
acc += fabs(static_cast<double>(a[i]) - static_cast<double>(b[i]));
return acc / static_cast<double>(a.size());
}
static void MakeRGBImage(int w, int h, std::vector<unsigned char>* dat) {
dat->resize(w * h * 3);
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
unsigned char* org_px = &(*dat)[(y * w + x) * 3];
org_px[0] = x * 3; // r
org_px[1] = x * 3 + 1; // g
org_px[2] = x * 3 + 2; // b
}
}
}
TEST(JPEGCodec, EncodeDecodeRGB) {
int w = 20, h = 20;
// create an image with known values
std::vector<unsigned char> original;
MakeRGBImage(w, h, &original);
// encode, making sure it was compressed some
std::vector<unsigned char> encoded;
EXPECT_TRUE(JPEGCodec::Encode(&original[0], JPEGCodec::FORMAT_RGB, w, h,
w * 3, jpeg_quality, &encoded));
EXPECT_GT(original.size(), encoded.size());
// decode, it should have the same size as the original
std::vector<unsigned char> decoded;
int outw, outh;
EXPECT_TRUE(JPEGCodec::Decode(&encoded[0], encoded.size(),
JPEGCodec::FORMAT_RGB, &decoded,
&outw, &outh));
ASSERT_EQ(w, outw);
ASSERT_EQ(h, outh);
ASSERT_EQ(original.size(), decoded.size());
// Images must be approximately equal (compression will have introduced some
// minor artifacts).
ASSERT_GE(jpeg_equality_threshold, AveragePixelDelta(original, decoded));
}
TEST(JPEGCodec, EncodeDecodeRGBA) {
int w = 20, h = 20;
// create an image with known values, a must be opaque because it will be
// lost during compression
std::vector<unsigned char> original;
original.resize(w * h * 4);
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
unsigned char* org_px = &original[(y * w + x) * 4];
org_px[0] = x * 3; // r
org_px[1] = x * 3 + 1; // g
org_px[2] = x * 3 + 2; // b
org_px[3] = 0xFF; // a (opaque)
}
}
// encode, making sure it was compressed some
std::vector<unsigned char> encoded;
EXPECT_TRUE(JPEGCodec::Encode(&original[0], JPEGCodec::FORMAT_RGBA, w, h,
w * 4, jpeg_quality, &encoded));
EXPECT_GT(original.size(), encoded.size());
// decode, it should have the same size as the original
std::vector<unsigned char> decoded;
int outw, outh;
EXPECT_TRUE(JPEGCodec::Decode(&encoded[0], encoded.size(),
JPEGCodec::FORMAT_RGBA, &decoded,
&outw, &outh));
ASSERT_EQ(w, outw);
ASSERT_EQ(h, outh);
ASSERT_EQ(original.size(), decoded.size());
// Images must be approximately equal (compression will have introduced some
// minor artifacts).
ASSERT_GE(jpeg_equality_threshold, AveragePixelDelta(original, decoded));
}
// Test that corrupted data decompression causes failures.
TEST(JPEGCodec, DecodeCorrupted) {
int w = 20, h = 20;
// some random data (an uncompressed image)
std::vector<unsigned char> original;
MakeRGBImage(w, h, &original);
// it should fail when given non-JPEG compressed data
std::vector<unsigned char> output;
int outw, outh;
ASSERT_FALSE(JPEGCodec::Decode(&original[0], original.size(),
JPEGCodec::FORMAT_RGB, &output,
&outw, &outh));
// make some compressed data
std::vector<unsigned char> compressed;
ASSERT_TRUE(JPEGCodec::Encode(&original[0], JPEGCodec::FORMAT_RGB, w, h,
w * 3, jpeg_quality, &compressed));
// try decompressing a truncated version
ASSERT_FALSE(JPEGCodec::Decode(&compressed[0], compressed.size() / 2,
JPEGCodec::FORMAT_RGB, &output,
&outw, &outh));
// corrupt it and try decompressing that
for (int i = 10; i < 30; i++)
compressed[i] = i;
ASSERT_FALSE(JPEGCodec::Decode(&compressed[0], compressed.size(),
JPEGCodec::FORMAT_RGB, &output,
&outw, &outh));
}

View File

@ -1,710 +0,0 @@
// Copyright (c) 2006-2008 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 "base/gfx/native_theme.h"
#include <windows.h>
#include <uxtheme.h>
#include <vsstyle.h>
#include <vssym32.h>
#include "base/gfx/gdi_util.h"
#include "base/gfx/rect.h"
#include "base/logging.h"
#include "base/scoped_handle.h"
#include "skia/ext/platform_canvas.h"
#include "skia/ext/skia_utils_win.h"
#include "skia/include/SkShader.h"
namespace {
void SetCheckerboardShader(SkPaint* paint, const RECT& align_rect) {
// Create a 2x2 checkerboard pattern using the 3D face and highlight colors.
SkColor face = skia::COLORREFToSkColor(GetSysColor(COLOR_3DFACE));
SkColor highlight = skia::COLORREFToSkColor(GetSysColor(COLOR_3DHILIGHT));
SkColor buffer[] = { face, highlight, highlight, face };
// Confusing bit: we first create a temporary bitmap with our desired pattern,
// then copy it to another bitmap. The temporary bitmap doesn't take
// ownership of the pixel data, and so will point to garbage when this
// function returns. The copy will copy the pixel data into a place owned by
// the bitmap, which is in turn owned by the shader, etc., so it will live
// until we're done using it.
SkBitmap temp_bitmap;
temp_bitmap.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
temp_bitmap.setPixels(buffer);
SkBitmap bitmap;
temp_bitmap.copyTo(&bitmap, temp_bitmap.config());
SkShader* shader = SkShader::CreateBitmapShader(bitmap,
SkShader::kRepeat_TileMode,
SkShader::kRepeat_TileMode);
// Align the pattern with the upper corner of |align_rect|.
SkMatrix matrix;
matrix.setTranslate(SkIntToScalar(align_rect.left),
SkIntToScalar(align_rect.top));
shader->setLocalMatrix(matrix);
paint->setShader(shader)->safeUnref();
}
} // namespace
namespace gfx {
/* static */
const NativeTheme* NativeTheme::instance() {
// The global NativeTheme instance.
static const NativeTheme s_native_theme;
return &s_native_theme;
}
NativeTheme::NativeTheme()
: theme_dll_(LoadLibrary(L"uxtheme.dll")),
draw_theme_(NULL),
draw_theme_ex_(NULL),
get_theme_color_(NULL),
get_theme_content_rect_(NULL),
get_theme_part_size_(NULL),
open_theme_(NULL),
close_theme_(NULL),
set_theme_properties_(NULL),
is_theme_active_(NULL),
get_theme_int_(NULL) {
if (theme_dll_) {
draw_theme_ = reinterpret_cast<DrawThemeBackgroundPtr>(
GetProcAddress(theme_dll_, "DrawThemeBackground"));
draw_theme_ex_ = reinterpret_cast<DrawThemeBackgroundExPtr>(
GetProcAddress(theme_dll_, "DrawThemeBackgroundEx"));
get_theme_color_ = reinterpret_cast<GetThemeColorPtr>(
GetProcAddress(theme_dll_, "GetThemeColor"));
get_theme_content_rect_ = reinterpret_cast<GetThemeContentRectPtr>(
GetProcAddress(theme_dll_, "GetThemeBackgroundContentRect"));
get_theme_part_size_ = reinterpret_cast<GetThemePartSizePtr>(
GetProcAddress(theme_dll_, "GetThemePartSize"));
open_theme_ = reinterpret_cast<OpenThemeDataPtr>(
GetProcAddress(theme_dll_, "OpenThemeData"));
close_theme_ = reinterpret_cast<CloseThemeDataPtr>(
GetProcAddress(theme_dll_, "CloseThemeData"));
set_theme_properties_ = reinterpret_cast<SetThemeAppPropertiesPtr>(
GetProcAddress(theme_dll_, "SetThemeAppProperties"));
is_theme_active_ = reinterpret_cast<IsThemeActivePtr>(
GetProcAddress(theme_dll_, "IsThemeActive"));
get_theme_int_ = reinterpret_cast<GetThemeIntPtr>(
GetProcAddress(theme_dll_, "GetThemeInt"));
}
memset(theme_handles_, 0, sizeof(theme_handles_));
}
NativeTheme::~NativeTheme() {
if (theme_dll_) {
// todo (cpu): fix this soon.
// CloseHandles();
FreeLibrary(theme_dll_);
}
}
HRESULT NativeTheme::PaintButton(HDC hdc,
int part_id,
int state_id,
int classic_state,
RECT* rect) const {
HANDLE handle = GetThemeHandle(BUTTON);
if (handle && draw_theme_)
return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
// Draw it manually.
// All pressed states have both low bits set, and no other states do.
const bool focused = ((state_id & ETS_FOCUSED) == ETS_FOCUSED);
const bool pressed = ((state_id & PBS_PRESSED) == PBS_PRESSED);
if ((BP_PUSHBUTTON == part_id) && (pressed || focused)) {
// BP_PUSHBUTTON has a focus rect drawn around the outer edge, and the
// button itself is shrunk by 1 pixel.
HBRUSH brush = GetSysColorBrush(COLOR_3DDKSHADOW);
if (brush) {
FrameRect(hdc, rect, brush);
InflateRect(rect, -1, -1);
}
}
DrawFrameControl(hdc, rect, DFC_BUTTON, classic_state);
// Draw the focus rectangle (the dotted line box) only on buttons. For radio
// and checkboxes, we let webkit draw the focus rectangle (orange glow).
if ((BP_PUSHBUTTON == part_id) && focused) {
// The focus rect is inside the button. The exact number of pixels depends
// on whether we're in classic mode or using uxtheme.
if (handle && get_theme_content_rect_) {
get_theme_content_rect_(handle, hdc, part_id, state_id, rect, rect);
} else {
InflateRect(rect, -GetSystemMetrics(SM_CXEDGE),
-GetSystemMetrics(SM_CYEDGE));
}
DrawFocusRect(hdc, rect);
}
return S_OK;
}
HRESULT NativeTheme::PaintDialogBackground(HDC hdc, bool active,
RECT* rect) const {
HANDLE handle = GetThemeHandle(WINDOW);
if (handle && draw_theme_) {
return draw_theme_(handle, hdc, WP_DIALOG,
active ? FS_ACTIVE : FS_INACTIVE, rect, NULL);
}
// Classic just renders a flat color background.
FillRect(hdc, rect, reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1));
return S_OK;
}
HRESULT NativeTheme::PaintListBackground(HDC hdc,
bool enabled,
RECT* rect) const {
HANDLE handle = GetThemeHandle(LIST);
if (handle && draw_theme_)
return draw_theme_(handle, hdc, 1, TS_NORMAL, rect, NULL);
// Draw it manually.
HBRUSH bg_brush = GetSysColorBrush(COLOR_WINDOW);
FillRect(hdc, rect, bg_brush);
DrawEdge(hdc, rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
return S_OK;
}
HRESULT NativeTheme::PaintMenuArrow(ThemeName theme,
HDC hdc,
int part_id,
int state_id,
RECT* rect,
MenuArrowDirection arrow_direction,
bool is_highlighted) const {
HANDLE handle = GetThemeHandle(MENU);
if (handle && draw_theme_) {
if (arrow_direction == RIGHT_POINTING_ARROW) {
return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
} else {
// There is no way to tell the uxtheme API to draw a left pointing arrow;
// it doesn't have a flag equivalent to DFCS_MENUARROWRIGHT. But they
// are needed for RTL locales on Vista. So use a memory DC and mirror
// the region with GDI's StretchBlt.
Rect r(*rect);
ScopedHDC mem_dc(CreateCompatibleDC(hdc));
ScopedBitmap mem_bitmap(CreateCompatibleBitmap(hdc, r.width(),
r.height()));
HGDIOBJ old_bitmap = SelectObject(mem_dc, mem_bitmap);
// Copy and horizontally mirror the background from hdc into mem_dc. Use
// a negative-width source rect, starting at the rightmost pixel.
StretchBlt(mem_dc, 0, 0, r.width(), r.height(),
hdc, r.right()-1, r.y(), -r.width(), r.height(), SRCCOPY);
// Draw the arrow.
RECT theme_rect = {0, 0, r.width(), r.height()};
HRESULT result = draw_theme_(handle, mem_dc, part_id,
state_id, &theme_rect, NULL);
// Copy and mirror the result back into mem_dc.
StretchBlt(hdc, r.x(), r.y(), r.width(), r.height(),
mem_dc, r.width()-1, 0, -r.width(), r.height(), SRCCOPY);
SelectObject(mem_dc, old_bitmap);
return result;
}
}
// For some reason, Windows uses the name DFCS_MENUARROWRIGHT to indicate a
// left pointing arrow. This makes the following 'if' statement slightly
// counterintuitive.
UINT state;
if (arrow_direction == RIGHT_POINTING_ARROW)
state = DFCS_MENUARROW;
else
state = DFCS_MENUARROWRIGHT;
return PaintFrameControl(hdc, rect, DFC_MENU, state, is_highlighted);
}
HRESULT NativeTheme::PaintMenuBackground(ThemeName theme,
HDC hdc,
int part_id,
int state_id,
RECT* rect) const {
HANDLE handle = GetThemeHandle(MENU);
if (handle && draw_theme_) {
HRESULT result = draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
FrameRect(hdc, rect, GetSysColorBrush(COLOR_3DSHADOW));
return result;
}
FillRect(hdc, rect, GetSysColorBrush(COLOR_MENU));
DrawEdge(hdc, rect, EDGE_RAISED, BF_RECT);
return S_OK;
}
HRESULT NativeTheme::PaintMenuCheckBackground(ThemeName theme,
HDC hdc,
int part_id,
int state_id,
RECT* rect) const {
HANDLE handle = GetThemeHandle(MENU);
if (handle && draw_theme_)
return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
// Nothing to do for background.
return S_OK;
}
HRESULT NativeTheme::PaintMenuCheck(ThemeName theme,
HDC hdc,
int part_id,
int state_id,
RECT* rect,
bool is_highlighted) const {
HANDLE handle = GetThemeHandle(MENU);
if (handle && draw_theme_) {
return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
}
return PaintFrameControl(hdc, rect, DFC_MENU, DFCS_MENUCHECK, is_highlighted);
}
HRESULT NativeTheme::PaintMenuGutter(HDC hdc,
int part_id,
int state_id,
RECT* rect) const {
HANDLE handle = GetThemeHandle(MENU);
if (handle && draw_theme_)
return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
return E_NOTIMPL;
}
HRESULT NativeTheme::PaintMenuItemBackground(ThemeName theme,
HDC hdc,
int part_id,
int state_id,
bool selected,
RECT* rect) const {
HANDLE handle = GetThemeHandle(MENU);
if (handle && draw_theme_)
return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
if (selected)
FillRect(hdc, rect, GetSysColorBrush(COLOR_HIGHLIGHT));
return S_OK;
}
HRESULT NativeTheme::PaintMenuList(HDC hdc,
int part_id,
int state_id,
int classic_state,
RECT* rect) const {
HANDLE handle = GetThemeHandle(MENULIST);
if (handle && draw_theme_)
return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
// Draw it manually.
DrawFrameControl(hdc, rect, DFC_SCROLL, DFCS_SCROLLCOMBOBOX | classic_state);
return S_OK;
}
HRESULT NativeTheme::PaintMenuSeparator(HDC hdc,
int part_id,
int state_id,
RECT* rect) const {
HANDLE handle = GetThemeHandle(MENU);
if (handle && draw_theme_)
return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
DrawEdge(hdc, rect, EDGE_ETCHED, BF_TOP);
return S_OK;
}
HRESULT NativeTheme::PaintScrollbarArrow(HDC hdc,
int state_id,
int classic_state,
RECT* rect) const {
HANDLE handle = GetThemeHandle(SCROLLBAR);
if (handle && draw_theme_)
return draw_theme_(handle, hdc, SBP_ARROWBTN, state_id, rect, NULL);
// Draw it manually.
DrawFrameControl(hdc, rect, DFC_SCROLL, classic_state);
return S_OK;
}
HRESULT NativeTheme::PaintScrollbarTrack(
HDC hdc,
int part_id,
int state_id,
int classic_state,
RECT* target_rect,
RECT* align_rect,
skia::PlatformCanvasWin* canvas) const {
HANDLE handle = GetThemeHandle(SCROLLBAR);
if (handle && draw_theme_)
return draw_theme_(handle, hdc, part_id, state_id, target_rect, NULL);
// Draw it manually.
const DWORD colorScrollbar = GetSysColor(COLOR_SCROLLBAR);
const DWORD color3DFace = GetSysColor(COLOR_3DFACE);
if ((colorScrollbar != color3DFace) &&
(colorScrollbar != GetSysColor(COLOR_WINDOW))) {
FillRect(hdc, target_rect, reinterpret_cast<HBRUSH>(COLOR_SCROLLBAR + 1));
} else {
SkPaint paint;
SetCheckerboardShader(&paint, *align_rect);
canvas->drawIRect(skia::RECTToSkIRect(*target_rect), paint);
}
if (classic_state & DFCS_PUSHED)
InvertRect(hdc, target_rect);
return S_OK;
}
HRESULT NativeTheme::PaintScrollbarThumb(HDC hdc,
int part_id,
int state_id,
int classic_state,
RECT* rect) const {
HANDLE handle = GetThemeHandle(SCROLLBAR);
if (handle && draw_theme_)
return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
// Draw it manually.
if ((part_id == SBP_THUMBBTNHORZ) || (part_id == SBP_THUMBBTNVERT))
DrawEdge(hdc, rect, EDGE_RAISED, BF_RECT | BF_MIDDLE);
// Classic mode doesn't have a gripper.
return S_OK;
}
HRESULT NativeTheme::PaintStatusGripper(HDC hdc,
int part_id,
int state_id,
int classic_state,
RECT* rect) const {
HANDLE handle = GetThemeHandle(STATUS);
if (handle && draw_theme_) {
// Paint the status bar gripper. There doesn't seem to be a
// standard gripper in Windows for the space between
// scrollbars. This is pretty close, but it's supposed to be
// painted over a status bar.
return draw_theme_(handle, hdc, SP_GRIPPER, 0, rect, NULL);
}
// Draw a windows classic scrollbar gripper.
DrawFrameControl(hdc, rect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
return S_OK;
}
HRESULT NativeTheme::PaintTabPanelBackground(HDC hdc, RECT* rect) const {
HANDLE handle = GetThemeHandle(TAB);
if (handle && draw_theme_)
return draw_theme_(handle, hdc, TABP_BODY, 0, rect, NULL);
// Classic just renders a flat color background.
FillRect(hdc, rect, reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1));
return S_OK;
}
HRESULT NativeTheme::PaintTrackbar(HDC hdc,
int part_id,
int state_id,
int classic_state,
RECT* rect,
skia::PlatformCanvasWin* canvas) const {
// Make the channel be 4 px thick in the center of the supplied rect. (4 px
// matches what XP does in various menus; GetThemePartSize() doesn't seem to
// return good values here.)
RECT channel_rect = *rect;
const int channel_thickness = 4;
if (part_id == TKP_TRACK) {
channel_rect.top +=
((channel_rect.bottom - channel_rect.top - channel_thickness) / 2);
channel_rect.bottom = channel_rect.top + channel_thickness;
} else if (part_id == TKP_TRACKVERT) {
channel_rect.left +=
((channel_rect.right - channel_rect.left - channel_thickness) / 2);
channel_rect.right = channel_rect.left + channel_thickness;
} // else this isn't actually a channel, so |channel_rect| == |rect|.
HANDLE handle = GetThemeHandle(TRACKBAR);
if (handle && draw_theme_)
return draw_theme_(handle, hdc, part_id, state_id, &channel_rect, NULL);
// Classic mode, draw it manually.
if ((part_id == TKP_TRACK) || (part_id == TKP_TRACKVERT)) {
DrawEdge(hdc, &channel_rect, EDGE_SUNKEN, BF_RECT);
} else if (part_id == TKP_THUMBVERT) {
DrawEdge(hdc, rect, EDGE_RAISED, BF_RECT | BF_SOFT | BF_MIDDLE);
} else {
// Split rect into top and bottom pieces.
RECT top_section = *rect;
RECT bottom_section = *rect;
top_section.bottom -= ((bottom_section.right - bottom_section.left) / 2);
bottom_section.top = top_section.bottom;
DrawEdge(hdc, &top_section, EDGE_RAISED,
BF_LEFT | BF_TOP | BF_RIGHT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
// Split triangular piece into two diagonals.
RECT& left_half = bottom_section;
RECT right_half = bottom_section;
right_half.left += ((bottom_section.right - bottom_section.left) / 2);
left_half.right = right_half.left;
DrawEdge(hdc, &left_half, EDGE_RAISED,
BF_DIAGONAL_ENDTOPLEFT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
DrawEdge(hdc, &right_half, EDGE_RAISED,
BF_DIAGONAL_ENDBOTTOMLEFT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
// If the button is pressed, draw hatching.
if (classic_state & DFCS_PUSHED) {
SkPaint paint;
SetCheckerboardShader(&paint, *rect);
// Fill all three pieces with the pattern.
canvas->drawIRect(skia::RECTToSkIRect(top_section), paint);
SkScalar left_triangle_top = SkIntToScalar(left_half.top);
SkScalar left_triangle_right = SkIntToScalar(left_half.right);
SkPath left_triangle;
left_triangle.moveTo(SkIntToScalar(left_half.left), left_triangle_top);
left_triangle.lineTo(left_triangle_right, left_triangle_top);
left_triangle.lineTo(left_triangle_right,
SkIntToScalar(left_half.bottom));
left_triangle.close();
canvas->drawPath(left_triangle, paint);
SkScalar right_triangle_left = SkIntToScalar(right_half.left);
SkScalar right_triangle_top = SkIntToScalar(right_half.top);
SkPath right_triangle;
right_triangle.moveTo(right_triangle_left, right_triangle_top);
right_triangle.lineTo(SkIntToScalar(right_half.right),
right_triangle_top);
right_triangle.lineTo(right_triangle_left,
SkIntToScalar(right_half.bottom));
right_triangle.close();
canvas->drawPath(right_triangle, paint);
}
}
return S_OK;
}
HRESULT NativeTheme::PaintTextField(HDC hdc,
int part_id,
int state_id,
int classic_state,
RECT* rect,
COLORREF color,
bool fill_content_area,
bool draw_edges) const {
// TODO(ojan): http://b/1210017 Figure out how to give the ability to
// exclude individual edges from being drawn.
HANDLE handle = GetThemeHandle(TEXTFIELD);
// TODO(mpcomplete): can we detect if the color is specified by the user,
// and if not, just use the system color?
// CreateSolidBrush() accepts a RGB value but alpha must be 0.
HBRUSH bg_brush = CreateSolidBrush(color);
HRESULT hr;
// DrawThemeBackgroundEx was introduced in XP SP2, so that it's possible
// draw_theme_ex_ is NULL and draw_theme_ is non-null.
if (handle && (draw_theme_ex_ || (draw_theme_ && draw_edges))) {
if (draw_theme_ex_) {
static DTBGOPTS omit_border_options = {
sizeof(DTBGOPTS),
DTBG_OMITBORDER,
{0,0,0,0}
};
DTBGOPTS* draw_opts = draw_edges ? NULL : &omit_border_options;
hr = draw_theme_ex_(handle, hdc, part_id, state_id, rect, draw_opts);
} else {
hr = draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
}
// TODO(maruel): Need to be fixed if get_theme_content_rect_ is NULL.
if (fill_content_area && get_theme_content_rect_) {
RECT content_rect;
hr = get_theme_content_rect_(handle, hdc, part_id, state_id, rect,
&content_rect);
FillRect(hdc, &content_rect, bg_brush);
}
} else {
// Draw it manually.
if (draw_edges)
DrawEdge(hdc, rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
if (fill_content_area) {
FillRect(hdc, rect, (classic_state & DFCS_INACTIVE) ?
reinterpret_cast<HBRUSH>(COLOR_BTNFACE + 1) : bg_brush);
}
hr = S_OK;
}
DeleteObject(bg_brush);
return hr;
}
bool NativeTheme::IsThemingActive() const {
if (is_theme_active_)
return !!is_theme_active_();
return false;
}
HRESULT NativeTheme::GetThemePartSize(ThemeName theme_name,
HDC hdc,
int part_id,
int state_id,
RECT* rect,
int ts,
SIZE* size) const {
HANDLE handle = GetThemeHandle(theme_name);
if (handle && get_theme_part_size_)
return get_theme_part_size_(handle, hdc, part_id, state_id, rect, ts, size);
return E_NOTIMPL;
}
HRESULT NativeTheme::GetThemeColor(ThemeName theme,
int part_id,
int state_id,
int prop_id,
SkColor* color) const {
HANDLE handle = GetThemeHandle(theme);
if (handle && get_theme_color_) {
COLORREF color_ref;
if (get_theme_color_(handle, part_id, state_id, prop_id, &color_ref) ==
S_OK) {
*color = skia::COLORREFToSkColor(color_ref);
return S_OK;
}
}
return E_NOTIMPL;
}
SkColor NativeTheme::GetThemeColorWithDefault(ThemeName theme,
int part_id,
int state_id,
int prop_id,
int default_sys_color) const {
SkColor color;
if (GetThemeColor(theme, part_id, state_id, prop_id, &color) != S_OK)
color = skia::COLORREFToSkColor(GetSysColor(default_sys_color));
return color;
}
HRESULT NativeTheme::GetThemeInt(ThemeName theme,
int part_id,
int state_id,
int prop_id,
int *value) const {
HANDLE handle = GetThemeHandle(theme);
if (handle && get_theme_int_)
return get_theme_int_(handle, part_id, state_id, prop_id, value);
return E_NOTIMPL;
}
Size NativeTheme::GetThemeBorderSize(ThemeName theme) const {
// For simplicity use the wildcard state==0, part==0, since it works
// for the cases we currently depend on.
int border;
if (GetThemeInt(theme, 0, 0, TMT_BORDERSIZE, &border) == S_OK)
return Size(border, border);
else
return Size(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
}
void NativeTheme::DisableTheming() const {
if (!set_theme_properties_)
return;
set_theme_properties_(0);
}
HRESULT NativeTheme::PaintFrameControl(HDC hdc,
RECT* rect,
UINT type,
UINT state,
bool is_highlighted) const {
const int width = rect->right - rect->left;
const int height = rect->bottom - rect->top;
// DrawFrameControl for menu arrow/check wants a monochrome bitmap.
ScopedBitmap mask_bitmap(CreateBitmap(width, height, 1, 1, NULL));
if (mask_bitmap == NULL)
return E_OUTOFMEMORY;
ScopedHDC bitmap_dc(CreateCompatibleDC(NULL));
HGDIOBJ org_bitmap = SelectObject(bitmap_dc, mask_bitmap);
RECT local_rect = { 0, 0, width, height };
DrawFrameControl(bitmap_dc, &local_rect, type, state);
// We're going to use BitBlt with a b&w mask. This results in using the dest
// dc's text color for the black bits in the mask, and the dest dc's
// background color for the white bits in the mask. DrawFrameControl draws the
// check in black, and the background in white.
COLORREF old_bg_color =
SetBkColor(hdc,
GetSysColor(is_highlighted ? COLOR_HIGHLIGHT : COLOR_MENU));
COLORREF old_text_color =
SetTextColor(hdc,
GetSysColor(is_highlighted ? COLOR_HIGHLIGHTTEXT :
COLOR_MENUTEXT));
BitBlt(hdc, rect->left, rect->top, width, height, bitmap_dc, 0, 0, SRCCOPY);
SetBkColor(hdc, old_bg_color);
SetTextColor(hdc, old_text_color);
SelectObject(bitmap_dc, org_bitmap);
return S_OK;
}
void NativeTheme::CloseHandles() const
{
if (!close_theme_)
return;
for (int i = 0; i < LAST; ++i) {
if (theme_handles_[i])
close_theme_(theme_handles_[i]);
theme_handles_[i] = NULL;
}
}
HANDLE NativeTheme::GetThemeHandle(ThemeName theme_name) const
{
if (!open_theme_ || theme_name < 0 || theme_name >= LAST)
return 0;
if (theme_handles_[theme_name])
return theme_handles_[theme_name];
// Not found, try to load it.
HANDLE handle = 0;
switch (theme_name) {
case BUTTON:
handle = open_theme_(NULL, L"Button");
break;
case LIST:
handle = open_theme_(NULL, L"Listview");
break;
case MENU:
handle = open_theme_(NULL, L"Menu");
break;
case MENULIST:
handle = open_theme_(NULL, L"Combobox");
break;
case SCROLLBAR:
handle = open_theme_(NULL, L"Scrollbar");
break;
case STATUS:
handle = open_theme_(NULL, L"Status");
break;
case TAB:
handle = open_theme_(NULL, L"Tab");
break;
case TEXTFIELD:
handle = open_theme_(NULL, L"Edit");
break;
case TRACKBAR:
handle = open_theme_(NULL, L"Trackbar");
break;
case WINDOW:
handle = open_theme_(NULL, L"Window");
break;
default:
NOTREACHED();
}
theme_handles_[theme_name] = handle;
return handle;
}
} // namespace gfx

View File

@ -1,296 +0,0 @@
// Copyright (c) 2006-2008 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.
//
// A wrapper class for working with custom XP/Vista themes provided in
// uxtheme.dll. This is a singleton class that can be grabbed using
// NativeTheme::instance().
// For more information on visual style parts and states, see:
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/userex/topics/partsandstates.asp
#ifndef BASE_GFX_NATIVE_THEME_H__
#define BASE_GFX_NATIVE_THEME_H__
#include <windows.h>
#include <uxtheme.h>
#include "base/basictypes.h"
#include "base/gfx/size.h"
#include "skia/include/SkColor.h"
namespace skia {
class PlatformCanvasWin;
} // namespace skia
namespace gfx {
// TODO: Define class member enums to replace part_id and state_id parameters
// that are currently defined in <vssym32.h>. Afterward, classic_state should
// be removed and class users wouldn't need to include <vssym32.h> anymore.
// This would enable HOT state on non-themed UI (like when RDP'ing) and would
// simplify usage.
// TODO: This class should probably be changed to be platform independent at
// the same time.
class NativeTheme {
public:
enum ThemeName {
BUTTON,
LIST,
MENU,
MENULIST,
SCROLLBAR,
STATUS,
TAB,
TEXTFIELD,
TRACKBAR,
WINDOW,
LAST
};
// This enumeration is used within PaintMenuArrow in order to indicate the
// direction the menu arrow should point to.
enum MenuArrowDirection {
LEFT_POINTING_ARROW,
RIGHT_POINTING_ARROW
};
typedef HRESULT (WINAPI* DrawThemeBackgroundPtr)(HANDLE theme,
HDC hdc,
int part_id,
int state_id,
const RECT* rect,
const RECT* clip_rect);
typedef HRESULT (WINAPI* DrawThemeBackgroundExPtr)(HANDLE theme,
HDC hdc,
int part_id,
int state_id,
const RECT* rect,
const DTBGOPTS* opts);
typedef HRESULT (WINAPI* GetThemeColorPtr)(HANDLE hTheme,
int part_id,
int state_id,
int prop_id,
COLORREF* color);
typedef HRESULT (WINAPI* GetThemeContentRectPtr)(HANDLE hTheme,
HDC hdc,
int part_id,
int state_id,
const RECT* rect,
RECT* content_rect);
typedef HRESULT (WINAPI* GetThemePartSizePtr)(HANDLE hTheme,
HDC hdc,
int part_id,
int state_id,
RECT* rect,
int ts,
SIZE* size);
typedef HANDLE (WINAPI* OpenThemeDataPtr)(HWND window,
LPCWSTR class_list);
typedef HRESULT (WINAPI* CloseThemeDataPtr)(HANDLE theme);
typedef void (WINAPI* SetThemeAppPropertiesPtr) (DWORD flags);
typedef BOOL (WINAPI* IsThemeActivePtr)();
typedef HRESULT (WINAPI* GetThemeIntPtr)(HANDLE hTheme,
int part_id,
int state_id,
int prop_id,
int *value);
HRESULT PaintButton(HDC hdc,
int part_id,
int state_id,
int classic_state,
RECT* rect) const;
HRESULT PaintDialogBackground(HDC dc, bool active, RECT* rect) const;
HRESULT PaintListBackground(HDC dc, bool enabled, RECT* rect) const;
// |arrow_direction| determines whether the arrow is pointing to the left or
// to the right. In RTL locales, sub-menus open from right to left and
// therefore the menu arrow should point to the left and not to the right.
HRESULT PaintMenuArrow(ThemeName theme,
HDC hdc,
int part_id,
int state_id,
RECT* rect,
MenuArrowDirection arrow_direction,
bool is_highlighted) const;
HRESULT PaintMenuBackground(ThemeName theme,
HDC hdc,
int part_id,
int state_id,
RECT* rect) const;
HRESULT PaintMenuCheck(ThemeName theme,
HDC hdc,
int part_id,
int state_id,
RECT* rect,
bool is_highlighted) const;
HRESULT PaintMenuCheckBackground(ThemeName theme,
HDC hdc,
int part_id,
int state_id,
RECT* rect) const;
HRESULT PaintMenuGutter(HDC hdc,
int part_id,
int state_id,
RECT* rect) const;
HRESULT PaintMenuItemBackground(ThemeName theme,
HDC hdc,
int part_id,
int state_id,
bool selected,
RECT* rect) const;
HRESULT PaintMenuList(HDC hdc,
int part_id,
int state_id,
int classic_state,
RECT* rect) const;
HRESULT PaintMenuSeparator(HDC hdc,
int part_id,
int state_id,
RECT* rect) const;
// Paints a scrollbar arrow. |classic_state| should have the appropriate
// classic part number ORed in already.
HRESULT PaintScrollbarArrow(HDC hdc,
int state_id,
int classic_state,
RECT* rect) const;
// Paints a scrollbar track section. |align_rect| is only used in classic
// mode, and makes sure the checkerboard pattern in |target_rect| is aligned
// with one presumed to be in |align_rect|.
HRESULT PaintScrollbarTrack(HDC hdc,
int part_id,
int state_id,
int classic_state,
RECT* target_rect,
RECT* align_rect,
skia::PlatformCanvasWin* canvas) const;
// Paints a scrollbar thumb or gripper.
HRESULT PaintScrollbarThumb(HDC hdc,
int part_id,
int state_id,
int classic_state,
RECT* rect) const;
HRESULT PaintStatusGripper(HDC hdc,
int part_id,
int state_id,
int classic_state,
RECT* rect) const;
HRESULT PaintTabPanelBackground(HDC dc, RECT* rect) const;
HRESULT PaintTextField(HDC hdc,
int part_id,
int state_id,
int classic_state,
RECT* rect,
COLORREF color,
bool fill_content_area,
bool draw_edges) const;
HRESULT PaintTrackbar(HDC hdc,
int part_id,
int state_id,
int classic_state,
RECT* rect,
skia::PlatformCanvasWin* canvas) const;
bool IsThemingActive() const;
HRESULT GetThemePartSize(ThemeName themeName,
HDC hdc,
int part_id,
int state_id,
RECT* rect,
int ts,
SIZE* size) const;
HRESULT GetThemeColor(ThemeName theme,
int part_id,
int state_id,
int prop_id,
SkColor* color) const;
// Get the theme color if theming is enabled. If theming is unsupported
// for this part, use Win32's GetSysColor to find the color specified
// by default_sys_color.
SkColor GetThemeColorWithDefault(ThemeName theme,
int part_id,
int state_id,
int prop_id,
int default_sys_color) const;
HRESULT GetThemeInt(ThemeName theme,
int part_id,
int state_id,
int prop_id,
int *result) const;
// Get the thickness of the border associated with the specified theme,
// defaulting to GetSystemMetrics edge size if themes are disabled.
// In Classic Windows, borders are typically 2px; on XP+, they are 1px.
Size GetThemeBorderSize(ThemeName theme) const;
// Disables all theming for top-level windows in the entire process, from
// when this method is called until the process exits. All the other
// methods in this class will continue to work, but their output will ignore
// the user's theme. This is meant for use when running tests that require
// consistent visual results.
void DisableTheming() const;
// Closes cached theme handles so we can unload the DLL or update our UI
// for a theme change.
void CloseHandles() const;
// Gets our singleton instance.
static const NativeTheme* instance();
private:
NativeTheme();
~NativeTheme();
HRESULT PaintFrameControl(HDC hdc,
RECT* rect,
UINT type,
UINT state,
bool is_highlighted) const;
// Returns a handle to the theme data.
HANDLE GetThemeHandle(ThemeName theme_name) const;
// Function pointers into uxtheme.dll.
DrawThemeBackgroundPtr draw_theme_;
DrawThemeBackgroundExPtr draw_theme_ex_;
GetThemeColorPtr get_theme_color_;
GetThemeContentRectPtr get_theme_content_rect_;
GetThemePartSizePtr get_theme_part_size_;
OpenThemeDataPtr open_theme_;
CloseThemeDataPtr close_theme_;
SetThemeAppPropertiesPtr set_theme_properties_;
IsThemeActivePtr is_theme_active_;
GetThemeIntPtr get_theme_int_;
// Handle to uxtheme.dll.
HMODULE theme_dll_;
// A cache of open theme handles.
mutable HANDLE theme_handles_[LAST];
DISALLOW_EVIL_CONSTRUCTORS(NativeTheme);
};
} // namespace gfx
#endif // BASE_GFX_NATIVE_THEME_H__

View File

@ -1,11 +0,0 @@
// Copyright (c) 2006-2008 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 "base/gfx/native_theme.h"
#include "testing/gtest/include/gtest/gtest.h"
TEST(NativeThemeTest, Init) {
ASSERT_TRUE(gfx::NativeTheme::instance() != NULL);
}

View File

@ -1,16 +0,0 @@
// Copyright (c) 2009 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 "base/gfx/native_widget_types.h"
#include "base/gfx/gtk_native_view_id_manager.h"
#include "base/logging.h"
namespace gfx {
NativeViewId IdFromNativeView(NativeView view) {
return Singleton<GtkNativeViewManager>()->GetIdForWidget(view);
}
} // namespace gfx

View File

@ -1,7 +0,0 @@
// Copyright (c) 2006-2008 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.
// TODO(brettw) this file should be removed and the includes changed to this
// new location.
#include "skia/ext/platform_canvas.h"

View File

@ -1,12 +0,0 @@
// Copyright (c) 2006-2008 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.
#ifndef BASE_GFX_PLATFORM_CANVAS_LINUX_H_
#define BASE_GFX_PLATFORM_CANVAS_LINUX_H_
// TODO(brettw) this file should be removed and the includes changed to this
// new location.
#include "skia/ext/platform_canvas_linux.h"
#endif // BASE_GFX_PLATFORM_CANVAS_LINUX_H_

View File

@ -1,12 +0,0 @@
// Copyright (c) 2006-2008 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.
#ifndef BASE_GFX_PLATFORM_CANVAS_MAC_H__
#define BASE_GFX_PLATFORM_CANVAS_MAC_H__
// TODO(brettw) this file should be removed and the includes changed to this
// new location.
#include "skia/ext/platform_canvas_mac.h"
#endif // BASE_GFX_PLATFORM_CANVAS_MAC_H__

View File

@ -1,12 +0,0 @@
// Copyright (c) 2006-2008 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.
#ifndef BASE_GFX_PLATFORM_DEVICE_LINUX_H_
#define BASE_GFX_PLATFORM_DEVICE_LINUX_H_
// TODO(brettw) this file should be removed and the includes changed to this
// new location.
#include "skia/ext/platform_device_linux.h"
#endif // BASE_GFX_PLATFORM_DEVICE_LINUX_H_

View File

@ -1,12 +0,0 @@
// Copyright (c) 2006-2008 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.
#ifndef BASE_GFX_PLATFORM_DEVICE_MAC_H__
#define BASE_GFX_PLATFORM_DEVICE_MAC_H__
// TODO(brettw) this file should be removed and the includes changed to this
// new location.
#include "skia/ext/platform_device_mac.h"
#endif // BASE_GFX_PLATFORM_DEVICE_MAC_H__

View File

@ -1,202 +0,0 @@
// Copyright (c) 2006-2008 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 <math.h>
#include "base/gfx/png_encoder.h"
#include "base/gfx/png_decoder.h"
#include "testing/gtest/include/gtest/gtest.h"
static void MakeRGBImage(int w, int h, std::vector<unsigned char>* dat) {
dat->resize(w * h * 3);
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
unsigned char* org_px = &(*dat)[(y * w + x) * 3];
org_px[0] = x * 3; // r
org_px[1] = x * 3 + 1; // g
org_px[2] = x * 3 + 2; // b
}
}
}
// Set use_transparency to write data into the alpha channel, otherwise it will
// be filled with 0xff. With the alpha channel stripped, this should yield the
// same image as MakeRGBImage above, so the code below can make reference
// images for conversion testing.
static void MakeRGBAImage(int w, int h, bool use_transparency,
std::vector<unsigned char>* dat) {
dat->resize(w * h * 4);
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
unsigned char* org_px = &(*dat)[(y * w + x) * 4];
org_px[0] = x * 3; // r
org_px[1] = x * 3 + 1; // g
org_px[2] = x * 3 + 2; // b
if (use_transparency)
org_px[3] = x*3 + 3; // a
else
org_px[3] = 0xFF; // a (opaque)
}
}
}
TEST(PNGCodec, EncodeDecodeRGB) {
const int w = 20, h = 20;
// create an image with known values
std::vector<unsigned char> original;
MakeRGBImage(w, h, &original);
// encode
std::vector<unsigned char> encoded;
EXPECT_TRUE(PNGEncoder::Encode(&original[0], PNGEncoder::FORMAT_RGB, w, h,
w * 3, false, &encoded));
// decode, it should have the same size as the original
std::vector<unsigned char> decoded;
int outw, outh;
EXPECT_TRUE(PNGDecoder::Decode(&encoded[0], encoded.size(),
PNGDecoder::FORMAT_RGB, &decoded,
&outw, &outh));
ASSERT_EQ(w, outw);
ASSERT_EQ(h, outh);
ASSERT_EQ(original.size(), decoded.size());
// Images must be equal
ASSERT_TRUE(original == decoded);
}
TEST(PNGCodec, EncodeDecodeRGBA) {
const int w = 20, h = 20;
// create an image with known values, a must be opaque because it will be
// lost during encoding
std::vector<unsigned char> original;
MakeRGBAImage(w, h, true, &original);
// encode
std::vector<unsigned char> encoded;
EXPECT_TRUE(PNGEncoder::Encode(&original[0], PNGEncoder::FORMAT_RGBA, w, h,
w * 4, false, &encoded));
// decode, it should have the same size as the original
std::vector<unsigned char> decoded;
int outw, outh;
EXPECT_TRUE(PNGDecoder::Decode(&encoded[0], encoded.size(),
PNGDecoder::FORMAT_RGBA, &decoded,
&outw, &outh));
ASSERT_EQ(w, outw);
ASSERT_EQ(h, outh);
ASSERT_EQ(original.size(), decoded.size());
// Images must be exactly equal
ASSERT_TRUE(original == decoded);
}
// Test that corrupted data decompression causes failures.
TEST(PNGCodec, DecodeCorrupted) {
int w = 20, h = 20;
// Make some random data (an uncompressed image).
std::vector<unsigned char> original;
MakeRGBImage(w, h, &original);
// It should fail when given non-JPEG compressed data.
std::vector<unsigned char> output;
int outw, outh;
EXPECT_FALSE(PNGDecoder::Decode(&original[0], original.size(),
PNGDecoder::FORMAT_RGB, &output,
&outw, &outh));
// Make some compressed data.
std::vector<unsigned char> compressed;
EXPECT_TRUE(PNGEncoder::Encode(&original[0], PNGEncoder::FORMAT_RGB, w, h,
w * 3, false, &compressed));
// Try decompressing a truncated version.
EXPECT_FALSE(PNGDecoder::Decode(&compressed[0], compressed.size() / 2,
PNGDecoder::FORMAT_RGB, &output,
&outw, &outh));
// Corrupt it and try decompressing that.
for (int i = 10; i < 30; i++)
compressed[i] = i;
EXPECT_FALSE(PNGDecoder::Decode(&compressed[0], compressed.size(),
PNGDecoder::FORMAT_RGB, &output,
&outw, &outh));
}
TEST(PNGCodec, EncodeDecodeBGRA) {
const int w = 20, h = 20;
// Create an image with known values, alpha must be opaque because it will be
// lost during encoding.
std::vector<unsigned char> original;
MakeRGBAImage(w, h, true, &original);
// Encode.
std::vector<unsigned char> encoded;
EXPECT_TRUE(PNGEncoder::Encode(&original[0], PNGEncoder::FORMAT_BGRA, w, h,
w * 4, false, &encoded));
// Decode, it should have the same size as the original.
std::vector<unsigned char> decoded;
int outw, outh;
EXPECT_TRUE(PNGDecoder::Decode(&encoded[0], encoded.size(),
PNGDecoder::FORMAT_BGRA, &decoded,
&outw, &outh));
ASSERT_EQ(w, outw);
ASSERT_EQ(h, outh);
ASSERT_EQ(original.size(), decoded.size());
// Images must be exactly equal.
ASSERT_TRUE(original == decoded);
}
TEST(PNGCodec, StripAddAlpha) {
const int w = 20, h = 20;
// These should be the same except one has a 0xff alpha channel.
std::vector<unsigned char> original_rgb;
MakeRGBImage(w, h, &original_rgb);
std::vector<unsigned char> original_rgba;
MakeRGBAImage(w, h, false, &original_rgba);
// Encode RGBA data as RGB.
std::vector<unsigned char> encoded;
EXPECT_TRUE(PNGEncoder::Encode(&original_rgba[0],
PNGEncoder::FORMAT_RGBA,
w, h,
w * 4, true, &encoded));
// Decode the RGB to RGBA.
std::vector<unsigned char> decoded;
int outw, outh;
EXPECT_TRUE(PNGDecoder::Decode(&encoded[0], encoded.size(),
PNGDecoder::FORMAT_RGBA, &decoded,
&outw, &outh));
// Decoded and reference should be the same (opaque alpha).
ASSERT_EQ(w, outw);
ASSERT_EQ(h, outh);
ASSERT_EQ(original_rgba.size(), decoded.size());
ASSERT_TRUE(original_rgba == decoded);
// Encode RGBA to RGBA.
EXPECT_TRUE(PNGEncoder::Encode(&original_rgba[0],
PNGEncoder::FORMAT_RGBA,
w, h,
w * 4, false, &encoded));
// Decode the RGBA to RGB.
EXPECT_TRUE(PNGDecoder::Decode(&encoded[0], encoded.size(),
PNGDecoder::FORMAT_RGB, &decoded,
&outw, &outh));
// It should be the same as our non-alpha-channel reference.
ASSERT_EQ(w, outw);
ASSERT_EQ(h, outh);
ASSERT_EQ(original_rgb.size(), decoded.size());
ASSERT_TRUE(original_rgb == decoded);
}

View File

@ -1,354 +0,0 @@
// Copyright (c) 2006-2008 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 "base/gfx/png_decoder.h"
#include "base/logging.h"
#include "skia/include/SkBitmap.h"
extern "C" {
#include "third_party/libpng/png.h"
}
namespace {
// Converts BGRA->RGBA and RGBA->BGRA.
void ConvertBetweenBGRAandRGBA(const unsigned char* input, int pixel_width,
unsigned char* output) {
for (int x = 0; x < pixel_width; x++) {
const unsigned char* pixel_in = &input[x * 4];
unsigned char* pixel_out = &output[x * 4];
pixel_out[0] = pixel_in[2];
pixel_out[1] = pixel_in[1];
pixel_out[2] = pixel_in[0];
pixel_out[3] = pixel_in[3];
}
}
void ConvertRGBAtoRGB(const unsigned char* rgba, int pixel_width,
unsigned char* rgb) {
for (int x = 0; x < pixel_width; x++) {
const unsigned char* pixel_in = &rgba[x * 4];
unsigned char* pixel_out = &rgb[x * 3];
pixel_out[0] = pixel_in[0];
pixel_out[1] = pixel_in[1];
pixel_out[2] = pixel_in[2];
}
}
} // namespace
// Decoder --------------------------------------------------------------------
//
// This code is based on WebKit libpng interface (PNGImageDecoder), which is
// in turn based on the Mozilla png decoder.
namespace {
// Gamma constants: We assume we're on Windows which uses a gamma of 2.2.
const double kMaxGamma = 21474.83; // Maximum gamma accepted by png library.
const double kDefaultGamma = 2.2;
const double kInverseGamma = 1.0 / kDefaultGamma;
// Maximum pixel dimension we'll try to decode.
const png_uint_32 kMaxSize = 4096;
class PngDecoderState {
public:
PngDecoderState(PNGDecoder::ColorFormat ofmt, std::vector<unsigned char>* o)
: output_format(ofmt),
output_channels(0),
output(o),
row_converter(NULL),
width(0),
height(0),
done(false) {
}
PNGDecoder::ColorFormat output_format;
int output_channels;
std::vector<unsigned char>* output;
// Called to convert a row from the library to the correct output format.
// When NULL, no conversion is necessary.
void (*row_converter)(const unsigned char* in, int w, unsigned char* out);
// Size of the image, set in the info callback.
int width;
int height;
// Set to true when we've found the end of the data.
bool done;
private:
DISALLOW_EVIL_CONSTRUCTORS(PngDecoderState);
};
void ConvertRGBtoRGBA(const unsigned char* rgb, int pixel_width,
unsigned char* rgba) {
for (int x = 0; x < pixel_width; x++) {
const unsigned char* pixel_in = &rgb[x * 3];
unsigned char* pixel_out = &rgba[x * 4];
pixel_out[0] = pixel_in[0];
pixel_out[1] = pixel_in[1];
pixel_out[2] = pixel_in[2];
pixel_out[3] = 0xff;
}
}
void ConvertRGBtoBGRA(const unsigned char* rgb, int pixel_width,
unsigned char* bgra) {
for (int x = 0; x < pixel_width; x++) {
const unsigned char* pixel_in = &rgb[x * 3];
unsigned char* pixel_out = &bgra[x * 4];
pixel_out[0] = pixel_in[2];
pixel_out[1] = pixel_in[1];
pixel_out[2] = pixel_in[0];
pixel_out[3] = 0xff;
}
}
// Called when the png header has been read. This code is based on the WebKit
// PNGImageDecoder
void DecodeInfoCallback(png_struct* png_ptr, png_info* info_ptr) {
PngDecoderState* state = static_cast<PngDecoderState*>(
png_get_progressive_ptr(png_ptr));
int bit_depth, color_type, interlace_type, compression_type;
int filter_type, channels;
png_uint_32 w, h;
png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type,
&interlace_type, &compression_type, &filter_type);
// Bounds check. When the image is unreasonably big, we'll error out and
// end up back at the setjmp call when we set up decoding.
if (w > kMaxSize || h > kMaxSize)
longjmp(png_ptr->jmpbuf, 1);
state->width = static_cast<int>(w);
state->height = static_cast<int>(h);
// Expand to ensure we use 24-bit for RGB and 32-bit for RGBA.
if (color_type == PNG_COLOR_TYPE_PALETTE ||
(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8))
png_set_expand(png_ptr);
// Transparency for paletted images.
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_expand(png_ptr);
// Convert 16-bit to 8-bit.
if (bit_depth == 16)
png_set_strip_16(png_ptr);
// Expand grayscale to RGB.
if (color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png_ptr);
// Deal with gamma and keep it under our control.
double gamma;
if (png_get_gAMA(png_ptr, info_ptr, &gamma)) {
if (gamma <= 0.0 || gamma > kMaxGamma) {
gamma = kInverseGamma;
png_set_gAMA(png_ptr, info_ptr, gamma);
}
png_set_gamma(png_ptr, kDefaultGamma, gamma);
} else {
png_set_gamma(png_ptr, kDefaultGamma, kInverseGamma);
}
// Tell libpng to send us rows for interlaced pngs.
if (interlace_type == PNG_INTERLACE_ADAM7)
png_set_interlace_handling(png_ptr);
// Update our info now
png_read_update_info(png_ptr, info_ptr);
channels = png_get_channels(png_ptr, info_ptr);
// Pick our row format converter necessary for this data.
if (channels == 3) {
switch (state->output_format) {
case PNGDecoder::FORMAT_RGB:
state->row_converter = NULL; // no conversion necessary
state->output_channels = 3;
break;
case PNGDecoder::FORMAT_RGBA:
state->row_converter = &ConvertRGBtoRGBA;
state->output_channels = 4;
break;
case PNGDecoder::FORMAT_BGRA:
state->row_converter = &ConvertRGBtoBGRA;
state->output_channels = 4;
break;
default:
NOTREACHED() << "Unknown output format";
break;
}
} else if (channels == 4) {
switch (state->output_format) {
case PNGDecoder::FORMAT_RGB:
state->row_converter = &ConvertRGBAtoRGB;
state->output_channels = 3;
break;
case PNGDecoder::FORMAT_RGBA:
state->row_converter = NULL; // no conversion necessary
state->output_channels = 4;
break;
case PNGDecoder::FORMAT_BGRA:
state->row_converter = &ConvertBetweenBGRAandRGBA;
state->output_channels = 4;
break;
default:
NOTREACHED() << "Unknown output format";
break;
}
} else {
NOTREACHED() << "Unknown input channels";
longjmp(png_ptr->jmpbuf, 1);
}
state->output->resize(state->width * state->output_channels * state->height);
}
void DecodeRowCallback(png_struct* png_ptr, png_byte* new_row,
png_uint_32 row_num, int pass) {
PngDecoderState* state = static_cast<PngDecoderState*>(
png_get_progressive_ptr(png_ptr));
DCHECK(pass == 0) << "We didn't turn on interlace handling, but libpng is "
"giving us interlaced data.";
if (static_cast<int>(row_num) > state->height) {
NOTREACHED() << "Invalid row";
return;
}
unsigned char* dest = &(*state->output)[
state->width * state->output_channels * row_num];
if (state->row_converter)
state->row_converter(new_row, state->width, dest);
else
memcpy(dest, new_row, state->width * state->output_channels);
}
void DecodeEndCallback(png_struct* png_ptr, png_info* info) {
PngDecoderState* state = static_cast<PngDecoderState*>(
png_get_progressive_ptr(png_ptr));
// Mark the image as complete, this will tell the Decode function that we
// have successfully found the end of the data.
state->done = true;
}
// Automatically destroys the given read structs on destruction to make
// cleanup and error handling code cleaner.
class PngReadStructDestroyer {
public:
PngReadStructDestroyer(png_struct** ps, png_info** pi) : ps_(ps), pi_(pi) {
}
~PngReadStructDestroyer() {
png_destroy_read_struct(ps_, pi_, NULL);
}
private:
png_struct** ps_;
png_info** pi_;
};
} // namespace
// static
bool PNGDecoder::Decode(const unsigned char* input, size_t input_size,
ColorFormat format, std::vector<unsigned char>* output,
int* w, int* h) {
if (input_size < 8)
return false; // Input data too small to be a png
// Have libpng check the signature, it likes the first 8 bytes.
if (png_sig_cmp(const_cast<unsigned char*>(input), 0, 8) != 0)
return false;
png_struct* png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
png_voidp_NULL,
png_error_ptr_NULL,
png_error_ptr_NULL);
if (!png_ptr)
return false;
png_info* info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
png_destroy_read_struct(&png_ptr, NULL, NULL);
return false;
}
PngReadStructDestroyer destroyer(&png_ptr, &info_ptr);
if (setjmp(png_jmpbuf(png_ptr))) {
// The destroyer will ensure that the structures are cleaned up in this
// case, even though we may get here as a jump from random parts of the
// PNG library called below.
return false;
}
PngDecoderState state(format, output);
png_set_progressive_read_fn(png_ptr, &state, &DecodeInfoCallback,
&DecodeRowCallback, &DecodeEndCallback);
png_process_data(png_ptr,
info_ptr,
const_cast<unsigned char*>(input),
input_size);
if (!state.done) {
// Fed it all the data but the library didn't think we got all the data, so
// this file must be truncated.
output->clear();
return false;
}
*w = state.width;
*h = state.height;
return true;
}
// static
bool PNGDecoder::Decode(const std::vector<unsigned char>* data,
SkBitmap* bitmap) {
DCHECK(bitmap);
if (!data || data->empty())
return false;
int width, height;
std::vector<unsigned char> decoded_data;
if (PNGDecoder::Decode(&data->front(), data->size(), PNGDecoder::FORMAT_BGRA,
&decoded_data, &width, &height)) {
bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height);
bitmap->allocPixels();
memcpy(bitmap->getPixels(), &decoded_data.front(), width * height * 4);
return true;
}
return false;
}
//static
SkBitmap* PNGDecoder::CreateSkBitmapFromBGRAFormat(
std::vector<unsigned char>& bgra, int width, int height) {
SkBitmap* bitmap = new SkBitmap();
bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height);
bitmap->allocPixels();
bool opaque = false;
unsigned char* bitmap_data =
reinterpret_cast<unsigned char*>(bitmap->getAddr32(0, 0));
for (int i = width * height * 4 - 4; i >= 0; i -= 4) {
unsigned char alpha = bgra[i + 3];
if (!opaque && alpha != 255) {
opaque = false;
}
bitmap_data[i + 3] = alpha;
bitmap_data[i] = (bgra[i] * alpha) >> 8;
bitmap_data[i + 1] = (bgra[i + 1] * alpha) >> 8;
bitmap_data[i + 2] = (bgra[i + 2] * alpha) >> 8;
}
bitmap->setIsOpaque(opaque);
return bitmap;
}

View File

@ -1,63 +0,0 @@
// Copyright (c) 2006-2008 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.
#ifndef BASE_GFX_PNG_DECODER_H_
#define BASE_GFX_PNG_DECODER_H_
#include <vector>
#include "base/basictypes.h"
class SkBitmap;
// Interface for decoding PNG data. This is a wrapper around libpng,
// which has an inconvenient interface for callers. This is currently designed
// for use in tests only (where we control the files), so the handling isn't as
// robust as would be required for a browser (see Decode() for more). WebKit
// has its own more complicated PNG decoder which handles, among other things,
// partially downloaded data.
class PNGDecoder {
public:
enum ColorFormat {
// 3 bytes per pixel (packed), in RGB order regardless of endianness.
// This is the native JPEG format.
FORMAT_RGB,
// 4 bytes per pixel, in RGBA order in memory regardless of endianness.
FORMAT_RGBA,
// 4 bytes per pixel, in BGRA order in memory regardless of endianness.
// This is the default Windows DIB order.
FORMAT_BGRA
};
// Decodes the PNG data contained in input of length input_size. The
// decoded data will be placed in *output with the dimensions in *w and *h
// on success (returns true). This data will be written in the 'format'
// format. On failure, the values of these output variables are undefined.
//
// This function may not support all PNG types, and it hasn't been tested
// with a large number of images, so assume a new format may not work. It's
// really designed to be able to read in something written by Encode() above.
static bool Decode(const unsigned char* input, size_t input_size,
ColorFormat format, std::vector<unsigned char>* output,
int* w, int* h);
// A convenience function for decoding PNGs as previously encoded by the PNG
// encoder. Chrome encodes png in the format PNGDecoder::FORMAT_BGRA.
//
// Returns true if data is non-null and can be decoded as a png, false
// otherwise.
static bool Decode(const std::vector<unsigned char>* data, SkBitmap* icon);
// Create a SkBitmap from a decoded BGRA DIB. The caller owns the returned
// SkBitmap.
static SkBitmap* CreateSkBitmapFromBGRAFormat(
std::vector<unsigned char>& bgra, int width, int height);
private:
DISALLOW_COPY_AND_ASSIGN(PNGDecoder);
};
#endif // BASE_GFX_PNG_DECODER_H_

View File

@ -1,205 +0,0 @@
// Copyright (c) 2006-2008 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 "base/basictypes.h"
#include "base/gfx/png_encoder.h"
#include "base/logging.h"
#include "skia/include/SkBitmap.h"
extern "C" {
#include "third_party/libpng/png.h"
}
namespace {
// Converts BGRA->RGBA and RGBA->BGRA.
void ConvertBetweenBGRAandRGBA(const unsigned char* input, int pixel_width,
unsigned char* output) {
for (int x = 0; x < pixel_width; x++) {
const unsigned char* pixel_in = &input[x * 4];
unsigned char* pixel_out = &output[x * 4];
pixel_out[0] = pixel_in[2];
pixel_out[1] = pixel_in[1];
pixel_out[2] = pixel_in[0];
pixel_out[3] = pixel_in[3];
}
}
void ConvertRGBAtoRGB(const unsigned char* rgba, int pixel_width,
unsigned char* rgb) {
for (int x = 0; x < pixel_width; x++) {
const unsigned char* pixel_in = &rgba[x * 4];
unsigned char* pixel_out = &rgb[x * 3];
pixel_out[0] = pixel_in[0];
pixel_out[1] = pixel_in[1];
pixel_out[2] = pixel_in[2];
}
}
} // namespace
// Encoder --------------------------------------------------------------------
//
// This section of the code is based on nsPNGEncoder.cpp in Mozilla
// (Copyright 2005 Google Inc.)
namespace {
// Passed around as the io_ptr in the png structs so our callbacks know where
// to write data.
struct PngEncoderState {
PngEncoderState(std::vector<unsigned char>* o) : out(o) {}
std::vector<unsigned char>* out;
};
// Called by libpng to flush its internal buffer to ours.
void EncoderWriteCallback(png_structp png, png_bytep data, png_size_t size) {
PngEncoderState* state = static_cast<PngEncoderState*>(png_get_io_ptr(png));
DCHECK(state->out);
size_t old_size = state->out->size();
state->out->resize(old_size + size);
memcpy(&(*state->out)[old_size], data, size);
}
void ConvertBGRAtoRGB(const unsigned char* bgra, int pixel_width,
unsigned char* rgb) {
for (int x = 0; x < pixel_width; x++) {
const unsigned char* pixel_in = &bgra[x * 4];
unsigned char* pixel_out = &rgb[x * 3];
pixel_out[0] = pixel_in[2];
pixel_out[1] = pixel_in[1];
pixel_out[2] = pixel_in[0];
}
}
// Automatically destroys the given write structs on destruction to make
// cleanup and error handling code cleaner.
class PngWriteStructDestroyer {
public:
PngWriteStructDestroyer(png_struct** ps, png_info** pi) : ps_(ps), pi_(pi) {
}
~PngWriteStructDestroyer() {
png_destroy_write_struct(ps_, pi_);
}
private:
png_struct** ps_;
png_info** pi_;
DISALLOW_EVIL_CONSTRUCTORS(PngWriteStructDestroyer);
};
} // namespace
// static
bool PNGEncoder::Encode(const unsigned char* input, ColorFormat format,
int w, int h, int row_byte_width,
bool discard_transparency,
std::vector<unsigned char>* output) {
// Run to convert an input row into the output row format, NULL means no
// conversion is necessary.
void (*converter)(const unsigned char* in, int w, unsigned char* out) = NULL;
int input_color_components, output_color_components;
int png_output_color_type;
switch (format) {
case FORMAT_RGB:
input_color_components = 3;
output_color_components = 3;
png_output_color_type = PNG_COLOR_TYPE_RGB;
discard_transparency = false;
break;
case FORMAT_RGBA:
input_color_components = 4;
if (discard_transparency) {
output_color_components = 3;
png_output_color_type = PNG_COLOR_TYPE_RGB;
converter = ConvertRGBAtoRGB;
} else {
output_color_components = 4;
png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
converter = NULL;
}
break;
case FORMAT_BGRA:
input_color_components = 4;
if (discard_transparency) {
output_color_components = 3;
png_output_color_type = PNG_COLOR_TYPE_RGB;
converter = ConvertBGRAtoRGB;
} else {
output_color_components = 4;
png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
converter = ConvertBetweenBGRAandRGBA;
}
break;
default:
NOTREACHED() << "Unknown pixel format";
return false;
}
// Row stride should be at least as long as the length of the data.
DCHECK(input_color_components * w <= row_byte_width);
png_struct* png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
png_voidp_NULL,
png_error_ptr_NULL,
png_error_ptr_NULL);
if (!png_ptr)
return false;
png_info* info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
png_destroy_write_struct(&png_ptr, NULL);
return false;
}
PngWriteStructDestroyer destroyer(&png_ptr, &info_ptr);
if (setjmp(png_jmpbuf(png_ptr))) {
// The destroyer will ensure that the structures are cleaned up in this
// case, even though we may get here as a jump from random parts of the
// PNG library called below.
return false;
}
// Set our callback for libpng to give us the data.
PngEncoderState state(output);
png_set_write_fn(png_ptr, &state, EncoderWriteCallback, NULL);
png_set_IHDR(png_ptr, info_ptr, w, h, 8, png_output_color_type,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
png_write_info(png_ptr, info_ptr);
if (!converter) {
// No conversion needed, give the data directly to libpng.
for (int y = 0; y < h; y ++)
png_write_row(png_ptr,
const_cast<unsigned char*>(&input[y * row_byte_width]));
} else {
// Needs conversion using a separate buffer.
unsigned char* row = new unsigned char[w * output_color_components];
for (int y = 0; y < h; y ++) {
converter(&input[y * row_byte_width], w, row);
png_write_row(png_ptr, row);
}
delete[] row;
}
png_write_end(png_ptr, info_ptr);
return true;
}
// static
bool PNGEncoder::EncodeBGRASkBitmap(const SkBitmap& input,
bool discard_transparency,
std::vector<unsigned char>* output) {
SkAutoLockPixels input_lock(input);
DCHECK(input.empty() || input.bytesPerPixel() == 4);
return Encode(static_cast<unsigned char*>(input.getPixels()),
PNGEncoder::FORMAT_BGRA, input.width(), input.height(),
input.rowBytes(), discard_transparency, output);
}

View File

@ -1,44 +0,0 @@
// Copyright (c) 2006-2008 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 "base/gfx/point.h"
#if defined(OS_WIN)
#include <windows.h>
#endif
namespace gfx {
Point::Point() : x_(0), y_(0) {
}
Point::Point(int x, int y) : x_(x), y_(y) {
}
#if defined(OS_WIN)
Point::Point(const POINT& point) : x_(point.x), y_(point.y) {
}
Point& Point::operator=(const POINT& point) {
x_ = point.x;
y_ = point.y;
return *this;
}
POINT Point::ToPOINT() const {
POINT p;
p.x = x_;
p.y = y_;
return p;
}
#elif defined(OS_MACOSX)
Point::Point(const CGPoint& point) : x_(point.x), y_(point.y) {
}
CGPoint Point::ToCGPoint() const {
return CGPointMake(x_, y_);
}
#endif
} // namespace gfx

View File

@ -1,226 +0,0 @@
// Copyright (c) 2009 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 "base/gfx/rect.h"
#if defined(OS_WIN)
#include <windows.h>
#elif defined(OS_MACOSX)
#include <CoreGraphics/CGGeometry.h>
#elif defined(OS_LINUX)
#include <gdk/gdk.h>
#endif
#include "base/logging.h"
namespace {
void AdjustAlongAxis(int dst_origin, int dst_size, int* origin, int* size) {
if (*origin < dst_origin) {
*origin = dst_origin;
*size = std::min(dst_size, *size);
} else {
*size = std::min(dst_size, *size);
*origin = std::min(dst_origin + dst_size, *origin + *size) - *size;
}
}
} // namespace
namespace gfx {
Rect::Rect() {
}
Rect::Rect(int width, int height) {
set_width(width);
set_height(height);
}
Rect::Rect(int x, int y, int width, int height)
: origin_(x, y) {
set_width(width);
set_height(height);
}
Rect::Rect(const gfx::Point& origin, const gfx::Size& size)
: origin_(origin), size_(size) {
}
#if defined(OS_WIN)
Rect::Rect(const RECT& r)
: origin_(r.left, r.top) {
set_width(r.right - r.left);
set_height(r.bottom - r.top);
}
Rect& Rect::operator=(const RECT& r) {
origin_.SetPoint(r.left, r.top);
set_width(r.right - r.left);
set_height(r.bottom - r.top);
return *this;
}
#elif defined(OS_MACOSX)
Rect::Rect(const CGRect& r)
: origin_(r.origin.x, r.origin.y) {
set_width(r.size.width);
set_height(r.size.height);
}
Rect& Rect::operator=(const CGRect& r) {
origin_.SetPoint(r.origin.x, r.origin.y);
set_width(r.size.width);
set_height(r.size.height);
return *this;
}
#elif defined(OS_LINUX)
Rect::Rect(const GdkRectangle& r)
: origin_(r.x, r.y) {
set_width(r.width);
set_height(r.height);
}
Rect& Rect::operator=(const GdkRectangle& r) {
origin_.SetPoint(r.x, r.y);
set_width(r.width);
set_height(r.height);
return *this;
}
#endif
void Rect::set_width(int width) {
size_.set_width(width);
}
void Rect::set_height(int height) {
size_.set_height(height);
}
void Rect::SetRect(int x, int y, int width, int height) {
origin_.SetPoint(x, y);
set_width(width);
set_height(height);
}
void Rect::Inset(int left, int top, int right, int bottom) {
Offset(left, top);
set_width(std::max(width() - left - right, 0));
set_height(std::max(height() - top - bottom, 0));
}
void Rect::Offset(int horizontal, int vertical) {
set_x(x() + horizontal);
set_y(y() + vertical);
}
bool Rect::operator==(const Rect& other) const {
return origin_ == other.origin_ && size_ == other.size_;
}
#if defined(OS_WIN)
RECT Rect::ToRECT() const {
RECT r;
r.left = x();
r.right = right();
r.top = y();
r.bottom = bottom();
return r;
}
#elif defined(OS_LINUX)
GdkRectangle Rect::ToGdkRectangle() const {
GdkRectangle r = {x(), y(), width(), height()};
return r;
}
#elif defined(OS_MACOSX)
CGRect Rect::ToCGRect() const {
return CGRectMake(x(), y(), width(), height());
}
#endif
bool Rect::Contains(int point_x, int point_y) const {
return (point_x >= x()) && (point_x < right()) &&
(point_y >= y()) && (point_y < bottom());
}
bool Rect::Contains(const Rect& rect) const {
return (rect.x() >= x() && rect.right() <= right() &&
rect.y() >= y() && rect.bottom() <= bottom());
}
bool Rect::Intersects(const Rect& rect) const {
return !(rect.x() >= right() || rect.right() <= x() ||
rect.y() >= bottom() || rect.bottom() <= y());
}
Rect Rect::Intersect(const Rect& rect) const {
int rx = std::max(x(), rect.x());
int ry = std::max(y(), rect.y());
int rr = std::min(right(), rect.right());
int rb = std::min(bottom(), rect.bottom());
if (rx >= rr || ry >= rb)
rx = ry = rr = rb = 0; // non-intersecting
return Rect(rx, ry, rr - rx, rb - ry);
}
Rect Rect::Union(const Rect& rect) const {
// special case empty rects...
if (IsEmpty())
return rect;
if (rect.IsEmpty())
return *this;
int rx = std::min(x(), rect.x());
int ry = std::min(y(), rect.y());
int rr = std::max(right(), rect.right());
int rb = std::max(bottom(), rect.bottom());
return Rect(rx, ry, rr - rx, rb - ry);
}
Rect Rect::Subtract(const Rect& rect) const {
// boundary cases:
if (!Intersects(rect))
return *this;
if (rect.Contains(*this))
return Rect();
int rx = x();
int ry = y();
int rr = right();
int rb = bottom();
if (rect.y() <= y() && rect.bottom() >= bottom()) {
// complete intersection in the y-direction
if (rect.x() <= x()) {
rx = rect.right();
} else {
rr = rect.x();
}
} else if (rect.x() <= x() && rect.right() >= right()) {
// complete intersection in the x-direction
if (rect.y() <= y()) {
ry = rect.bottom();
} else {
rb = rect.y();
}
}
return Rect(rx, ry, rr - rx, rb - ry);
}
Rect Rect::AdjustToFit(const Rect& rect) const {
int new_x = x();
int new_y = y();
int new_width = width();
int new_height = height();
AdjustAlongAxis(rect.x(), rect.width(), &new_x, &new_width);
AdjustAlongAxis(rect.y(), rect.height(), &new_y, &new_height);
return Rect(new_x, new_y, new_width, new_height);
}
Point Rect::CenterPoint() const {
return Point(x() + (width() + 1) / 2, y() + (height() + 1) / 2);
}
} // namespace gfx

View File

@ -1,162 +0,0 @@
// Copyright (c) 2009 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.
// Defines a simple integer rectangle class. The containment semantics
// are array-like; that is, the coordinate (x, y) is considered to be
// contained by the rectangle, but the coordinate (x + width, y) is not.
// The class will happily let you create malformed rectangles (that is,
// rectangles with negative width and/or height), but there will be assertions
// in the operations (such as contain()) to complain in this case.
#ifndef BASE_GFX_RECT_H__
#define BASE_GFX_RECT_H__
#include <ostream>
#include "base/gfx/point.h"
#include "base/gfx/size.h"
#if defined(OS_WIN)
typedef struct tagRECT RECT;
#elif defined(OS_LINUX)
typedef struct _GdkRectangle GdkRectangle;
#endif
namespace gfx {
class Rect {
public:
Rect();
Rect(int width, int height);
Rect(int x, int y, int width, int height);
#if defined(OS_WIN)
explicit Rect(const RECT& r);
#elif defined(OS_MACOSX)
explicit Rect(const CGRect& r);
#elif defined(OS_LINUX)
explicit Rect(const GdkRectangle& r);
#endif
Rect(const gfx::Point& origin, const gfx::Size& size);
~Rect() {}
#if defined(OS_WIN)
Rect& operator=(const RECT& r);
#elif defined(OS_MACOSX)
Rect& operator=(const CGRect& r);
#elif defined(OS_LINUX)
Rect& operator=(const GdkRectangle& r);
#endif
int x() const { return origin_.x(); }
void set_x(int x) { origin_.set_x(x); }
int y() const { return origin_.y(); }
void set_y(int y) { origin_.set_y(y); }
int width() const { return size_.width(); }
void set_width(int width);
int height() const { return size_.height(); }
void set_height(int height);
const gfx::Point& origin() const { return origin_; }
void set_origin(const gfx::Point& origin) { origin_ = origin; }
const gfx::Size& size() const { return size_; }
int right() const { return x() + width(); }
int bottom() const { return y() + height(); }
void SetRect(int x, int y, int width, int height);
// Shrink the rectangle by a horizontal and vertical distance on all sides.
void Inset(int horizontal, int vertical) {
Inset(horizontal, vertical, horizontal, vertical);
}
// Shrink the rectangle by the specified amount on each side.
void Inset(int left, int top, int right, int bottom);
// Move the rectangle by a horizontal and vertical distance.
void Offset(int horizontal, int vertical);
void Offset(const gfx::Point& point) {
Offset(point.x(), point.y());
}
// Returns true if the area of the rectangle is zero.
bool IsEmpty() const { return size_.IsEmpty(); }
bool operator==(const Rect& other) const;
bool operator!=(const Rect& other) const {
return !(*this == other);
}
#if defined(OS_WIN)
// Construct an equivalent Win32 RECT object.
RECT ToRECT() const;
#elif defined(OS_LINUX)
GdkRectangle ToGdkRectangle() const;
#elif defined(OS_MACOSX)
// Construct an equivalent CoreGraphics object.
CGRect ToCGRect() const;
#endif
// Returns true if the point identified by point_x and point_y falls inside
// this rectangle. The point (x, y) is inside the rectangle, but the
// point (x + width, y + height) is not.
bool Contains(int point_x, int point_y) const;
// Returns true if the specified point is contained by this rectangle.
bool Contains(const gfx::Point& point) const {
return Contains(point.x(), point.y());
}
// Returns true if this rectangle contains the specified rectangle.
bool Contains(const Rect& rect) const;
// Returns true if this rectangle intersects the specified rectangle.
bool Intersects(const Rect& rect) const;
// Computes the intersection of this rectangle with the given rectangle.
Rect Intersect(const Rect& rect) const;
// Computes the union of this rectangle with the given rectangle. The union
// is the smallest rectangle containing both rectangles.
Rect Union(const Rect& rect) const;
// Computes the rectangle resulting from subtracting |rect| from |this|. If
// |rect| does not intersect completely in either the x- or y-direction, then
// |*this| is returned. If |rect| contains |this|, then an empty Rect is
// returned.
Rect Subtract(const Rect& rect) const;
// Returns true if this rectangle equals that of the supplied rectangle.
bool Equals(const Rect& rect) const {
return *this == rect;
}
// Fits as much of the receiving rectangle into the supplied rectangle as
// possible, returning the result. For example, if the receiver had
// a x-location of 2 and a width of 4, and the supplied rectangle had
// an x-location of 0 with a width of 5, the returned rectangle would have
// an x-location of 1 with a width of 4.
Rect AdjustToFit(const Rect& rect) const;
// Returns the center of this rectangle.
Point CenterPoint() const;
private:
gfx::Point origin_;
gfx::Size size_;
};
} // namespace gfx
inline std::ostream& operator<<(std::ostream& out, const gfx::Rect& r) {
return out << r.origin() << " " << r.size();
}
#endif // BASE_GFX_RECT_H__

View File

@ -1,280 +0,0 @@
// Copyright (c) 2006-2008 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 "base/basictypes.h"
#include "base/gfx/rect.h"
#include "testing/gtest/include/gtest/gtest.h"
typedef testing::Test RectTest;
TEST(RectTest, Contains) {
static const struct ContainsCase {
int rect_x;
int rect_y;
int rect_width;
int rect_height;
int point_x;
int point_y;
bool contained;
} contains_cases[] = {
{0, 0, 10, 10, 0, 0, true},
{0, 0, 10, 10, 5, 5, true},
{0, 0, 10, 10, 9, 9, true},
{0, 0, 10, 10, 5, 10, false},
{0, 0, 10, 10, 10, 5, false},
{0, 0, 10, 10, -1, -1, false},
{0, 0, 10, 10, 50, 50, false},
#ifdef NDEBUG
{0, 0, -10, -10, 0, 0, false},
#endif // NDEBUG
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(contains_cases); ++i) {
const ContainsCase& value = contains_cases[i];
gfx::Rect rect(value.rect_x, value.rect_y,
value.rect_width, value.rect_height);
EXPECT_EQ(value.contained, rect.Contains(value.point_x, value.point_y));
}
}
TEST(RectTest, Intersects) {
static const struct {
int x1; // rect 1
int y1;
int w1;
int h1;
int x2; // rect 2
int y2;
int w2;
int h2;
bool intersects;
} tests[] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, false },
{ 0, 0, 10, 10, 0, 0, 10, 10, true },
{ 0, 0, 10, 10, 10, 10, 10, 10, false },
{ 10, 10, 10, 10, 0, 0, 10, 10, false },
{ 10, 10, 10, 10, 5, 5, 10, 10, true },
{ 10, 10, 10, 10, 15, 15, 10, 10, true },
{ 10, 10, 10, 10, 20, 15, 10, 10, false },
{ 10, 10, 10, 10, 21, 15, 10, 10, false }
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
gfx::Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
gfx::Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
EXPECT_EQ(tests[i].intersects, r1.Intersects(r2));
}
}
TEST(RectTest, Intersect) {
static const struct {
int x1; // rect 1
int y1;
int w1;
int h1;
int x2; // rect 2
int y2;
int w2;
int h2;
int x3; // rect 3: the union of rects 1 and 2
int y3;
int w3;
int h3;
} tests[] = {
{ 0, 0, 0, 0, // zeros
0, 0, 0, 0,
0, 0, 0, 0 },
{ 0, 0, 4, 4, // equal
0, 0, 4, 4,
0, 0, 4, 4 },
{ 0, 0, 4, 4, // neighboring
4, 4, 4, 4,
0, 0, 0, 0 },
{ 0, 0, 4, 4, // overlapping corners
2, 2, 4, 4,
2, 2, 2, 2 },
{ 0, 0, 4, 4, // T junction
3, 1, 4, 2,
3, 1, 1, 2 },
{ 3, 0, 2, 2, // gap
0, 0, 2, 2,
0, 0, 0, 0 }
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
gfx::Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
gfx::Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
gfx::Rect r3(tests[i].x3, tests[i].y3, tests[i].w3, tests[i].h3);
gfx::Rect ir = r1.Intersect(r2);
EXPECT_EQ(r3.x(), ir.x());
EXPECT_EQ(r3.y(), ir.y());
EXPECT_EQ(r3.width(), ir.width());
EXPECT_EQ(r3.height(), ir.height());
}
}
TEST(RectTest, Union) {
static const struct Test {
int x1; // rect 1
int y1;
int w1;
int h1;
int x2; // rect 2
int y2;
int w2;
int h2;
int x3; // rect 3: the union of rects 1 and 2
int y3;
int w3;
int h3;
} tests[] = {
{ 0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0 },
{ 0, 0, 4, 4,
0, 0, 4, 4,
0, 0, 4, 4 },
{ 0, 0, 4, 4,
4, 4, 4, 4,
0, 0, 8, 8 },
{ 0, 0, 4, 4,
0, 5, 4, 4,
0, 0, 4, 9 },
{ 0, 0, 2, 2,
3, 3, 2, 2,
0, 0, 5, 5 },
{ 3, 3, 2, 2, // reverse r1 and r2 from previous test
0, 0, 2, 2,
0, 0, 5, 5 },
{ 0, 0, 0, 0, // union with empty rect
2, 2, 2, 2,
2, 2, 2, 2 }
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
gfx::Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
gfx::Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
gfx::Rect r3(tests[i].x3, tests[i].y3, tests[i].w3, tests[i].h3);
gfx::Rect u = r1.Union(r2);
EXPECT_EQ(r3.x(), u.x());
EXPECT_EQ(r3.y(), u.y());
EXPECT_EQ(r3.width(), u.width());
EXPECT_EQ(r3.height(), u.height());
}
}
TEST(RectTest, Equals) {
ASSERT_TRUE(gfx::Rect(0, 0, 0, 0).Equals(gfx::Rect(0, 0, 0, 0)));
ASSERT_TRUE(gfx::Rect(1, 2, 3, 4).Equals(gfx::Rect(1, 2, 3, 4)));
ASSERT_FALSE(gfx::Rect(0, 0, 0, 0).Equals(gfx::Rect(0, 0, 0, 1)));
ASSERT_FALSE(gfx::Rect(0, 0, 0, 0).Equals(gfx::Rect(0, 0, 1, 0)));
ASSERT_FALSE(gfx::Rect(0, 0, 0, 0).Equals(gfx::Rect(0, 1, 0, 0)));
ASSERT_FALSE(gfx::Rect(0, 0, 0, 0).Equals(gfx::Rect(1, 0, 0, 0)));
}
TEST(RectTest, AdjustToFit) {
static const struct Test {
int x1; // source
int y1;
int w1;
int h1;
int x2; // target
int y2;
int w2;
int h2;
int x3; // rect 3: results of invoking AdjustToFit
int y3;
int w3;
int h3;
} tests[] = {
{ 0, 0, 2, 2,
0, 0, 2, 2,
0, 0, 2, 2 },
{ 2, 2, 3, 3,
0, 0, 4, 4,
1, 1, 3, 3 },
{ -1, -1, 5, 5,
0, 0, 4, 4,
0, 0, 4, 4 },
{ 2, 2, 4, 4,
0, 0, 3, 3,
0, 0, 3, 3 },
{ 2, 2, 1, 1,
0, 0, 3, 3,
2, 2, 1, 1 }
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
gfx::Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
gfx::Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
gfx::Rect r3(tests[i].x3, tests[i].y3, tests[i].w3, tests[i].h3);
gfx::Rect u(r1.AdjustToFit(r2));
EXPECT_EQ(r3.x(), u.x());
EXPECT_EQ(r3.y(), u.y());
EXPECT_EQ(r3.width(), u.width());
EXPECT_EQ(r3.height(), u.height());
}
}
TEST(RectTest, Subtract) {
// Matching
EXPECT_TRUE(
gfx::Rect(10, 10, 20, 20).Subtract(
gfx::Rect(10, 10, 20, 20)).Equals(
gfx::Rect(0, 0, 0, 0)));
// Contains
EXPECT_TRUE(
gfx::Rect(10, 10, 20, 20).Subtract(
gfx::Rect(5, 5, 30, 30)).Equals(
gfx::Rect(0, 0, 0, 0)));
// No intersection
EXPECT_TRUE(
gfx::Rect(10, 10, 20, 20).Subtract(
gfx::Rect(30, 30, 20, 20)).Equals(
gfx::Rect(10, 10, 20, 20)));
// Not a complete intersection in either direction
EXPECT_TRUE(
gfx::Rect(10, 10, 20, 20).Subtract(
gfx::Rect(15, 15, 20, 20)).Equals(
gfx::Rect(10, 10, 20, 20)));
// Complete intersection in the x-direction
EXPECT_TRUE(
gfx::Rect(10, 10, 20, 20).Subtract(
gfx::Rect(10, 15, 20, 20)).Equals(
gfx::Rect(10, 10, 20, 5)));
// Complete intersection in the x-direction
EXPECT_TRUE(
gfx::Rect(10, 10, 20, 20).Subtract(
gfx::Rect(5, 15, 30, 20)).Equals(
gfx::Rect(10, 10, 20, 5)));
// Complete intersection in the x-direction
EXPECT_TRUE(
gfx::Rect(10, 10, 20, 20).Subtract(
gfx::Rect(5, 5, 30, 20)).Equals(
gfx::Rect(10, 25, 20, 5)));
// Complete intersection in the y-direction
EXPECT_TRUE(
gfx::Rect(10, 10, 20, 20).Subtract(
gfx::Rect(10, 10, 10, 30)).Equals(
gfx::Rect(20, 10, 10, 20)));
// Complete intersection in the y-direction
EXPECT_TRUE(
gfx::Rect(10, 10, 20, 20).Subtract(
gfx::Rect(5, 5, 20, 30)).Equals(
gfx::Rect(25, 10, 5, 20)));
}
TEST(RectTest, IsEmpty) {
EXPECT_TRUE(gfx::Rect(0, 0, 0, 0).IsEmpty());
EXPECT_TRUE(gfx::Rect(0, 0, 0, 0).size().IsEmpty());
EXPECT_TRUE(gfx::Rect(0, 0, 10, 0).IsEmpty());
EXPECT_TRUE(gfx::Rect(0, 0, 10, 0).size().IsEmpty());
EXPECT_TRUE(gfx::Rect(0, 0, 0, 10).IsEmpty());
EXPECT_TRUE(gfx::Rect(0, 0, 0, 10).size().IsEmpty());
EXPECT_FALSE(gfx::Rect(0, 0, 10, 10).IsEmpty());
EXPECT_FALSE(gfx::Rect(0, 0, 10, 10).size().IsEmpty());
}

View File

@ -1,53 +0,0 @@
// Copyright (c) 2006-2008 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 "base/gfx/size.h"
#if defined(OS_WIN)
#include <windows.h>
#elif defined(OS_MACOSX)
#include <CoreGraphics/CGGeometry.h>
#endif
#include "base/logging.h"
namespace gfx {
Size::Size(int width, int height) {
set_width(width);
set_height(height);
}
#if defined(OS_WIN)
SIZE Size::ToSIZE() const {
SIZE s;
s.cx = width_;
s.cy = height_;
return s;
}
#elif defined(OS_MACOSX)
CGSize Size::ToCGSize() const {
return CGSizeMake(width_, height_);
}
#endif
void Size::set_width(int width) {
if (width < 0) {
NOTREACHED();
width = 0;
}
width_ = width;
}
void Size::set_height(int height) {
if (height < 0) {
NOTREACHED();
height = 0;
}
height_ = height;
}
} // namespace gfx

View File

@ -1,76 +0,0 @@
// Copyright (c) 2006-2008 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.
#ifndef BASE_GFX_SIZE_H__
#define BASE_GFX_SIZE_H__
#include "build/build_config.h"
#include <ostream>
#if defined(OS_WIN)
typedef struct tagSIZE SIZE;
#elif defined(OS_MACOSX)
#include <ApplicationServices/ApplicationServices.h>
#endif
namespace gfx {
//
// A size has width and height values.
//
class Size {
public:
Size() : width_(0), height_(0) {}
Size(int width, int height);
~Size() {}
int width() const { return width_; }
int height() const { return height_; }
void SetSize(int width, int height) {
set_width(width);
set_height(height);
}
void Enlarge(int width, int height) {
set_width(width_ + width);
set_height(height_ + height);
}
void set_width(int width);
void set_height(int height);
bool operator==(const Size& s) const {
return width_ == s.width_ && height_ == s.height_;
}
bool operator!=(const Size& s) const {
return !(*this == s);
}
bool IsEmpty() const {
// Size doesn't allow negative dimensions, so testing for 0 is enough.
return (width_ == 0) || (height_ == 0);
}
#if defined(OS_WIN)
SIZE ToSIZE() const;
#elif defined(OS_MACOSX)
CGSize ToCGSize() const;
#endif
private:
int width_;
int height_;
};
} // namespace gfx
inline std::ostream& operator<<(std::ostream& out, const gfx::Size& s) {
return out << s.width() << "x" << s.height();
}
#endif // BASE_GFX_SIZE_H__