Wow, it's been a while since we cleaned EOL.
Ran dos2unix on *.cc, *.h, *.py and SCons*.* Ran for /R /D %a in (*.*) do @if exist %a\.svn\. svn pset svn:eol-style LF %a\*.cc Ran for /R /D %a in (*.*) do @if exist %a\.svn\. svn pset svn:eol-style LF %a\*.h Ran for /R /D %a in (*.*) do @if exist %a\.svn\. svn pset svn:eol-style LF %a\*.py Ran for /R /D %a in (*.*) do @if exist %a\.svn\. svn pset svn:eol-style LF %a\SCons*.* git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2611 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
104
base/cpu.cc
104
base/cpu.cc
@ -1,52 +1,52 @@
|
||||
// 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/cpu.h"
|
||||
#include <intrin.h>
|
||||
#include <string>
|
||||
|
||||
namespace base {
|
||||
|
||||
CPU::CPU()
|
||||
: type_(0),
|
||||
family_(0),
|
||||
model_(0),
|
||||
stepping_(0),
|
||||
ext_model_(0),
|
||||
ext_family_(0),
|
||||
cpu_vendor_("unknown") {
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void CPU::Initialize() {
|
||||
int cpu_info[4] = {-1};
|
||||
char cpu_string[0x20];
|
||||
|
||||
// __cpuid with an InfoType argument of 0 returns the number of
|
||||
// valid Ids in CPUInfo[0] and the CPU identification string in
|
||||
// the other three array elements. The CPU identification string is
|
||||
// not in linear order. The code below arranges the information
|
||||
// in a human readable form.
|
||||
//
|
||||
// More info can be found here:
|
||||
// http://msdn.microsoft.com/en-us/library/hskdteyh.aspx
|
||||
__cpuid(cpu_info, 0);
|
||||
int num_ids = cpu_info[0];
|
||||
memset(cpu_string, 0, sizeof(cpu_string));
|
||||
*(reinterpret_cast<int*>(cpu_string)) = cpu_info[1];
|
||||
*(reinterpret_cast<int*>(cpu_string+4)) = cpu_info[3];
|
||||
*(reinterpret_cast<int*>(cpu_string+8)) = cpu_info[2];
|
||||
|
||||
// Interpret CPU feature information.
|
||||
__cpuid(cpu_info, 1);
|
||||
stepping_ = cpu_info[0] & 0xf;
|
||||
model_ = (cpu_info[0] >> 4) & 0xf;
|
||||
family_ = (cpu_info[0] >> 8) & 0xf;
|
||||
type_ = (cpu_info[0] >> 12) & 0x3;
|
||||
ext_model_ = (cpu_info[0] >> 16) & 0xf;
|
||||
ext_family_ = (cpu_info[0] >> 20) & 0xff;
|
||||
cpu_vendor_ = cpu_string;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
// 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/cpu.h"
|
||||
#include <intrin.h>
|
||||
#include <string>
|
||||
|
||||
namespace base {
|
||||
|
||||
CPU::CPU()
|
||||
: type_(0),
|
||||
family_(0),
|
||||
model_(0),
|
||||
stepping_(0),
|
||||
ext_model_(0),
|
||||
ext_family_(0),
|
||||
cpu_vendor_("unknown") {
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void CPU::Initialize() {
|
||||
int cpu_info[4] = {-1};
|
||||
char cpu_string[0x20];
|
||||
|
||||
// __cpuid with an InfoType argument of 0 returns the number of
|
||||
// valid Ids in CPUInfo[0] and the CPU identification string in
|
||||
// the other three array elements. The CPU identification string is
|
||||
// not in linear order. The code below arranges the information
|
||||
// in a human readable form.
|
||||
//
|
||||
// More info can be found here:
|
||||
// http://msdn.microsoft.com/en-us/library/hskdteyh.aspx
|
||||
__cpuid(cpu_info, 0);
|
||||
int num_ids = cpu_info[0];
|
||||
memset(cpu_string, 0, sizeof(cpu_string));
|
||||
*(reinterpret_cast<int*>(cpu_string)) = cpu_info[1];
|
||||
*(reinterpret_cast<int*>(cpu_string+4)) = cpu_info[3];
|
||||
*(reinterpret_cast<int*>(cpu_string+8)) = cpu_info[2];
|
||||
|
||||
// Interpret CPU feature information.
|
||||
__cpuid(cpu_info, 1);
|
||||
stepping_ = cpu_info[0] & 0xf;
|
||||
model_ = (cpu_info[0] >> 4) & 0xf;
|
||||
family_ = (cpu_info[0] >> 8) & 0xf;
|
||||
type_ = (cpu_info[0] >> 12) & 0x3;
|
||||
ext_model_ = (cpu_info[0] >> 16) & 0xf;
|
||||
ext_family_ = (cpu_info[0] >> 20) & 0xff;
|
||||
cpu_vendor_ = cpu_string;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
84
base/cpu.h
84
base/cpu.h
@ -1,42 +1,42 @@
|
||||
// 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_CPU_H_
|
||||
#define BASE_CPU_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace base {
|
||||
|
||||
// Query information about the processor.
|
||||
class CPU {
|
||||
public:
|
||||
// Constructor
|
||||
CPU();
|
||||
|
||||
// Accessors for CPU information.
|
||||
const std::string& vendor_name() const { return cpu_vendor_; }
|
||||
int stepping() const { return stepping_; }
|
||||
int model() const { return model_; }
|
||||
int family() const { return family_; }
|
||||
int type() const { return type_; }
|
||||
int extended_model() const { return ext_model_; }
|
||||
int extended_family() const { return ext_family_; }
|
||||
|
||||
private:
|
||||
// Query the processor for CPUID information.
|
||||
void Initialize();
|
||||
|
||||
int type_; // process type
|
||||
int family_; // family of the processor
|
||||
int model_; // model of processor
|
||||
int stepping_; // processor revision number
|
||||
int ext_model_;
|
||||
int ext_family_;
|
||||
std::string cpu_vendor_;
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_CPU_H_
|
||||
// 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_CPU_H_
|
||||
#define BASE_CPU_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace base {
|
||||
|
||||
// Query information about the processor.
|
||||
class CPU {
|
||||
public:
|
||||
// Constructor
|
||||
CPU();
|
||||
|
||||
// Accessors for CPU information.
|
||||
const std::string& vendor_name() const { return cpu_vendor_; }
|
||||
int stepping() const { return stepping_; }
|
||||
int model() const { return model_; }
|
||||
int family() const { return family_; }
|
||||
int type() const { return type_; }
|
||||
int extended_model() const { return ext_model_; }
|
||||
int extended_family() const { return ext_family_; }
|
||||
|
||||
private:
|
||||
// Query the processor for CPUID information.
|
||||
void Initialize();
|
||||
|
||||
int type_; // process type
|
||||
int family_; // family of the processor
|
||||
int model_; // model of processor
|
||||
int stepping_; // processor revision number
|
||||
int ext_model_;
|
||||
int ext_family_;
|
||||
std::string cpu_vendor_;
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_CPU_H_
|
||||
|
@ -1,31 +1,31 @@
|
||||
// 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_BITMAP_PLATFORM_DEVICE_LINUX_H_
|
||||
#define BASE_GFX_BITMAP_PLATFORM_DEVICE_LINUX_H_
|
||||
|
||||
#include "base/gfx/platform_device_linux.h"
|
||||
#include "base/ref_counted.h"
|
||||
|
||||
namespace gfx {
|
||||
|
||||
// I'm trying to get away with defining as little as possible on this. Right
|
||||
// now, we don't do anything.
|
||||
class BitmapPlatformDeviceLinux : public PlatformDeviceLinux {
|
||||
public:
|
||||
/// Static constructor. I don't understand this, it's just a copy of the mac
|
||||
static BitmapPlatformDeviceLinux* Create(int width, int height,
|
||||
bool is_opaque);
|
||||
|
||||
/// Create a BitmapPlatformDeviceLinux from an already constructed bitmap;
|
||||
/// you should probably be using Create(). This may become private later if
|
||||
/// we ever have to share state between some native drawing UI and Skia, like
|
||||
/// the Windows and Mac versions of this class do.
|
||||
BitmapPlatformDeviceLinux(const SkBitmap& other);
|
||||
virtual ~BitmapPlatformDeviceLinux();
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
#endif // BASE_GFX_BITMAP_PLATFORM_DEVICE_LINUX_H_
|
||||
// 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_BITMAP_PLATFORM_DEVICE_LINUX_H_
|
||||
#define BASE_GFX_BITMAP_PLATFORM_DEVICE_LINUX_H_
|
||||
|
||||
#include "base/gfx/platform_device_linux.h"
|
||||
#include "base/ref_counted.h"
|
||||
|
||||
namespace gfx {
|
||||
|
||||
// I'm trying to get away with defining as little as possible on this. Right
|
||||
// now, we don't do anything.
|
||||
class BitmapPlatformDeviceLinux : public PlatformDeviceLinux {
|
||||
public:
|
||||
/// Static constructor. I don't understand this, it's just a copy of the mac
|
||||
static BitmapPlatformDeviceLinux* Create(int width, int height,
|
||||
bool is_opaque);
|
||||
|
||||
/// Create a BitmapPlatformDeviceLinux from an already constructed bitmap;
|
||||
/// you should probably be using Create(). This may become private later if
|
||||
/// we ever have to share state between some native drawing UI and Skia, like
|
||||
/// the Windows and Mac versions of this class do.
|
||||
BitmapPlatformDeviceLinux(const SkBitmap& other);
|
||||
virtual ~BitmapPlatformDeviceLinux();
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
#endif // BASE_GFX_BITMAP_PLATFORM_DEVICE_LINUX_H_
|
||||
|
@ -1,487 +1,487 @@
|
||||
// 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/bitmap_platform_device_win.h"
|
||||
|
||||
#include "base/gfx/bitmap_header.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/process_util.h"
|
||||
#include "SkMatrix.h"
|
||||
#include "SkRegion.h"
|
||||
#include "SkUtils.h"
|
||||
|
||||
namespace gfx {
|
||||
|
||||
// When Windows draws text, is sets the fourth byte (which Skia uses for alpha)
|
||||
// to zero. This means that if we try compositing with text that Windows has
|
||||
// drawn, we get invalid color values (if the alpha is 0, the other channels
|
||||
// should be 0 since Skia uses premultiplied colors) and strange results.
|
||||
//
|
||||
// HTML rendering only requires one bit of transparency. When you ask for a
|
||||
// semitransparent div, the div itself is drawn in another layer as completely
|
||||
// opaque, and then composited onto the lower layer with a transfer function.
|
||||
// The only place an alpha channel is needed is to track what has been drawn
|
||||
// and what has not been drawn.
|
||||
//
|
||||
// Therefore, when we allocate a new device, we fill it with this special
|
||||
// color. Because Skia uses premultiplied colors, any color where the alpha
|
||||
// channel is smaller than any component is impossible, so we know that no
|
||||
// legitimate drawing will produce this color. We use 1 as the alpha value
|
||||
// because 0 is produced when Windows draws text (even though it should be
|
||||
// opaque).
|
||||
//
|
||||
// When a layer is done and we want to render it to a lower layer, we use
|
||||
// fixupAlphaBeforeCompositing. This replaces all 0 alpha channels with
|
||||
// opaque (to fix the text problem), and replaces this magic color value
|
||||
// with transparency. The result is something that can be correctly
|
||||
// composited. However, once this has been done, no more can be drawn to
|
||||
// the layer because fixing the alphas *again* will result in incorrect
|
||||
// values.
|
||||
static const uint32_t kMagicTransparencyColor = 0x01FFFEFD;
|
||||
|
||||
namespace {
|
||||
|
||||
// Constrains position and size to fit within available_size. If |size| is -1,
|
||||
// all the available_size is used. Returns false if the position is out of
|
||||
// available_size.
|
||||
bool Constrain(int available_size, int* position, int *size) {
|
||||
if (*size < -2)
|
||||
return false;
|
||||
|
||||
if (*position < 0) {
|
||||
if (*size != -1)
|
||||
*size += *position;
|
||||
*position = 0;
|
||||
}
|
||||
if (*size == 0 || *position >= available_size)
|
||||
return false;
|
||||
|
||||
if (*size > 0) {
|
||||
int overflow = (*position + *size) - available_size;
|
||||
if (overflow > 0) {
|
||||
*size -= overflow;
|
||||
}
|
||||
} else {
|
||||
// Fill up available size.
|
||||
*size = available_size - *position;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the pixel value is 0, it gets set to kMagicTransparencyColor.
|
||||
void PrepareAlphaForGDI(uint32_t* pixel) {
|
||||
if (*pixel == 0) {
|
||||
*pixel = kMagicTransparencyColor;
|
||||
}
|
||||
}
|
||||
|
||||
// If the pixel value is kMagicTransparencyColor, it gets set to 0. Otherwise
|
||||
// if the alpha is 0, the alpha is set to 255.
|
||||
void PostProcessAlphaForGDI(uint32_t* pixel) {
|
||||
if (*pixel == kMagicTransparencyColor) {
|
||||
*pixel = 0;
|
||||
} else if ((*pixel & 0xFF000000) == 0) {
|
||||
*pixel |= 0xFF000000;
|
||||
}
|
||||
}
|
||||
|
||||
// Sets the opacity of the specified value to 0xFF.
|
||||
void MakeOpaqueAlphaAdjuster(uint32_t* pixel) {
|
||||
*pixel |= 0xFF000000;
|
||||
}
|
||||
|
||||
// See the declaration of kMagicTransparencyColor at the top of the file.
|
||||
void FixupAlphaBeforeCompositing(uint32_t* pixel) {
|
||||
if (*pixel == kMagicTransparencyColor)
|
||||
*pixel = 0;
|
||||
else
|
||||
*pixel |= 0xFF000000;
|
||||
}
|
||||
|
||||
// Crashes the process. This is called when a bitmap allocation fails, and this
|
||||
// function tries to determine why it might have failed, and crash on different
|
||||
// lines. This allows us to see in crash dumps the most likely reason for the
|
||||
// failure. It takes the size of the bitmap we were trying to allocate as its
|
||||
// arguments so we can check that as well.
|
||||
void CrashForBitmapAllocationFailure(int w, int h) {
|
||||
// The maximum number of GDI objects per process is 10K. If we're very close
|
||||
// to that, it's probably the problem.
|
||||
const int kLotsOfGDIObjs = 9990;
|
||||
CHECK(GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS) < kLotsOfGDIObjs);
|
||||
|
||||
// If the bitmap is ginormous, then we probably can't allocate it.
|
||||
// We use 64M pixels = 256MB @ 4 bytes per pixel.
|
||||
const int64 kGinormousBitmapPxl = 64000000;
|
||||
CHECK(static_cast<int64>(w) * static_cast<int64>(h) < kGinormousBitmapPxl);
|
||||
|
||||
// If we're using a crazy amount of virtual address space, then maybe there
|
||||
// isn't enough for our bitmap.
|
||||
const int64 kLotsOfMem = 1500000000; // 1.5GB.
|
||||
scoped_ptr<process_util::ProcessMetrics> process_metrics(
|
||||
process_util::ProcessMetrics::CreateProcessMetrics(GetCurrentProcess()));
|
||||
CHECK(process_metrics->GetPagefileUsage() < kLotsOfMem);
|
||||
|
||||
// Everything else.
|
||||
CHECK(0);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData
|
||||
: public base::RefCounted<BitmapPlatformDeviceWinData> {
|
||||
public:
|
||||
explicit BitmapPlatformDeviceWinData(HBITMAP hbitmap);
|
||||
|
||||
// Create/destroy hdc_, which is the memory DC for our bitmap data.
|
||||
HDC GetBitmapDC();
|
||||
void ReleaseBitmapDC();
|
||||
bool IsBitmapDCCreated() const;
|
||||
|
||||
// Sets the transform and clip operations. This will not update the DC,
|
||||
// but will mark the config as dirty. The next call of LoadConfig will
|
||||
// pick up these changes.
|
||||
void SetMatrixClip(const SkMatrix& transform, const SkRegion& region);
|
||||
// The device offset is already modified according to the transformation.
|
||||
void SetDeviceOffset(int x, int y);
|
||||
|
||||
const SkMatrix& transform() const {
|
||||
return transform_;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Loads the current transform (taking into account offset_*_) and clip
|
||||
// into the DC. Can be called even when the DC is NULL (will be a NOP).
|
||||
void LoadConfig();
|
||||
|
||||
// Windows bitmap corresponding to our surface.
|
||||
HBITMAP hbitmap_;
|
||||
|
||||
// Lazily-created DC used to draw into the bitmap, see getBitmapDC.
|
||||
HDC hdc_;
|
||||
|
||||
// Additional offset applied to the transform. See setDeviceOffset().
|
||||
int offset_x_;
|
||||
int offset_y_;
|
||||
|
||||
// True when there is a transform or clip that has not been set to the DC.
|
||||
// The DC is retrieved for every text operation, and the transform and clip
|
||||
// do not change as much. We can save time by not loading the clip and
|
||||
// transform for every one.
|
||||
bool config_dirty_;
|
||||
|
||||
// Translation assigned to the DC: we need to keep track of this separately
|
||||
// so it can be updated even if the DC isn't created yet.
|
||||
SkMatrix transform_;
|
||||
|
||||
// The current clipping
|
||||
SkRegion clip_region_;
|
||||
|
||||
private:
|
||||
friend class base::RefCounted<BitmapPlatformDeviceWinData>;
|
||||
~BitmapPlatformDeviceWinData();
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(BitmapPlatformDeviceWinData);
|
||||
};
|
||||
|
||||
BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::BitmapPlatformDeviceWinData(
|
||||
HBITMAP hbitmap)
|
||||
: hbitmap_(hbitmap),
|
||||
hdc_(NULL),
|
||||
offset_x_(0),
|
||||
offset_y_(0),
|
||||
config_dirty_(true) { // Want to load the config next time.
|
||||
// Initialize the clip region to the entire bitmap.
|
||||
BITMAP bitmap_data;
|
||||
if (GetObject(hbitmap_, sizeof(BITMAP), &bitmap_data)) {
|
||||
SkIRect rect;
|
||||
rect.set(0, 0, bitmap_data.bmWidth, bitmap_data.bmHeight);
|
||||
clip_region_ = SkRegion(rect);
|
||||
}
|
||||
|
||||
transform_.reset();
|
||||
}
|
||||
|
||||
BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::~BitmapPlatformDeviceWinData() {
|
||||
if (hdc_)
|
||||
ReleaseBitmapDC();
|
||||
|
||||
// this will free the bitmap data as well as the bitmap handle
|
||||
DeleteObject(hbitmap_);
|
||||
}
|
||||
|
||||
HDC BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::GetBitmapDC() {
|
||||
if (!hdc_) {
|
||||
hdc_ = CreateCompatibleDC(NULL);
|
||||
InitializeDC(hdc_);
|
||||
HGDIOBJ old_bitmap = SelectObject(hdc_, hbitmap_);
|
||||
// When the memory DC is created, its display surface is exactly one
|
||||
// monochrome pixel wide and one monochrome pixel high. Since we select our
|
||||
// own bitmap, we must delete the previous one.
|
||||
DeleteObject(old_bitmap);
|
||||
}
|
||||
|
||||
LoadConfig();
|
||||
return hdc_;
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::ReleaseBitmapDC() {
|
||||
DCHECK(hdc_);
|
||||
DeleteDC(hdc_);
|
||||
hdc_ = NULL;
|
||||
}
|
||||
|
||||
bool BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::IsBitmapDCCreated() const {
|
||||
return hdc_ != NULL;
|
||||
}
|
||||
|
||||
|
||||
void BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::SetMatrixClip(
|
||||
const SkMatrix& transform,
|
||||
const SkRegion& region) {
|
||||
transform_ = transform;
|
||||
clip_region_ = region;
|
||||
config_dirty_ = true;
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::SetDeviceOffset(int x,
|
||||
int y) {
|
||||
offset_x_ = x;
|
||||
offset_y_ = y;
|
||||
config_dirty_ = true;
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::LoadConfig() {
|
||||
if (!config_dirty_ || !hdc_)
|
||||
return; // Nothing to do.
|
||||
config_dirty_ = false;
|
||||
|
||||
// Transform.
|
||||
SkMatrix t(transform_);
|
||||
t.postTranslate(SkIntToScalar(-offset_x_), SkIntToScalar(-offset_y_));
|
||||
LoadTransformToDC(hdc_, t);
|
||||
// We don't use transform_ for the clipping region since the translation is
|
||||
// already applied to offset_x_ and offset_y_.
|
||||
t.reset();
|
||||
t.postTranslate(SkIntToScalar(-offset_x_), SkIntToScalar(-offset_y_));
|
||||
LoadClippingRegionToDC(hdc_, clip_region_, t);
|
||||
}
|
||||
|
||||
// We use this static factory function instead of the regular constructor so
|
||||
// that we can create the pixel data before calling the constructor. This is
|
||||
// required so that we can call the base class' constructor with the pixel
|
||||
// data.
|
||||
BitmapPlatformDeviceWin* BitmapPlatformDeviceWin::create(HDC screen_dc,
|
||||
int width,
|
||||
int height,
|
||||
bool is_opaque,
|
||||
HANDLE shared_section) {
|
||||
SkBitmap bitmap;
|
||||
|
||||
// CreateDIBSection appears to get unhappy if we create an empty bitmap, so
|
||||
// we just expand it here.
|
||||
if (width == 0)
|
||||
width = 1;
|
||||
if (height == 0)
|
||||
height = 1;
|
||||
|
||||
BITMAPINFOHEADER hdr;
|
||||
CreateBitmapHeader(width, height, &hdr);
|
||||
|
||||
void* data;
|
||||
HBITMAP hbitmap = CreateDIBSection(screen_dc,
|
||||
reinterpret_cast<BITMAPINFO*>(&hdr), 0,
|
||||
&data,
|
||||
shared_section, 0);
|
||||
|
||||
// If we run out of GDI objects or some other error occurs, we won't get a
|
||||
// bitmap here. This will cause us to crash later because the data pointer is
|
||||
// NULL. To make sure that we can assign blame for those crashes to this code,
|
||||
// we deliberately crash here, even in release mode.
|
||||
if (!hbitmap)
|
||||
CrashForBitmapAllocationFailure(width, height);
|
||||
|
||||
bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
|
||||
bitmap.setPixels(data);
|
||||
bitmap.setIsOpaque(is_opaque);
|
||||
|
||||
if (is_opaque) {
|
||||
#ifndef NDEBUG
|
||||
// To aid in finding bugs, we set the background color to something
|
||||
// obviously wrong so it will be noticable when it is not cleared
|
||||
bitmap.eraseARGB(255, 0, 255, 128); // bright bluish green
|
||||
#endif
|
||||
} else {
|
||||
// A transparent layer is requested: fill with our magic "transparent"
|
||||
// color, see the declaration of kMagicTransparencyColor above
|
||||
sk_memset32(static_cast<uint32_t*>(data), kMagicTransparencyColor,
|
||||
width * height);
|
||||
}
|
||||
|
||||
// The device object will take ownership of the HBITMAP.
|
||||
return new BitmapPlatformDeviceWin(new BitmapPlatformDeviceWinData(hbitmap), bitmap);
|
||||
}
|
||||
|
||||
// The device will own the HBITMAP, which corresponds to also owning the pixel
|
||||
// data. Therefore, we do not transfer ownership to the SkDevice's bitmap.
|
||||
BitmapPlatformDeviceWin::BitmapPlatformDeviceWin(BitmapPlatformDeviceWinData* data,
|
||||
const SkBitmap& bitmap)
|
||||
: PlatformDeviceWin(bitmap),
|
||||
data_(data) {
|
||||
}
|
||||
|
||||
// The copy constructor just adds another reference to the underlying data.
|
||||
// We use a const cast since the default Skia definitions don't define the
|
||||
// proper constedness that we expect (accessBitmap should really be const).
|
||||
BitmapPlatformDeviceWin::BitmapPlatformDeviceWin(const BitmapPlatformDeviceWin& other)
|
||||
: PlatformDeviceWin(
|
||||
const_cast<BitmapPlatformDeviceWin&>(other).accessBitmap(true)),
|
||||
data_(other.data_) {
|
||||
}
|
||||
|
||||
BitmapPlatformDeviceWin::~BitmapPlatformDeviceWin() {
|
||||
}
|
||||
|
||||
BitmapPlatformDeviceWin& BitmapPlatformDeviceWin::operator=(
|
||||
const BitmapPlatformDeviceWin& other) {
|
||||
data_ = other.data_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
HDC BitmapPlatformDeviceWin::getBitmapDC() {
|
||||
return data_->GetBitmapDC();
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::setMatrixClip(const SkMatrix& transform,
|
||||
const SkRegion& region) {
|
||||
data_->SetMatrixClip(transform, region);
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::setDeviceOffset(int x, int y) {
|
||||
data_->SetDeviceOffset(x, y);
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::drawToHDC(HDC dc, int x, int y,
|
||||
const RECT* src_rect) {
|
||||
bool created_dc = !data_->IsBitmapDCCreated();
|
||||
HDC source_dc = getBitmapDC();
|
||||
|
||||
RECT temp_rect;
|
||||
if (!src_rect) {
|
||||
temp_rect.left = 0;
|
||||
temp_rect.right = width();
|
||||
temp_rect.top = 0;
|
||||
temp_rect.bottom = height();
|
||||
src_rect = &temp_rect;
|
||||
}
|
||||
|
||||
int copy_width = src_rect->right - src_rect->left;
|
||||
int copy_height = src_rect->bottom - src_rect->top;
|
||||
|
||||
// We need to reset the translation for our bitmap or (0,0) won't be in the
|
||||
// upper left anymore
|
||||
SkMatrix identity;
|
||||
identity.reset();
|
||||
|
||||
LoadTransformToDC(source_dc, identity);
|
||||
if (isOpaque()) {
|
||||
BitBlt(dc,
|
||||
x,
|
||||
y,
|
||||
copy_width,
|
||||
copy_height,
|
||||
source_dc,
|
||||
src_rect->left,
|
||||
src_rect->top,
|
||||
SRCCOPY);
|
||||
} else {
|
||||
BLENDFUNCTION blend_function = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
|
||||
AlphaBlend(dc,
|
||||
x,
|
||||
y,
|
||||
copy_width,
|
||||
copy_height,
|
||||
source_dc,
|
||||
src_rect->left,
|
||||
src_rect->top,
|
||||
copy_width,
|
||||
copy_height,
|
||||
blend_function);
|
||||
}
|
||||
LoadTransformToDC(source_dc, data_->transform());
|
||||
|
||||
if (created_dc)
|
||||
data_->ReleaseBitmapDC();
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::prepareForGDI(int x, int y, int width, int height) {
|
||||
processPixels<PrepareAlphaForGDI>(x, y, width, height);
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::postProcessGDI(int x, int y, int width, int height) {
|
||||
processPixels<PostProcessAlphaForGDI>(x, y, width, height);
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::makeOpaque(int x, int y, int width, int height) {
|
||||
processPixels<MakeOpaqueAlphaAdjuster>(x, y, width, height);
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::fixupAlphaBeforeCompositing() {
|
||||
const SkBitmap& bitmap = accessBitmap(true);
|
||||
SkAutoLockPixels lock(bitmap);
|
||||
uint32_t* data = bitmap.getAddr32(0, 0);
|
||||
|
||||
size_t words = bitmap.rowBytes() / sizeof(uint32_t) * bitmap.height();
|
||||
for (size_t i = 0; i < words; i++) {
|
||||
if (data[i] == kMagicTransparencyColor)
|
||||
data[i] = 0;
|
||||
else
|
||||
data[i] |= 0xFF000000;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the color value at the specified location.
|
||||
SkColor BitmapPlatformDeviceWin::getColorAt(int x, int y) {
|
||||
const SkBitmap& bitmap = accessBitmap(false);
|
||||
SkAutoLockPixels lock(bitmap);
|
||||
uint32_t* data = bitmap.getAddr32(0, 0);
|
||||
return static_cast<SkColor>(data[x + y * width()]);
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::onAccessBitmap(SkBitmap* bitmap) {
|
||||
// FIXME(brettw) OPTIMIZATION: We should only flush if we know a GDI
|
||||
// operation has occurred on our DC.
|
||||
if (data_->IsBitmapDCCreated())
|
||||
GdiFlush();
|
||||
}
|
||||
|
||||
template<BitmapPlatformDeviceWin::adjustAlpha adjustor>
|
||||
void BitmapPlatformDeviceWin::processPixels(int x,
|
||||
int y,
|
||||
int width,
|
||||
int height) {
|
||||
const SkBitmap& bitmap = accessBitmap(true);
|
||||
DCHECK_EQ(bitmap.config(), SkBitmap::kARGB_8888_Config);
|
||||
const SkMatrix& matrix = data_->transform();
|
||||
int bitmap_start_x = SkScalarRound(matrix.getTranslateX()) + x;
|
||||
int bitmap_start_y = SkScalarRound(matrix.getTranslateY()) + y;
|
||||
|
||||
if (Constrain(bitmap.width(), &bitmap_start_x, &width) &&
|
||||
Constrain(bitmap.height(), &bitmap_start_y, &height)) {
|
||||
SkAutoLockPixels lock(bitmap);
|
||||
DCHECK_EQ(bitmap.rowBytes() % sizeof(uint32_t), 0u);
|
||||
size_t row_words = bitmap.rowBytes() / sizeof(uint32_t);
|
||||
// Set data to the first pixel to be modified.
|
||||
uint32_t* data = bitmap.getAddr32(0, 0) + (bitmap_start_y * row_words) +
|
||||
bitmap_start_x;
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
adjustor(data + j);
|
||||
}
|
||||
data += row_words;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
// 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/bitmap_platform_device_win.h"
|
||||
|
||||
#include "base/gfx/bitmap_header.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/process_util.h"
|
||||
#include "SkMatrix.h"
|
||||
#include "SkRegion.h"
|
||||
#include "SkUtils.h"
|
||||
|
||||
namespace gfx {
|
||||
|
||||
// When Windows draws text, is sets the fourth byte (which Skia uses for alpha)
|
||||
// to zero. This means that if we try compositing with text that Windows has
|
||||
// drawn, we get invalid color values (if the alpha is 0, the other channels
|
||||
// should be 0 since Skia uses premultiplied colors) and strange results.
|
||||
//
|
||||
// HTML rendering only requires one bit of transparency. When you ask for a
|
||||
// semitransparent div, the div itself is drawn in another layer as completely
|
||||
// opaque, and then composited onto the lower layer with a transfer function.
|
||||
// The only place an alpha channel is needed is to track what has been drawn
|
||||
// and what has not been drawn.
|
||||
//
|
||||
// Therefore, when we allocate a new device, we fill it with this special
|
||||
// color. Because Skia uses premultiplied colors, any color where the alpha
|
||||
// channel is smaller than any component is impossible, so we know that no
|
||||
// legitimate drawing will produce this color. We use 1 as the alpha value
|
||||
// because 0 is produced when Windows draws text (even though it should be
|
||||
// opaque).
|
||||
//
|
||||
// When a layer is done and we want to render it to a lower layer, we use
|
||||
// fixupAlphaBeforeCompositing. This replaces all 0 alpha channels with
|
||||
// opaque (to fix the text problem), and replaces this magic color value
|
||||
// with transparency. The result is something that can be correctly
|
||||
// composited. However, once this has been done, no more can be drawn to
|
||||
// the layer because fixing the alphas *again* will result in incorrect
|
||||
// values.
|
||||
static const uint32_t kMagicTransparencyColor = 0x01FFFEFD;
|
||||
|
||||
namespace {
|
||||
|
||||
// Constrains position and size to fit within available_size. If |size| is -1,
|
||||
// all the available_size is used. Returns false if the position is out of
|
||||
// available_size.
|
||||
bool Constrain(int available_size, int* position, int *size) {
|
||||
if (*size < -2)
|
||||
return false;
|
||||
|
||||
if (*position < 0) {
|
||||
if (*size != -1)
|
||||
*size += *position;
|
||||
*position = 0;
|
||||
}
|
||||
if (*size == 0 || *position >= available_size)
|
||||
return false;
|
||||
|
||||
if (*size > 0) {
|
||||
int overflow = (*position + *size) - available_size;
|
||||
if (overflow > 0) {
|
||||
*size -= overflow;
|
||||
}
|
||||
} else {
|
||||
// Fill up available size.
|
||||
*size = available_size - *position;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the pixel value is 0, it gets set to kMagicTransparencyColor.
|
||||
void PrepareAlphaForGDI(uint32_t* pixel) {
|
||||
if (*pixel == 0) {
|
||||
*pixel = kMagicTransparencyColor;
|
||||
}
|
||||
}
|
||||
|
||||
// If the pixel value is kMagicTransparencyColor, it gets set to 0. Otherwise
|
||||
// if the alpha is 0, the alpha is set to 255.
|
||||
void PostProcessAlphaForGDI(uint32_t* pixel) {
|
||||
if (*pixel == kMagicTransparencyColor) {
|
||||
*pixel = 0;
|
||||
} else if ((*pixel & 0xFF000000) == 0) {
|
||||
*pixel |= 0xFF000000;
|
||||
}
|
||||
}
|
||||
|
||||
// Sets the opacity of the specified value to 0xFF.
|
||||
void MakeOpaqueAlphaAdjuster(uint32_t* pixel) {
|
||||
*pixel |= 0xFF000000;
|
||||
}
|
||||
|
||||
// See the declaration of kMagicTransparencyColor at the top of the file.
|
||||
void FixupAlphaBeforeCompositing(uint32_t* pixel) {
|
||||
if (*pixel == kMagicTransparencyColor)
|
||||
*pixel = 0;
|
||||
else
|
||||
*pixel |= 0xFF000000;
|
||||
}
|
||||
|
||||
// Crashes the process. This is called when a bitmap allocation fails, and this
|
||||
// function tries to determine why it might have failed, and crash on different
|
||||
// lines. This allows us to see in crash dumps the most likely reason for the
|
||||
// failure. It takes the size of the bitmap we were trying to allocate as its
|
||||
// arguments so we can check that as well.
|
||||
void CrashForBitmapAllocationFailure(int w, int h) {
|
||||
// The maximum number of GDI objects per process is 10K. If we're very close
|
||||
// to that, it's probably the problem.
|
||||
const int kLotsOfGDIObjs = 9990;
|
||||
CHECK(GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS) < kLotsOfGDIObjs);
|
||||
|
||||
// If the bitmap is ginormous, then we probably can't allocate it.
|
||||
// We use 64M pixels = 256MB @ 4 bytes per pixel.
|
||||
const int64 kGinormousBitmapPxl = 64000000;
|
||||
CHECK(static_cast<int64>(w) * static_cast<int64>(h) < kGinormousBitmapPxl);
|
||||
|
||||
// If we're using a crazy amount of virtual address space, then maybe there
|
||||
// isn't enough for our bitmap.
|
||||
const int64 kLotsOfMem = 1500000000; // 1.5GB.
|
||||
scoped_ptr<process_util::ProcessMetrics> process_metrics(
|
||||
process_util::ProcessMetrics::CreateProcessMetrics(GetCurrentProcess()));
|
||||
CHECK(process_metrics->GetPagefileUsage() < kLotsOfMem);
|
||||
|
||||
// Everything else.
|
||||
CHECK(0);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData
|
||||
: public base::RefCounted<BitmapPlatformDeviceWinData> {
|
||||
public:
|
||||
explicit BitmapPlatformDeviceWinData(HBITMAP hbitmap);
|
||||
|
||||
// Create/destroy hdc_, which is the memory DC for our bitmap data.
|
||||
HDC GetBitmapDC();
|
||||
void ReleaseBitmapDC();
|
||||
bool IsBitmapDCCreated() const;
|
||||
|
||||
// Sets the transform and clip operations. This will not update the DC,
|
||||
// but will mark the config as dirty. The next call of LoadConfig will
|
||||
// pick up these changes.
|
||||
void SetMatrixClip(const SkMatrix& transform, const SkRegion& region);
|
||||
// The device offset is already modified according to the transformation.
|
||||
void SetDeviceOffset(int x, int y);
|
||||
|
||||
const SkMatrix& transform() const {
|
||||
return transform_;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Loads the current transform (taking into account offset_*_) and clip
|
||||
// into the DC. Can be called even when the DC is NULL (will be a NOP).
|
||||
void LoadConfig();
|
||||
|
||||
// Windows bitmap corresponding to our surface.
|
||||
HBITMAP hbitmap_;
|
||||
|
||||
// Lazily-created DC used to draw into the bitmap, see getBitmapDC.
|
||||
HDC hdc_;
|
||||
|
||||
// Additional offset applied to the transform. See setDeviceOffset().
|
||||
int offset_x_;
|
||||
int offset_y_;
|
||||
|
||||
// True when there is a transform or clip that has not been set to the DC.
|
||||
// The DC is retrieved for every text operation, and the transform and clip
|
||||
// do not change as much. We can save time by not loading the clip and
|
||||
// transform for every one.
|
||||
bool config_dirty_;
|
||||
|
||||
// Translation assigned to the DC: we need to keep track of this separately
|
||||
// so it can be updated even if the DC isn't created yet.
|
||||
SkMatrix transform_;
|
||||
|
||||
// The current clipping
|
||||
SkRegion clip_region_;
|
||||
|
||||
private:
|
||||
friend class base::RefCounted<BitmapPlatformDeviceWinData>;
|
||||
~BitmapPlatformDeviceWinData();
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(BitmapPlatformDeviceWinData);
|
||||
};
|
||||
|
||||
BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::BitmapPlatformDeviceWinData(
|
||||
HBITMAP hbitmap)
|
||||
: hbitmap_(hbitmap),
|
||||
hdc_(NULL),
|
||||
offset_x_(0),
|
||||
offset_y_(0),
|
||||
config_dirty_(true) { // Want to load the config next time.
|
||||
// Initialize the clip region to the entire bitmap.
|
||||
BITMAP bitmap_data;
|
||||
if (GetObject(hbitmap_, sizeof(BITMAP), &bitmap_data)) {
|
||||
SkIRect rect;
|
||||
rect.set(0, 0, bitmap_data.bmWidth, bitmap_data.bmHeight);
|
||||
clip_region_ = SkRegion(rect);
|
||||
}
|
||||
|
||||
transform_.reset();
|
||||
}
|
||||
|
||||
BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::~BitmapPlatformDeviceWinData() {
|
||||
if (hdc_)
|
||||
ReleaseBitmapDC();
|
||||
|
||||
// this will free the bitmap data as well as the bitmap handle
|
||||
DeleteObject(hbitmap_);
|
||||
}
|
||||
|
||||
HDC BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::GetBitmapDC() {
|
||||
if (!hdc_) {
|
||||
hdc_ = CreateCompatibleDC(NULL);
|
||||
InitializeDC(hdc_);
|
||||
HGDIOBJ old_bitmap = SelectObject(hdc_, hbitmap_);
|
||||
// When the memory DC is created, its display surface is exactly one
|
||||
// monochrome pixel wide and one monochrome pixel high. Since we select our
|
||||
// own bitmap, we must delete the previous one.
|
||||
DeleteObject(old_bitmap);
|
||||
}
|
||||
|
||||
LoadConfig();
|
||||
return hdc_;
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::ReleaseBitmapDC() {
|
||||
DCHECK(hdc_);
|
||||
DeleteDC(hdc_);
|
||||
hdc_ = NULL;
|
||||
}
|
||||
|
||||
bool BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::IsBitmapDCCreated() const {
|
||||
return hdc_ != NULL;
|
||||
}
|
||||
|
||||
|
||||
void BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::SetMatrixClip(
|
||||
const SkMatrix& transform,
|
||||
const SkRegion& region) {
|
||||
transform_ = transform;
|
||||
clip_region_ = region;
|
||||
config_dirty_ = true;
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::SetDeviceOffset(int x,
|
||||
int y) {
|
||||
offset_x_ = x;
|
||||
offset_y_ = y;
|
||||
config_dirty_ = true;
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::LoadConfig() {
|
||||
if (!config_dirty_ || !hdc_)
|
||||
return; // Nothing to do.
|
||||
config_dirty_ = false;
|
||||
|
||||
// Transform.
|
||||
SkMatrix t(transform_);
|
||||
t.postTranslate(SkIntToScalar(-offset_x_), SkIntToScalar(-offset_y_));
|
||||
LoadTransformToDC(hdc_, t);
|
||||
// We don't use transform_ for the clipping region since the translation is
|
||||
// already applied to offset_x_ and offset_y_.
|
||||
t.reset();
|
||||
t.postTranslate(SkIntToScalar(-offset_x_), SkIntToScalar(-offset_y_));
|
||||
LoadClippingRegionToDC(hdc_, clip_region_, t);
|
||||
}
|
||||
|
||||
// We use this static factory function instead of the regular constructor so
|
||||
// that we can create the pixel data before calling the constructor. This is
|
||||
// required so that we can call the base class' constructor with the pixel
|
||||
// data.
|
||||
BitmapPlatformDeviceWin* BitmapPlatformDeviceWin::create(HDC screen_dc,
|
||||
int width,
|
||||
int height,
|
||||
bool is_opaque,
|
||||
HANDLE shared_section) {
|
||||
SkBitmap bitmap;
|
||||
|
||||
// CreateDIBSection appears to get unhappy if we create an empty bitmap, so
|
||||
// we just expand it here.
|
||||
if (width == 0)
|
||||
width = 1;
|
||||
if (height == 0)
|
||||
height = 1;
|
||||
|
||||
BITMAPINFOHEADER hdr;
|
||||
CreateBitmapHeader(width, height, &hdr);
|
||||
|
||||
void* data;
|
||||
HBITMAP hbitmap = CreateDIBSection(screen_dc,
|
||||
reinterpret_cast<BITMAPINFO*>(&hdr), 0,
|
||||
&data,
|
||||
shared_section, 0);
|
||||
|
||||
// If we run out of GDI objects or some other error occurs, we won't get a
|
||||
// bitmap here. This will cause us to crash later because the data pointer is
|
||||
// NULL. To make sure that we can assign blame for those crashes to this code,
|
||||
// we deliberately crash here, even in release mode.
|
||||
if (!hbitmap)
|
||||
CrashForBitmapAllocationFailure(width, height);
|
||||
|
||||
bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
|
||||
bitmap.setPixels(data);
|
||||
bitmap.setIsOpaque(is_opaque);
|
||||
|
||||
if (is_opaque) {
|
||||
#ifndef NDEBUG
|
||||
// To aid in finding bugs, we set the background color to something
|
||||
// obviously wrong so it will be noticable when it is not cleared
|
||||
bitmap.eraseARGB(255, 0, 255, 128); // bright bluish green
|
||||
#endif
|
||||
} else {
|
||||
// A transparent layer is requested: fill with our magic "transparent"
|
||||
// color, see the declaration of kMagicTransparencyColor above
|
||||
sk_memset32(static_cast<uint32_t*>(data), kMagicTransparencyColor,
|
||||
width * height);
|
||||
}
|
||||
|
||||
// The device object will take ownership of the HBITMAP.
|
||||
return new BitmapPlatformDeviceWin(new BitmapPlatformDeviceWinData(hbitmap), bitmap);
|
||||
}
|
||||
|
||||
// The device will own the HBITMAP, which corresponds to also owning the pixel
|
||||
// data. Therefore, we do not transfer ownership to the SkDevice's bitmap.
|
||||
BitmapPlatformDeviceWin::BitmapPlatformDeviceWin(BitmapPlatformDeviceWinData* data,
|
||||
const SkBitmap& bitmap)
|
||||
: PlatformDeviceWin(bitmap),
|
||||
data_(data) {
|
||||
}
|
||||
|
||||
// The copy constructor just adds another reference to the underlying data.
|
||||
// We use a const cast since the default Skia definitions don't define the
|
||||
// proper constedness that we expect (accessBitmap should really be const).
|
||||
BitmapPlatformDeviceWin::BitmapPlatformDeviceWin(const BitmapPlatformDeviceWin& other)
|
||||
: PlatformDeviceWin(
|
||||
const_cast<BitmapPlatformDeviceWin&>(other).accessBitmap(true)),
|
||||
data_(other.data_) {
|
||||
}
|
||||
|
||||
BitmapPlatformDeviceWin::~BitmapPlatformDeviceWin() {
|
||||
}
|
||||
|
||||
BitmapPlatformDeviceWin& BitmapPlatformDeviceWin::operator=(
|
||||
const BitmapPlatformDeviceWin& other) {
|
||||
data_ = other.data_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
HDC BitmapPlatformDeviceWin::getBitmapDC() {
|
||||
return data_->GetBitmapDC();
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::setMatrixClip(const SkMatrix& transform,
|
||||
const SkRegion& region) {
|
||||
data_->SetMatrixClip(transform, region);
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::setDeviceOffset(int x, int y) {
|
||||
data_->SetDeviceOffset(x, y);
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::drawToHDC(HDC dc, int x, int y,
|
||||
const RECT* src_rect) {
|
||||
bool created_dc = !data_->IsBitmapDCCreated();
|
||||
HDC source_dc = getBitmapDC();
|
||||
|
||||
RECT temp_rect;
|
||||
if (!src_rect) {
|
||||
temp_rect.left = 0;
|
||||
temp_rect.right = width();
|
||||
temp_rect.top = 0;
|
||||
temp_rect.bottom = height();
|
||||
src_rect = &temp_rect;
|
||||
}
|
||||
|
||||
int copy_width = src_rect->right - src_rect->left;
|
||||
int copy_height = src_rect->bottom - src_rect->top;
|
||||
|
||||
// We need to reset the translation for our bitmap or (0,0) won't be in the
|
||||
// upper left anymore
|
||||
SkMatrix identity;
|
||||
identity.reset();
|
||||
|
||||
LoadTransformToDC(source_dc, identity);
|
||||
if (isOpaque()) {
|
||||
BitBlt(dc,
|
||||
x,
|
||||
y,
|
||||
copy_width,
|
||||
copy_height,
|
||||
source_dc,
|
||||
src_rect->left,
|
||||
src_rect->top,
|
||||
SRCCOPY);
|
||||
} else {
|
||||
BLENDFUNCTION blend_function = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
|
||||
AlphaBlend(dc,
|
||||
x,
|
||||
y,
|
||||
copy_width,
|
||||
copy_height,
|
||||
source_dc,
|
||||
src_rect->left,
|
||||
src_rect->top,
|
||||
copy_width,
|
||||
copy_height,
|
||||
blend_function);
|
||||
}
|
||||
LoadTransformToDC(source_dc, data_->transform());
|
||||
|
||||
if (created_dc)
|
||||
data_->ReleaseBitmapDC();
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::prepareForGDI(int x, int y, int width, int height) {
|
||||
processPixels<PrepareAlphaForGDI>(x, y, width, height);
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::postProcessGDI(int x, int y, int width, int height) {
|
||||
processPixels<PostProcessAlphaForGDI>(x, y, width, height);
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::makeOpaque(int x, int y, int width, int height) {
|
||||
processPixels<MakeOpaqueAlphaAdjuster>(x, y, width, height);
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::fixupAlphaBeforeCompositing() {
|
||||
const SkBitmap& bitmap = accessBitmap(true);
|
||||
SkAutoLockPixels lock(bitmap);
|
||||
uint32_t* data = bitmap.getAddr32(0, 0);
|
||||
|
||||
size_t words = bitmap.rowBytes() / sizeof(uint32_t) * bitmap.height();
|
||||
for (size_t i = 0; i < words; i++) {
|
||||
if (data[i] == kMagicTransparencyColor)
|
||||
data[i] = 0;
|
||||
else
|
||||
data[i] |= 0xFF000000;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the color value at the specified location.
|
||||
SkColor BitmapPlatformDeviceWin::getColorAt(int x, int y) {
|
||||
const SkBitmap& bitmap = accessBitmap(false);
|
||||
SkAutoLockPixels lock(bitmap);
|
||||
uint32_t* data = bitmap.getAddr32(0, 0);
|
||||
return static_cast<SkColor>(data[x + y * width()]);
|
||||
}
|
||||
|
||||
void BitmapPlatformDeviceWin::onAccessBitmap(SkBitmap* bitmap) {
|
||||
// FIXME(brettw) OPTIMIZATION: We should only flush if we know a GDI
|
||||
// operation has occurred on our DC.
|
||||
if (data_->IsBitmapDCCreated())
|
||||
GdiFlush();
|
||||
}
|
||||
|
||||
template<BitmapPlatformDeviceWin::adjustAlpha adjustor>
|
||||
void BitmapPlatformDeviceWin::processPixels(int x,
|
||||
int y,
|
||||
int width,
|
||||
int height) {
|
||||
const SkBitmap& bitmap = accessBitmap(true);
|
||||
DCHECK_EQ(bitmap.config(), SkBitmap::kARGB_8888_Config);
|
||||
const SkMatrix& matrix = data_->transform();
|
||||
int bitmap_start_x = SkScalarRound(matrix.getTranslateX()) + x;
|
||||
int bitmap_start_y = SkScalarRound(matrix.getTranslateY()) + y;
|
||||
|
||||
if (Constrain(bitmap.width(), &bitmap_start_x, &width) &&
|
||||
Constrain(bitmap.height(), &bitmap_start_y, &height)) {
|
||||
SkAutoLockPixels lock(bitmap);
|
||||
DCHECK_EQ(bitmap.rowBytes() % sizeof(uint32_t), 0u);
|
||||
size_t row_words = bitmap.rowBytes() / sizeof(uint32_t);
|
||||
// Set data to the first pixel to be modified.
|
||||
uint32_t* data = bitmap.getAddr32(0, 0) + (bitmap_start_y * row_words) +
|
||||
bitmap_start_x;
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
adjustor(data + j);
|
||||
}
|
||||
data += row_words;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
|
@ -1,111 +1,111 @@
|
||||
// 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_BITMAP_PLATFORM_DEVICE_WIN_H__
|
||||
#define BASE_GFX_BITMAP_PLATFORM_DEVICE_WIN_H__
|
||||
|
||||
#include "base/gfx/platform_device_win.h"
|
||||
#include "base/ref_counted.h"
|
||||
|
||||
namespace gfx {
|
||||
|
||||
// A device is basically a wrapper around SkBitmap that provides a surface for
|
||||
// SkCanvas to draw into. Our device provides a surface Windows can also write
|
||||
// to. BitmapPlatformDeviceWin creates a bitmap using CreateDIBSection() in a
|
||||
// format that Skia supports and can then use this to draw ClearType into, etc.
|
||||
// This pixel data is provided to the bitmap that the device contains so that it
|
||||
// can be shared.
|
||||
//
|
||||
// The device owns the pixel data, when the device goes away, the pixel data
|
||||
// also becomes invalid. THIS IS DIFFERENT THAN NORMAL SKIA which uses
|
||||
// reference counting for the pixel data. In normal Skia, you could assign
|
||||
// another bitmap to this device's bitmap and everything will work properly.
|
||||
// For us, that other bitmap will become invalid as soon as the device becomes
|
||||
// invalid, which may lead to subtle bugs. Therefore, DO NOT ASSIGN THE
|
||||
// DEVICE'S PIXEL DATA TO ANOTHER BITMAP, make sure you copy instead.
|
||||
class BitmapPlatformDeviceWin : public PlatformDeviceWin {
|
||||
public:
|
||||
// Factory function. The screen DC is used to create the bitmap, and will not
|
||||
// be stored beyond this function. is_opaque should be set if the caller
|
||||
// knows the bitmap will be completely opaque and allows some optimizations.
|
||||
//
|
||||
// The shared_section parameter is optional (pass NULL for default behavior).
|
||||
// If shared_section is non-null, then it must be a handle to a file-mapping
|
||||
// object returned by CreateFileMapping. See CreateDIBSection for details.
|
||||
static BitmapPlatformDeviceWin* create(HDC screen_dc,
|
||||
int width,
|
||||
int height,
|
||||
bool is_opaque,
|
||||
HANDLE shared_section);
|
||||
|
||||
// Copy constructor. When copied, devices duplicate their internal data, so
|
||||
// stay linked. This is because their implementation is very heavyweight
|
||||
// (lots of memory and some GDI objects). If a device has been copied, both
|
||||
// clip rects and other state will stay in sync.
|
||||
//
|
||||
// This means it will NOT work to duplicate a device and assign it to a
|
||||
// canvas, because the two canvases will each set their own clip rects, and
|
||||
// the resulting GDI clip rect will be random.
|
||||
//
|
||||
// Copy constucting and "=" is designed for saving the device or passing it
|
||||
// around to another routine willing to deal with the bitmap data directly.
|
||||
BitmapPlatformDeviceWin(const BitmapPlatformDeviceWin& other);
|
||||
virtual ~BitmapPlatformDeviceWin();
|
||||
|
||||
// See warning for copy constructor above.
|
||||
BitmapPlatformDeviceWin& operator=(const BitmapPlatformDeviceWin& other);
|
||||
|
||||
// Retrieves the bitmap DC, which is the memory DC for our bitmap data. The
|
||||
// bitmap DC is lazy created.
|
||||
virtual HDC getBitmapDC();
|
||||
virtual void setMatrixClip(const SkMatrix& transform, const SkRegion& region);
|
||||
virtual void setDeviceOffset(int x, int y);
|
||||
|
||||
virtual void drawToHDC(HDC dc, int x, int y, const RECT* src_rect);
|
||||
virtual void prepareForGDI(int x, int y, int width, int height);
|
||||
virtual void postProcessGDI(int x, int y, int width, int height);
|
||||
virtual void makeOpaque(int x, int y, int width, int height);
|
||||
virtual void fixupAlphaBeforeCompositing();
|
||||
virtual bool IsVectorial() { return false; }
|
||||
|
||||
// Returns the color value at the specified location. This does not
|
||||
// consider any transforms that may be set on the device.
|
||||
SkColor getColorAt(int x, int y);
|
||||
|
||||
protected:
|
||||
// Flushes the Windows device context so that the pixel data can be accessed
|
||||
// directly by Skia. Overridden from SkDevice, this is called when Skia
|
||||
// starts accessing pixel data.
|
||||
virtual void onAccessBitmap(SkBitmap* bitmap);
|
||||
|
||||
private:
|
||||
// Function pointer used by the processPixels method for setting the alpha
|
||||
// value of a particular pixel.
|
||||
typedef void (*adjustAlpha)(uint32_t* pixel);
|
||||
|
||||
// Reference counted data that can be shared between multiple devices. This
|
||||
// allows copy constructors and operator= for devices to work properly. The
|
||||
// bitmaps used by the base device class are already refcounted and copyable.
|
||||
class BitmapPlatformDeviceWinData;
|
||||
|
||||
// Private constructor.
|
||||
BitmapPlatformDeviceWin(BitmapPlatformDeviceWinData* data, const SkBitmap& bitmap);
|
||||
|
||||
// Loops through each of the pixels in the specified range, invoking
|
||||
// adjustor for the alpha value of each pixel. If |width| or |height| are -1,
|
||||
// the available width/height is used.
|
||||
template<adjustAlpha adjustor>
|
||||
void processPixels(int x,
|
||||
int y,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
// Data associated with this device, guaranteed non-null.
|
||||
scoped_refptr<BitmapPlatformDeviceWinData> data_;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
#endif // BASE_GFX_BITMAP_PLATFORM_DEVICE_WIN_H__
|
||||
|
||||
// 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_BITMAP_PLATFORM_DEVICE_WIN_H__
|
||||
#define BASE_GFX_BITMAP_PLATFORM_DEVICE_WIN_H__
|
||||
|
||||
#include "base/gfx/platform_device_win.h"
|
||||
#include "base/ref_counted.h"
|
||||
|
||||
namespace gfx {
|
||||
|
||||
// A device is basically a wrapper around SkBitmap that provides a surface for
|
||||
// SkCanvas to draw into. Our device provides a surface Windows can also write
|
||||
// to. BitmapPlatformDeviceWin creates a bitmap using CreateDIBSection() in a
|
||||
// format that Skia supports and can then use this to draw ClearType into, etc.
|
||||
// This pixel data is provided to the bitmap that the device contains so that it
|
||||
// can be shared.
|
||||
//
|
||||
// The device owns the pixel data, when the device goes away, the pixel data
|
||||
// also becomes invalid. THIS IS DIFFERENT THAN NORMAL SKIA which uses
|
||||
// reference counting for the pixel data. In normal Skia, you could assign
|
||||
// another bitmap to this device's bitmap and everything will work properly.
|
||||
// For us, that other bitmap will become invalid as soon as the device becomes
|
||||
// invalid, which may lead to subtle bugs. Therefore, DO NOT ASSIGN THE
|
||||
// DEVICE'S PIXEL DATA TO ANOTHER BITMAP, make sure you copy instead.
|
||||
class BitmapPlatformDeviceWin : public PlatformDeviceWin {
|
||||
public:
|
||||
// Factory function. The screen DC is used to create the bitmap, and will not
|
||||
// be stored beyond this function. is_opaque should be set if the caller
|
||||
// knows the bitmap will be completely opaque and allows some optimizations.
|
||||
//
|
||||
// The shared_section parameter is optional (pass NULL for default behavior).
|
||||
// If shared_section is non-null, then it must be a handle to a file-mapping
|
||||
// object returned by CreateFileMapping. See CreateDIBSection for details.
|
||||
static BitmapPlatformDeviceWin* create(HDC screen_dc,
|
||||
int width,
|
||||
int height,
|
||||
bool is_opaque,
|
||||
HANDLE shared_section);
|
||||
|
||||
// Copy constructor. When copied, devices duplicate their internal data, so
|
||||
// stay linked. This is because their implementation is very heavyweight
|
||||
// (lots of memory and some GDI objects). If a device has been copied, both
|
||||
// clip rects and other state will stay in sync.
|
||||
//
|
||||
// This means it will NOT work to duplicate a device and assign it to a
|
||||
// canvas, because the two canvases will each set their own clip rects, and
|
||||
// the resulting GDI clip rect will be random.
|
||||
//
|
||||
// Copy constucting and "=" is designed for saving the device or passing it
|
||||
// around to another routine willing to deal with the bitmap data directly.
|
||||
BitmapPlatformDeviceWin(const BitmapPlatformDeviceWin& other);
|
||||
virtual ~BitmapPlatformDeviceWin();
|
||||
|
||||
// See warning for copy constructor above.
|
||||
BitmapPlatformDeviceWin& operator=(const BitmapPlatformDeviceWin& other);
|
||||
|
||||
// Retrieves the bitmap DC, which is the memory DC for our bitmap data. The
|
||||
// bitmap DC is lazy created.
|
||||
virtual HDC getBitmapDC();
|
||||
virtual void setMatrixClip(const SkMatrix& transform, const SkRegion& region);
|
||||
virtual void setDeviceOffset(int x, int y);
|
||||
|
||||
virtual void drawToHDC(HDC dc, int x, int y, const RECT* src_rect);
|
||||
virtual void prepareForGDI(int x, int y, int width, int height);
|
||||
virtual void postProcessGDI(int x, int y, int width, int height);
|
||||
virtual void makeOpaque(int x, int y, int width, int height);
|
||||
virtual void fixupAlphaBeforeCompositing();
|
||||
virtual bool IsVectorial() { return false; }
|
||||
|
||||
// Returns the color value at the specified location. This does not
|
||||
// consider any transforms that may be set on the device.
|
||||
SkColor getColorAt(int x, int y);
|
||||
|
||||
protected:
|
||||
// Flushes the Windows device context so that the pixel data can be accessed
|
||||
// directly by Skia. Overridden from SkDevice, this is called when Skia
|
||||
// starts accessing pixel data.
|
||||
virtual void onAccessBitmap(SkBitmap* bitmap);
|
||||
|
||||
private:
|
||||
// Function pointer used by the processPixels method for setting the alpha
|
||||
// value of a particular pixel.
|
||||
typedef void (*adjustAlpha)(uint32_t* pixel);
|
||||
|
||||
// Reference counted data that can be shared between multiple devices. This
|
||||
// allows copy constructors and operator= for devices to work properly. The
|
||||
// bitmaps used by the base device class are already refcounted and copyable.
|
||||
class BitmapPlatformDeviceWinData;
|
||||
|
||||
// Private constructor.
|
||||
BitmapPlatformDeviceWin(BitmapPlatformDeviceWinData* data, const SkBitmap& bitmap);
|
||||
|
||||
// Loops through each of the pixels in the specified range, invoking
|
||||
// adjustor for the alpha value of each pixel. If |width| or |height| are -1,
|
||||
// the available width/height is used.
|
||||
template<adjustAlpha adjustor>
|
||||
void processPixels(int x,
|
||||
int y,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
// Data associated with this device, guaranteed non-null.
|
||||
scoped_refptr<BitmapPlatformDeviceWinData> data_;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
#endif // BASE_GFX_BITMAP_PLATFORM_DEVICE_WIN_H__
|
||||
|
||||
|
@ -1,85 +1,85 @@
|
||||
// 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/platform_canvas_win.h"
|
||||
|
||||
#include "base/gfx/bitmap_platform_device_win.h"
|
||||
#include "base/logging.h"
|
||||
|
||||
#ifdef ARCH_CPU_64_BITS
|
||||
#error This code does not work on x64. Please make sure all the base unit tests\
|
||||
pass before doing any real work.
|
||||
#endif
|
||||
|
||||
namespace gfx {
|
||||
|
||||
PlatformCanvasWin::PlatformCanvasWin() : SkCanvas() {
|
||||
}
|
||||
|
||||
PlatformCanvasWin::PlatformCanvasWin(int width, int height, bool is_opaque)
|
||||
: SkCanvas() {
|
||||
initialize(width, height, is_opaque, NULL);
|
||||
}
|
||||
|
||||
PlatformCanvasWin::PlatformCanvasWin(int width,
|
||||
int height,
|
||||
bool is_opaque,
|
||||
HANDLE shared_section)
|
||||
: SkCanvas() {
|
||||
initialize(width, height, is_opaque, shared_section);
|
||||
}
|
||||
|
||||
PlatformCanvasWin::~PlatformCanvasWin() {
|
||||
}
|
||||
|
||||
void PlatformCanvasWin::initialize(int width,
|
||||
int height,
|
||||
bool is_opaque,
|
||||
HANDLE shared_section) {
|
||||
SkDevice* device =
|
||||
createPlatformDevice(width, height, is_opaque, shared_section);
|
||||
setDevice(device);
|
||||
device->unref(); // was created with refcount 1, and setDevice also refs
|
||||
}
|
||||
|
||||
HDC PlatformCanvasWin::beginPlatformPaint() {
|
||||
return getTopPlatformDevice().getBitmapDC();
|
||||
}
|
||||
|
||||
void PlatformCanvasWin::endPlatformPaint() {
|
||||
// we don't clear the DC here since it will be likely to be used again
|
||||
// flushing will be done in onAccessBitmap
|
||||
}
|
||||
|
||||
PlatformDeviceWin& PlatformCanvasWin::getTopPlatformDevice() const {
|
||||
// All of our devices should be our special PlatformDevice.
|
||||
SkCanvas::LayerIter iter(const_cast<PlatformCanvasWin*>(this), false);
|
||||
return *static_cast<PlatformDeviceWin*>(iter.device());
|
||||
}
|
||||
|
||||
SkDevice* PlatformCanvasWin::createDevice(SkBitmap::Config config,
|
||||
int width,
|
||||
int height,
|
||||
bool is_opaque, bool isForLayer) {
|
||||
DCHECK(config == SkBitmap::kARGB_8888_Config);
|
||||
return createPlatformDevice(width, height, is_opaque, NULL);
|
||||
}
|
||||
|
||||
SkDevice* PlatformCanvasWin::createPlatformDevice(int width,
|
||||
int height,
|
||||
bool is_opaque,
|
||||
HANDLE shared_section) {
|
||||
HDC screen_dc = GetDC(NULL);
|
||||
SkDevice* device = BitmapPlatformDeviceWin::create(screen_dc, width, height,
|
||||
is_opaque, shared_section);
|
||||
ReleaseDC(NULL, screen_dc);
|
||||
return device;
|
||||
}
|
||||
|
||||
SkDevice* PlatformCanvasWin::setBitmapDevice(const SkBitmap&) {
|
||||
NOTREACHED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
// 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/platform_canvas_win.h"
|
||||
|
||||
#include "base/gfx/bitmap_platform_device_win.h"
|
||||
#include "base/logging.h"
|
||||
|
||||
#ifdef ARCH_CPU_64_BITS
|
||||
#error This code does not work on x64. Please make sure all the base unit tests\
|
||||
pass before doing any real work.
|
||||
#endif
|
||||
|
||||
namespace gfx {
|
||||
|
||||
PlatformCanvasWin::PlatformCanvasWin() : SkCanvas() {
|
||||
}
|
||||
|
||||
PlatformCanvasWin::PlatformCanvasWin(int width, int height, bool is_opaque)
|
||||
: SkCanvas() {
|
||||
initialize(width, height, is_opaque, NULL);
|
||||
}
|
||||
|
||||
PlatformCanvasWin::PlatformCanvasWin(int width,
|
||||
int height,
|
||||
bool is_opaque,
|
||||
HANDLE shared_section)
|
||||
: SkCanvas() {
|
||||
initialize(width, height, is_opaque, shared_section);
|
||||
}
|
||||
|
||||
PlatformCanvasWin::~PlatformCanvasWin() {
|
||||
}
|
||||
|
||||
void PlatformCanvasWin::initialize(int width,
|
||||
int height,
|
||||
bool is_opaque,
|
||||
HANDLE shared_section) {
|
||||
SkDevice* device =
|
||||
createPlatformDevice(width, height, is_opaque, shared_section);
|
||||
setDevice(device);
|
||||
device->unref(); // was created with refcount 1, and setDevice also refs
|
||||
}
|
||||
|
||||
HDC PlatformCanvasWin::beginPlatformPaint() {
|
||||
return getTopPlatformDevice().getBitmapDC();
|
||||
}
|
||||
|
||||
void PlatformCanvasWin::endPlatformPaint() {
|
||||
// we don't clear the DC here since it will be likely to be used again
|
||||
// flushing will be done in onAccessBitmap
|
||||
}
|
||||
|
||||
PlatformDeviceWin& PlatformCanvasWin::getTopPlatformDevice() const {
|
||||
// All of our devices should be our special PlatformDevice.
|
||||
SkCanvas::LayerIter iter(const_cast<PlatformCanvasWin*>(this), false);
|
||||
return *static_cast<PlatformDeviceWin*>(iter.device());
|
||||
}
|
||||
|
||||
SkDevice* PlatformCanvasWin::createDevice(SkBitmap::Config config,
|
||||
int width,
|
||||
int height,
|
||||
bool is_opaque, bool isForLayer) {
|
||||
DCHECK(config == SkBitmap::kARGB_8888_Config);
|
||||
return createPlatformDevice(width, height, is_opaque, NULL);
|
||||
}
|
||||
|
||||
SkDevice* PlatformCanvasWin::createPlatformDevice(int width,
|
||||
int height,
|
||||
bool is_opaque,
|
||||
HANDLE shared_section) {
|
||||
HDC screen_dc = GetDC(NULL);
|
||||
SkDevice* device = BitmapPlatformDeviceWin::create(screen_dc, width, height,
|
||||
is_opaque, shared_section);
|
||||
ReleaseDC(NULL, screen_dc);
|
||||
return device;
|
||||
}
|
||||
|
||||
SkDevice* PlatformCanvasWin::setBitmapDevice(const SkBitmap&) {
|
||||
NOTREACHED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
|
@ -1,185 +1,185 @@
|
||||
// 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_WIN_H__
|
||||
#define BASE_GFX_PLATFORM_CANVAS_WIN_H__
|
||||
|
||||
#include "base/gfx/platform_device_win.h"
|
||||
#include "base/basictypes.h"
|
||||
|
||||
#include "SkCanvas.h"
|
||||
|
||||
namespace gfx {
|
||||
|
||||
// This class is a specialization of the regular SkCanvas that is designed to
|
||||
// work with a gfx::PlatformDevice to manage platform-specific drawing. It
|
||||
// allows using both Skia operations and platform-specific operations.
|
||||
class PlatformCanvasWin : public SkCanvas {
|
||||
public:
|
||||
// Set is_opaque if you are going to erase the bitmap and not use
|
||||
// transparency: this will enable some optimizations. The shared_section
|
||||
// parameter is passed to gfx::PlatformDevice::create. See it for details.
|
||||
//
|
||||
// If you use the version with no arguments, you MUST call initialize()
|
||||
PlatformCanvasWin();
|
||||
PlatformCanvasWin(int width, int height, bool is_opaque);
|
||||
PlatformCanvasWin(int width, int height, bool is_opaque, HANDLE shared_section);
|
||||
virtual ~PlatformCanvasWin();
|
||||
|
||||
// For two-part init, call if you use the no-argument constructor above
|
||||
void initialize(int width, int height, bool is_opaque, HANDLE shared_section);
|
||||
|
||||
// These calls should surround calls to platform drawing routines, the DC
|
||||
// returned by beginPlatformPaint is the DC that can be used to draw into.
|
||||
// Call endPlatformPaint when you are done and want to use Skia operations
|
||||
// again; this will synchronize the bitmap to Windows.
|
||||
virtual HDC beginPlatformPaint();
|
||||
virtual void endPlatformPaint();
|
||||
|
||||
// Returns the platform device pointer of the topmost rect with a non-empty
|
||||
// clip. In practice, this is usually either the top layer or nothing, since
|
||||
// we usually set the clip to new layers when we make them.
|
||||
//
|
||||
// If there is no layer that is not all clipped out, this will return a
|
||||
// dummy device so callers do not have to check. If you are concerned about
|
||||
// performance, check the clip before doing any painting.
|
||||
//
|
||||
// This is different than SkCanvas' getDevice, because that returns the
|
||||
// bottommost device.
|
||||
//
|
||||
// Danger: the resulting device should not be saved. It will be invalidated
|
||||
// by the next call to save() or restore().
|
||||
PlatformDeviceWin& getTopPlatformDevice() const;
|
||||
|
||||
protected:
|
||||
// Creates a device store for use by the canvas. We override this so that
|
||||
// the device is always our own so we know that we can use GDI operations
|
||||
// on it. Simply calls into createPlatformDevice().
|
||||
virtual SkDevice* createDevice(SkBitmap::Config, int width, int height,
|
||||
bool is_opaque, bool isForLayer);
|
||||
|
||||
// Creates a device store for use by the canvas. By default, it creates a
|
||||
// BitmapPlatformDeviceWin object. Can be overridden to change the object type.
|
||||
virtual SkDevice* createPlatformDevice(int width, int height, bool is_opaque,
|
||||
HANDLE shared_section);
|
||||
|
||||
private:
|
||||
// Unimplemented.
|
||||
virtual SkDevice* setBitmapDevice(const SkBitmap& bitmap);
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(PlatformCanvasWin);
|
||||
};
|
||||
|
||||
// A class designed to help with WM_PAINT operations on Windows. It will
|
||||
// do BeginPaint/EndPaint on init/destruction, and will create the bitmap and
|
||||
// canvas with the correct size and transform for the dirty rect. The bitmap
|
||||
// will be automatically painted to the screen on destruction.
|
||||
//
|
||||
// You MUST call isEmpty before painting to determine if anything needs
|
||||
// painting. Sometimes the dirty rect can actually be empty, and this makes
|
||||
// the bitmap functions we call unhappy. The caller should not paint in this
|
||||
// case.
|
||||
//
|
||||
// Therefore, all you need to do is:
|
||||
// case WM_PAINT: {
|
||||
// gfx::PlatformCanvasWinPaint canvas(hwnd);
|
||||
// if (!canvas.isEmpty()) {
|
||||
// ... paint to the canvas ...
|
||||
// }
|
||||
// return 0;
|
||||
// }
|
||||
template <class T>
|
||||
class CanvasPaintT : public T {
|
||||
public:
|
||||
CanvasPaintT(HWND hwnd) : hwnd_(hwnd), for_paint_(true) {
|
||||
initPaint(true);
|
||||
}
|
||||
|
||||
CanvasPaintT(HWND hwnd, bool opaque) : hwnd_(hwnd), for_paint_(true) {
|
||||
initPaint(opaque);
|
||||
}
|
||||
|
||||
// Creates a CanvasPaintT for the specified region that paints to the
|
||||
// specified dc. This does NOT do BeginPaint/EndPaint.
|
||||
CanvasPaintT(HDC dc, bool opaque, int x, int y, int w, int h)
|
||||
: hwnd_(NULL),
|
||||
paint_dc_(dc),
|
||||
for_paint_(false) {
|
||||
memset(&ps_, 0, sizeof(ps_));
|
||||
ps_.rcPaint.left = x;
|
||||
ps_.rcPaint.right = x + w;
|
||||
ps_.rcPaint.top = y;
|
||||
ps_.rcPaint.bottom = y + h;
|
||||
init(opaque);
|
||||
}
|
||||
|
||||
|
||||
virtual ~CanvasPaintT() {
|
||||
if (!isEmpty()) {
|
||||
restoreToCount(1);
|
||||
// Commit the drawing to the screen
|
||||
getTopPlatformDevice().drawToHDC(paint_dc_,
|
||||
ps_.rcPaint.left, ps_.rcPaint.top,
|
||||
NULL);
|
||||
}
|
||||
if (for_paint_)
|
||||
EndPaint(hwnd_, &ps_);
|
||||
}
|
||||
|
||||
// Returns true if the invalid region is empty. The caller should call this
|
||||
// function to determine if anything needs painting.
|
||||
bool isEmpty() const {
|
||||
return ps_.rcPaint.right - ps_.rcPaint.left == 0 ||
|
||||
ps_.rcPaint.bottom - ps_.rcPaint.top == 0;
|
||||
}
|
||||
|
||||
// Use to access the Windows painting parameters, especially useful for
|
||||
// getting the bounding rect for painting: paintstruct().rcPaint
|
||||
const PAINTSTRUCT& paintStruct() const {
|
||||
return ps_;
|
||||
}
|
||||
|
||||
// Returns the DC that will be painted to
|
||||
HDC paintDC() const {
|
||||
return paint_dc_;
|
||||
}
|
||||
|
||||
protected:
|
||||
HWND hwnd_;
|
||||
HDC paint_dc_;
|
||||
PAINTSTRUCT ps_;
|
||||
|
||||
private:
|
||||
void initPaint(bool opaque) {
|
||||
paint_dc_ = BeginPaint(hwnd_, &ps_);
|
||||
|
||||
init(opaque);
|
||||
}
|
||||
|
||||
void init(bool opaque) {
|
||||
// FIXME(brettw) for ClearType, we probably want to expand the bounds of
|
||||
// painting by one pixel so that the boundaries will be correct (ClearType
|
||||
// text can depend on the adjacent pixel). Then we would paint just the inset
|
||||
// pixels to the screen.
|
||||
initialize(ps_.rcPaint.right - ps_.rcPaint.left,
|
||||
ps_.rcPaint.bottom - ps_.rcPaint.top, opaque, NULL);
|
||||
|
||||
// This will bring the canvas into the screen coordinate system for the
|
||||
// dirty rect
|
||||
translate(SkIntToScalar(-ps_.rcPaint.left),
|
||||
SkIntToScalar(-ps_.rcPaint.top));
|
||||
}
|
||||
|
||||
// If true, this canvas was created for a BeginPaint.
|
||||
const bool for_paint_;
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(CanvasPaintT);
|
||||
};
|
||||
|
||||
typedef CanvasPaintT<PlatformCanvasWin> PlatformCanvasWinPaint;
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
#endif // BASE_GFX_PLATFORM_CANVAS_WIN_H__
|
||||
|
||||
// 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_WIN_H__
|
||||
#define BASE_GFX_PLATFORM_CANVAS_WIN_H__
|
||||
|
||||
#include "base/gfx/platform_device_win.h"
|
||||
#include "base/basictypes.h"
|
||||
|
||||
#include "SkCanvas.h"
|
||||
|
||||
namespace gfx {
|
||||
|
||||
// This class is a specialization of the regular SkCanvas that is designed to
|
||||
// work with a gfx::PlatformDevice to manage platform-specific drawing. It
|
||||
// allows using both Skia operations and platform-specific operations.
|
||||
class PlatformCanvasWin : public SkCanvas {
|
||||
public:
|
||||
// Set is_opaque if you are going to erase the bitmap and not use
|
||||
// transparency: this will enable some optimizations. The shared_section
|
||||
// parameter is passed to gfx::PlatformDevice::create. See it for details.
|
||||
//
|
||||
// If you use the version with no arguments, you MUST call initialize()
|
||||
PlatformCanvasWin();
|
||||
PlatformCanvasWin(int width, int height, bool is_opaque);
|
||||
PlatformCanvasWin(int width, int height, bool is_opaque, HANDLE shared_section);
|
||||
virtual ~PlatformCanvasWin();
|
||||
|
||||
// For two-part init, call if you use the no-argument constructor above
|
||||
void initialize(int width, int height, bool is_opaque, HANDLE shared_section);
|
||||
|
||||
// These calls should surround calls to platform drawing routines, the DC
|
||||
// returned by beginPlatformPaint is the DC that can be used to draw into.
|
||||
// Call endPlatformPaint when you are done and want to use Skia operations
|
||||
// again; this will synchronize the bitmap to Windows.
|
||||
virtual HDC beginPlatformPaint();
|
||||
virtual void endPlatformPaint();
|
||||
|
||||
// Returns the platform device pointer of the topmost rect with a non-empty
|
||||
// clip. In practice, this is usually either the top layer or nothing, since
|
||||
// we usually set the clip to new layers when we make them.
|
||||
//
|
||||
// If there is no layer that is not all clipped out, this will return a
|
||||
// dummy device so callers do not have to check. If you are concerned about
|
||||
// performance, check the clip before doing any painting.
|
||||
//
|
||||
// This is different than SkCanvas' getDevice, because that returns the
|
||||
// bottommost device.
|
||||
//
|
||||
// Danger: the resulting device should not be saved. It will be invalidated
|
||||
// by the next call to save() or restore().
|
||||
PlatformDeviceWin& getTopPlatformDevice() const;
|
||||
|
||||
protected:
|
||||
// Creates a device store for use by the canvas. We override this so that
|
||||
// the device is always our own so we know that we can use GDI operations
|
||||
// on it. Simply calls into createPlatformDevice().
|
||||
virtual SkDevice* createDevice(SkBitmap::Config, int width, int height,
|
||||
bool is_opaque, bool isForLayer);
|
||||
|
||||
// Creates a device store for use by the canvas. By default, it creates a
|
||||
// BitmapPlatformDeviceWin object. Can be overridden to change the object type.
|
||||
virtual SkDevice* createPlatformDevice(int width, int height, bool is_opaque,
|
||||
HANDLE shared_section);
|
||||
|
||||
private:
|
||||
// Unimplemented.
|
||||
virtual SkDevice* setBitmapDevice(const SkBitmap& bitmap);
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(PlatformCanvasWin);
|
||||
};
|
||||
|
||||
// A class designed to help with WM_PAINT operations on Windows. It will
|
||||
// do BeginPaint/EndPaint on init/destruction, and will create the bitmap and
|
||||
// canvas with the correct size and transform for the dirty rect. The bitmap
|
||||
// will be automatically painted to the screen on destruction.
|
||||
//
|
||||
// You MUST call isEmpty before painting to determine if anything needs
|
||||
// painting. Sometimes the dirty rect can actually be empty, and this makes
|
||||
// the bitmap functions we call unhappy. The caller should not paint in this
|
||||
// case.
|
||||
//
|
||||
// Therefore, all you need to do is:
|
||||
// case WM_PAINT: {
|
||||
// gfx::PlatformCanvasWinPaint canvas(hwnd);
|
||||
// if (!canvas.isEmpty()) {
|
||||
// ... paint to the canvas ...
|
||||
// }
|
||||
// return 0;
|
||||
// }
|
||||
template <class T>
|
||||
class CanvasPaintT : public T {
|
||||
public:
|
||||
CanvasPaintT(HWND hwnd) : hwnd_(hwnd), for_paint_(true) {
|
||||
initPaint(true);
|
||||
}
|
||||
|
||||
CanvasPaintT(HWND hwnd, bool opaque) : hwnd_(hwnd), for_paint_(true) {
|
||||
initPaint(opaque);
|
||||
}
|
||||
|
||||
// Creates a CanvasPaintT for the specified region that paints to the
|
||||
// specified dc. This does NOT do BeginPaint/EndPaint.
|
||||
CanvasPaintT(HDC dc, bool opaque, int x, int y, int w, int h)
|
||||
: hwnd_(NULL),
|
||||
paint_dc_(dc),
|
||||
for_paint_(false) {
|
||||
memset(&ps_, 0, sizeof(ps_));
|
||||
ps_.rcPaint.left = x;
|
||||
ps_.rcPaint.right = x + w;
|
||||
ps_.rcPaint.top = y;
|
||||
ps_.rcPaint.bottom = y + h;
|
||||
init(opaque);
|
||||
}
|
||||
|
||||
|
||||
virtual ~CanvasPaintT() {
|
||||
if (!isEmpty()) {
|
||||
restoreToCount(1);
|
||||
// Commit the drawing to the screen
|
||||
getTopPlatformDevice().drawToHDC(paint_dc_,
|
||||
ps_.rcPaint.left, ps_.rcPaint.top,
|
||||
NULL);
|
||||
}
|
||||
if (for_paint_)
|
||||
EndPaint(hwnd_, &ps_);
|
||||
}
|
||||
|
||||
// Returns true if the invalid region is empty. The caller should call this
|
||||
// function to determine if anything needs painting.
|
||||
bool isEmpty() const {
|
||||
return ps_.rcPaint.right - ps_.rcPaint.left == 0 ||
|
||||
ps_.rcPaint.bottom - ps_.rcPaint.top == 0;
|
||||
}
|
||||
|
||||
// Use to access the Windows painting parameters, especially useful for
|
||||
// getting the bounding rect for painting: paintstruct().rcPaint
|
||||
const PAINTSTRUCT& paintStruct() const {
|
||||
return ps_;
|
||||
}
|
||||
|
||||
// Returns the DC that will be painted to
|
||||
HDC paintDC() const {
|
||||
return paint_dc_;
|
||||
}
|
||||
|
||||
protected:
|
||||
HWND hwnd_;
|
||||
HDC paint_dc_;
|
||||
PAINTSTRUCT ps_;
|
||||
|
||||
private:
|
||||
void initPaint(bool opaque) {
|
||||
paint_dc_ = BeginPaint(hwnd_, &ps_);
|
||||
|
||||
init(opaque);
|
||||
}
|
||||
|
||||
void init(bool opaque) {
|
||||
// FIXME(brettw) for ClearType, we probably want to expand the bounds of
|
||||
// painting by one pixel so that the boundaries will be correct (ClearType
|
||||
// text can depend on the adjacent pixel). Then we would paint just the inset
|
||||
// pixels to the screen.
|
||||
initialize(ps_.rcPaint.right - ps_.rcPaint.left,
|
||||
ps_.rcPaint.bottom - ps_.rcPaint.top, opaque, NULL);
|
||||
|
||||
// This will bring the canvas into the screen coordinate system for the
|
||||
// dirty rect
|
||||
translate(SkIntToScalar(-ps_.rcPaint.left),
|
||||
SkIntToScalar(-ps_.rcPaint.top));
|
||||
}
|
||||
|
||||
// If true, this canvas was created for a BeginPaint.
|
||||
const bool for_paint_;
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(CanvasPaintT);
|
||||
};
|
||||
|
||||
typedef CanvasPaintT<PlatformCanvasWin> PlatformCanvasWinPaint;
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
#endif // BASE_GFX_PLATFORM_CANVAS_WIN_H__
|
||||
|
||||
|
@ -1,229 +1,229 @@
|
||||
// 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/platform_device_win.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/gfx/skia_utils.h"
|
||||
#include "SkMatrix.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkRegion.h"
|
||||
#include "SkUtils.h"
|
||||
|
||||
namespace gfx {
|
||||
|
||||
PlatformDeviceWin::PlatformDeviceWin(const SkBitmap& bitmap)
|
||||
: SkDevice(bitmap) {
|
||||
}
|
||||
|
||||
// static
|
||||
void PlatformDeviceWin::InitializeDC(HDC context) {
|
||||
// Enables world transformation.
|
||||
// If the GM_ADVANCED graphics mode is set, GDI always draws arcs in the
|
||||
// counterclockwise direction in logical space. This is equivalent to the
|
||||
// statement that, in the GM_ADVANCED graphics mode, both arc control points
|
||||
// and arcs themselves fully respect the device context's world-to-device
|
||||
// transformation.
|
||||
BOOL res = SetGraphicsMode(context, GM_ADVANCED);
|
||||
DCHECK_NE(res, 0);
|
||||
|
||||
// Enables dithering.
|
||||
res = SetStretchBltMode(context, HALFTONE);
|
||||
DCHECK_NE(res, 0);
|
||||
// As per SetStretchBltMode() documentation, SetBrushOrgEx() must be called
|
||||
// right after.
|
||||
res = SetBrushOrgEx(context, 0, 0, NULL);
|
||||
DCHECK_NE(res, 0);
|
||||
|
||||
// Sets up default orientation.
|
||||
res = SetArcDirection(context, AD_CLOCKWISE);
|
||||
DCHECK_NE(res, 0);
|
||||
|
||||
// Sets up default colors.
|
||||
res = SetBkColor(context, RGB(255, 255, 255));
|
||||
DCHECK_NE(res, CLR_INVALID);
|
||||
res = SetTextColor(context, RGB(0, 0, 0));
|
||||
DCHECK_NE(res, CLR_INVALID);
|
||||
res = SetDCBrushColor(context, RGB(255, 255, 255));
|
||||
DCHECK_NE(res, CLR_INVALID);
|
||||
res = SetDCPenColor(context, RGB(0, 0, 0));
|
||||
DCHECK_NE(res, CLR_INVALID);
|
||||
|
||||
// Sets up default transparency.
|
||||
res = SetBkMode(context, OPAQUE);
|
||||
DCHECK_NE(res, 0);
|
||||
res = SetROP2(context, R2_COPYPEN);
|
||||
DCHECK_NE(res, 0);
|
||||
}
|
||||
|
||||
// static
|
||||
void PlatformDeviceWin::LoadPathToDC(HDC context, const SkPath& path) {
|
||||
switch (path.getFillType()) {
|
||||
case SkPath::kWinding_FillType: {
|
||||
int res = SetPolyFillMode(context, WINDING);
|
||||
DCHECK(res != 0);
|
||||
break;
|
||||
}
|
||||
case SkPath::kEvenOdd_FillType: {
|
||||
int res = SetPolyFillMode(context, ALTERNATE);
|
||||
DCHECK(res != 0);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
NOTREACHED();
|
||||
break;
|
||||
}
|
||||
}
|
||||
BOOL res = BeginPath(context);
|
||||
DCHECK(res != 0);
|
||||
|
||||
CubicPaths paths;
|
||||
if (!SkPathToCubicPaths(&paths, path))
|
||||
return;
|
||||
|
||||
std::vector<POINT> points;
|
||||
for (CubicPaths::const_iterator path(paths.begin()); path != paths.end();
|
||||
++path) {
|
||||
if (!path->size())
|
||||
continue;
|
||||
// DCHECK_EQ(points.size() % 4, 0);
|
||||
points.resize(0);
|
||||
points.reserve(path->size() * 3 / 4 + 1);
|
||||
points.push_back(SkPointToPOINT(path->front().p[0]));
|
||||
for (CubicPath::const_iterator point(path->begin()); point != path->end();
|
||||
++point) {
|
||||
// Never add point->p[0]
|
||||
points.push_back(SkPointToPOINT(point->p[1]));
|
||||
points.push_back(SkPointToPOINT(point->p[2]));
|
||||
points.push_back(SkPointToPOINT(point->p[3]));
|
||||
}
|
||||
DCHECK_EQ((points.size() - 1) % 3, 0);
|
||||
// This is slightly inefficient since all straight line and quadratic lines
|
||||
// are "upgraded" to a cubic line.
|
||||
// TODO(maruel): http://b/1147346 We should use
|
||||
// PolyDraw/PolyBezier/Polyline whenever possible.
|
||||
res = PolyBezier(context, &points.front(),
|
||||
static_cast<DWORD>(points.size()));
|
||||
DCHECK_NE(res, 0);
|
||||
if (res == 0)
|
||||
break;
|
||||
}
|
||||
if (res == 0) {
|
||||
// Make sure the path is discarded.
|
||||
AbortPath(context);
|
||||
} else {
|
||||
res = EndPath(context);
|
||||
DCHECK(res != 0);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void PlatformDeviceWin::LoadTransformToDC(HDC dc, const SkMatrix& matrix) {
|
||||
XFORM xf;
|
||||
xf.eM11 = matrix[SkMatrix::kMScaleX];
|
||||
xf.eM21 = matrix[SkMatrix::kMSkewX];
|
||||
xf.eDx = matrix[SkMatrix::kMTransX];
|
||||
xf.eM12 = matrix[SkMatrix::kMSkewY];
|
||||
xf.eM22 = matrix[SkMatrix::kMScaleY];
|
||||
xf.eDy = matrix[SkMatrix::kMTransY];
|
||||
SetWorldTransform(dc, &xf);
|
||||
}
|
||||
|
||||
// static
|
||||
bool PlatformDeviceWin::SkPathToCubicPaths(CubicPaths* paths,
|
||||
const SkPath& skpath) {
|
||||
paths->clear();
|
||||
CubicPath* current_path = NULL;
|
||||
SkPoint current_points[4];
|
||||
CubicPoints points_to_add;
|
||||
SkPath::Iter iter(skpath, false);
|
||||
for (SkPath::Verb verb = iter.next(current_points);
|
||||
verb != SkPath::kDone_Verb;
|
||||
verb = iter.next(current_points)) {
|
||||
switch (verb) {
|
||||
case SkPath::kMove_Verb: { // iter.next returns 1 point
|
||||
// Ignores it since the point is copied in the next operation. See
|
||||
// SkPath::Iter::next() for reference.
|
||||
paths->push_back(CubicPath());
|
||||
current_path = &paths->back();
|
||||
// Skip point addition.
|
||||
continue;
|
||||
}
|
||||
case SkPath::kLine_Verb: { // iter.next returns 2 points
|
||||
points_to_add.p[0] = current_points[0];
|
||||
points_to_add.p[1] = current_points[0];
|
||||
points_to_add.p[2] = current_points[1];
|
||||
points_to_add.p[3] = current_points[1];
|
||||
break;
|
||||
}
|
||||
case SkPath::kQuad_Verb: { // iter.next returns 3 points
|
||||
points_to_add.p[0] = current_points[0];
|
||||
points_to_add.p[1] = current_points[1];
|
||||
points_to_add.p[2] = current_points[2];
|
||||
points_to_add.p[3] = current_points[2];
|
||||
break;
|
||||
}
|
||||
case SkPath::kCubic_Verb: { // iter.next returns 4 points
|
||||
points_to_add.p[0] = current_points[0];
|
||||
points_to_add.p[1] = current_points[1];
|
||||
points_to_add.p[2] = current_points[2];
|
||||
points_to_add.p[3] = current_points[3];
|
||||
break;
|
||||
}
|
||||
case SkPath::kClose_Verb: { // iter.next returns 1 point (the last point)
|
||||
paths->push_back(CubicPath());
|
||||
current_path = &paths->back();
|
||||
continue;
|
||||
}
|
||||
case SkPath::kDone_Verb: // iter.next returns 0 points
|
||||
default: {
|
||||
current_path = NULL;
|
||||
// Will return false.
|
||||
break;
|
||||
}
|
||||
}
|
||||
DCHECK(current_path);
|
||||
if (!current_path) {
|
||||
paths->clear();
|
||||
return false;
|
||||
}
|
||||
current_path->push_back(points_to_add);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
void PlatformDeviceWin::LoadClippingRegionToDC(HDC context,
|
||||
const SkRegion& region,
|
||||
const SkMatrix& transformation) {
|
||||
HRGN hrgn;
|
||||
if (region.isEmpty()) {
|
||||
// region can be empty, in which case everything will be clipped.
|
||||
hrgn = CreateRectRgn(0, 0, 0, 0);
|
||||
} else if (region.isRect()) {
|
||||
// Do the transformation.
|
||||
SkRect rect;
|
||||
rect.set(region.getBounds());
|
||||
transformation.mapRect(&rect);
|
||||
SkIRect irect;
|
||||
rect.round(&irect);
|
||||
hrgn = CreateRectRgnIndirect(&SkIRectToRECT(irect));
|
||||
} else {
|
||||
// It is complex.
|
||||
SkPath path;
|
||||
region.getBoundaryPath(&path);
|
||||
// Clip. Note that windows clipping regions are not affected by the
|
||||
// transform so apply it manually.
|
||||
path.transform(transformation);
|
||||
LoadPathToDC(context, path);
|
||||
hrgn = PathToRegion(context);
|
||||
}
|
||||
int result = SelectClipRgn(context, hrgn);
|
||||
DCHECK_NE(result, ERROR);
|
||||
result = DeleteObject(hrgn);
|
||||
DCHECK_NE(result, 0);
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
// 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/platform_device_win.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/gfx/skia_utils.h"
|
||||
#include "SkMatrix.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkRegion.h"
|
||||
#include "SkUtils.h"
|
||||
|
||||
namespace gfx {
|
||||
|
||||
PlatformDeviceWin::PlatformDeviceWin(const SkBitmap& bitmap)
|
||||
: SkDevice(bitmap) {
|
||||
}
|
||||
|
||||
// static
|
||||
void PlatformDeviceWin::InitializeDC(HDC context) {
|
||||
// Enables world transformation.
|
||||
// If the GM_ADVANCED graphics mode is set, GDI always draws arcs in the
|
||||
// counterclockwise direction in logical space. This is equivalent to the
|
||||
// statement that, in the GM_ADVANCED graphics mode, both arc control points
|
||||
// and arcs themselves fully respect the device context's world-to-device
|
||||
// transformation.
|
||||
BOOL res = SetGraphicsMode(context, GM_ADVANCED);
|
||||
DCHECK_NE(res, 0);
|
||||
|
||||
// Enables dithering.
|
||||
res = SetStretchBltMode(context, HALFTONE);
|
||||
DCHECK_NE(res, 0);
|
||||
// As per SetStretchBltMode() documentation, SetBrushOrgEx() must be called
|
||||
// right after.
|
||||
res = SetBrushOrgEx(context, 0, 0, NULL);
|
||||
DCHECK_NE(res, 0);
|
||||
|
||||
// Sets up default orientation.
|
||||
res = SetArcDirection(context, AD_CLOCKWISE);
|
||||
DCHECK_NE(res, 0);
|
||||
|
||||
// Sets up default colors.
|
||||
res = SetBkColor(context, RGB(255, 255, 255));
|
||||
DCHECK_NE(res, CLR_INVALID);
|
||||
res = SetTextColor(context, RGB(0, 0, 0));
|
||||
DCHECK_NE(res, CLR_INVALID);
|
||||
res = SetDCBrushColor(context, RGB(255, 255, 255));
|
||||
DCHECK_NE(res, CLR_INVALID);
|
||||
res = SetDCPenColor(context, RGB(0, 0, 0));
|
||||
DCHECK_NE(res, CLR_INVALID);
|
||||
|
||||
// Sets up default transparency.
|
||||
res = SetBkMode(context, OPAQUE);
|
||||
DCHECK_NE(res, 0);
|
||||
res = SetROP2(context, R2_COPYPEN);
|
||||
DCHECK_NE(res, 0);
|
||||
}
|
||||
|
||||
// static
|
||||
void PlatformDeviceWin::LoadPathToDC(HDC context, const SkPath& path) {
|
||||
switch (path.getFillType()) {
|
||||
case SkPath::kWinding_FillType: {
|
||||
int res = SetPolyFillMode(context, WINDING);
|
||||
DCHECK(res != 0);
|
||||
break;
|
||||
}
|
||||
case SkPath::kEvenOdd_FillType: {
|
||||
int res = SetPolyFillMode(context, ALTERNATE);
|
||||
DCHECK(res != 0);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
NOTREACHED();
|
||||
break;
|
||||
}
|
||||
}
|
||||
BOOL res = BeginPath(context);
|
||||
DCHECK(res != 0);
|
||||
|
||||
CubicPaths paths;
|
||||
if (!SkPathToCubicPaths(&paths, path))
|
||||
return;
|
||||
|
||||
std::vector<POINT> points;
|
||||
for (CubicPaths::const_iterator path(paths.begin()); path != paths.end();
|
||||
++path) {
|
||||
if (!path->size())
|
||||
continue;
|
||||
// DCHECK_EQ(points.size() % 4, 0);
|
||||
points.resize(0);
|
||||
points.reserve(path->size() * 3 / 4 + 1);
|
||||
points.push_back(SkPointToPOINT(path->front().p[0]));
|
||||
for (CubicPath::const_iterator point(path->begin()); point != path->end();
|
||||
++point) {
|
||||
// Never add point->p[0]
|
||||
points.push_back(SkPointToPOINT(point->p[1]));
|
||||
points.push_back(SkPointToPOINT(point->p[2]));
|
||||
points.push_back(SkPointToPOINT(point->p[3]));
|
||||
}
|
||||
DCHECK_EQ((points.size() - 1) % 3, 0);
|
||||
// This is slightly inefficient since all straight line and quadratic lines
|
||||
// are "upgraded" to a cubic line.
|
||||
// TODO(maruel): http://b/1147346 We should use
|
||||
// PolyDraw/PolyBezier/Polyline whenever possible.
|
||||
res = PolyBezier(context, &points.front(),
|
||||
static_cast<DWORD>(points.size()));
|
||||
DCHECK_NE(res, 0);
|
||||
if (res == 0)
|
||||
break;
|
||||
}
|
||||
if (res == 0) {
|
||||
// Make sure the path is discarded.
|
||||
AbortPath(context);
|
||||
} else {
|
||||
res = EndPath(context);
|
||||
DCHECK(res != 0);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void PlatformDeviceWin::LoadTransformToDC(HDC dc, const SkMatrix& matrix) {
|
||||
XFORM xf;
|
||||
xf.eM11 = matrix[SkMatrix::kMScaleX];
|
||||
xf.eM21 = matrix[SkMatrix::kMSkewX];
|
||||
xf.eDx = matrix[SkMatrix::kMTransX];
|
||||
xf.eM12 = matrix[SkMatrix::kMSkewY];
|
||||
xf.eM22 = matrix[SkMatrix::kMScaleY];
|
||||
xf.eDy = matrix[SkMatrix::kMTransY];
|
||||
SetWorldTransform(dc, &xf);
|
||||
}
|
||||
|
||||
// static
|
||||
bool PlatformDeviceWin::SkPathToCubicPaths(CubicPaths* paths,
|
||||
const SkPath& skpath) {
|
||||
paths->clear();
|
||||
CubicPath* current_path = NULL;
|
||||
SkPoint current_points[4];
|
||||
CubicPoints points_to_add;
|
||||
SkPath::Iter iter(skpath, false);
|
||||
for (SkPath::Verb verb = iter.next(current_points);
|
||||
verb != SkPath::kDone_Verb;
|
||||
verb = iter.next(current_points)) {
|
||||
switch (verb) {
|
||||
case SkPath::kMove_Verb: { // iter.next returns 1 point
|
||||
// Ignores it since the point is copied in the next operation. See
|
||||
// SkPath::Iter::next() for reference.
|
||||
paths->push_back(CubicPath());
|
||||
current_path = &paths->back();
|
||||
// Skip point addition.
|
||||
continue;
|
||||
}
|
||||
case SkPath::kLine_Verb: { // iter.next returns 2 points
|
||||
points_to_add.p[0] = current_points[0];
|
||||
points_to_add.p[1] = current_points[0];
|
||||
points_to_add.p[2] = current_points[1];
|
||||
points_to_add.p[3] = current_points[1];
|
||||
break;
|
||||
}
|
||||
case SkPath::kQuad_Verb: { // iter.next returns 3 points
|
||||
points_to_add.p[0] = current_points[0];
|
||||
points_to_add.p[1] = current_points[1];
|
||||
points_to_add.p[2] = current_points[2];
|
||||
points_to_add.p[3] = current_points[2];
|
||||
break;
|
||||
}
|
||||
case SkPath::kCubic_Verb: { // iter.next returns 4 points
|
||||
points_to_add.p[0] = current_points[0];
|
||||
points_to_add.p[1] = current_points[1];
|
||||
points_to_add.p[2] = current_points[2];
|
||||
points_to_add.p[3] = current_points[3];
|
||||
break;
|
||||
}
|
||||
case SkPath::kClose_Verb: { // iter.next returns 1 point (the last point)
|
||||
paths->push_back(CubicPath());
|
||||
current_path = &paths->back();
|
||||
continue;
|
||||
}
|
||||
case SkPath::kDone_Verb: // iter.next returns 0 points
|
||||
default: {
|
||||
current_path = NULL;
|
||||
// Will return false.
|
||||
break;
|
||||
}
|
||||
}
|
||||
DCHECK(current_path);
|
||||
if (!current_path) {
|
||||
paths->clear();
|
||||
return false;
|
||||
}
|
||||
current_path->push_back(points_to_add);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
void PlatformDeviceWin::LoadClippingRegionToDC(HDC context,
|
||||
const SkRegion& region,
|
||||
const SkMatrix& transformation) {
|
||||
HRGN hrgn;
|
||||
if (region.isEmpty()) {
|
||||
// region can be empty, in which case everything will be clipped.
|
||||
hrgn = CreateRectRgn(0, 0, 0, 0);
|
||||
} else if (region.isRect()) {
|
||||
// Do the transformation.
|
||||
SkRect rect;
|
||||
rect.set(region.getBounds());
|
||||
transformation.mapRect(&rect);
|
||||
SkIRect irect;
|
||||
rect.round(&irect);
|
||||
hrgn = CreateRectRgnIndirect(&SkIRectToRECT(irect));
|
||||
} else {
|
||||
// It is complex.
|
||||
SkPath path;
|
||||
region.getBoundaryPath(&path);
|
||||
// Clip. Note that windows clipping regions are not affected by the
|
||||
// transform so apply it manually.
|
||||
path.transform(transformation);
|
||||
LoadPathToDC(context, path);
|
||||
hrgn = PathToRegion(context);
|
||||
}
|
||||
int result = SelectClipRgn(context, hrgn);
|
||||
DCHECK_NE(result, ERROR);
|
||||
result = DeleteObject(hrgn);
|
||||
DCHECK_NE(result, 0);
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
|
@ -1,96 +1,96 @@
|
||||
// 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_WIN_H__
|
||||
#define BASE_GFX_PLATFORM_DEVICE_WIN_H__
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "SkDevice.h"
|
||||
|
||||
class SkMatrix;
|
||||
class SkPath;
|
||||
class SkRegion;
|
||||
|
||||
namespace gfx {
|
||||
|
||||
// A device is basically a wrapper around SkBitmap that provides a surface for
|
||||
// SkCanvas to draw into. Our device provides a surface Windows can also write
|
||||
// to. It also provides functionality to play well with GDI drawing functions.
|
||||
// This class is abstract and must be subclassed. It provides the basic
|
||||
// interface to implement it either with or without a bitmap backend.
|
||||
class PlatformDeviceWin : public SkDevice {
|
||||
public:
|
||||
// The DC that corresponds to the bitmap, used for GDI operations drawing
|
||||
// into the bitmap. This is possibly heavyweight, so it should be existant
|
||||
// only during one pass of rendering.
|
||||
virtual HDC getBitmapDC() = 0;
|
||||
|
||||
// Draws to the given screen DC, if the bitmap DC doesn't exist, this will
|
||||
// temporarily create it. However, if you have created the bitmap DC, it will
|
||||
// be more efficient if you don't free it until after this call so it doesn't
|
||||
// have to be created twice. If src_rect is null, then the entirety of the
|
||||
// source device will be copied.
|
||||
virtual void drawToHDC(HDC dc, int x, int y, const RECT* src_rect) = 0;
|
||||
|
||||
// Invoke before using GDI functions. See description in platform_device.cc
|
||||
// for specifics.
|
||||
// NOTE: x,y,width and height are relative to the current transform.
|
||||
virtual void prepareForGDI(int x, int y, int width, int height) { }
|
||||
|
||||
// Invoke after using GDI functions. See description in platform_device.cc
|
||||
// for specifics.
|
||||
// NOTE: x,y,width and height are relative to the current transform.
|
||||
virtual void postProcessGDI(int x, int y, int width, int height) { }
|
||||
|
||||
// Sets the opacity of each pixel in the specified region to be opaque.
|
||||
virtual void makeOpaque(int x, int y, int width, int height) { }
|
||||
|
||||
// Call this function to fix the alpha channels before compositing this layer
|
||||
// onto another. Internally, the device uses a special alpha method to work
|
||||
// around problems with Windows. This call will put the values into what
|
||||
// Skia expects, so it can be composited onto other layers.
|
||||
//
|
||||
// After this call, no more drawing can be done because the
|
||||
// alpha channels will be "correct", which, if this function is called again
|
||||
// will make them wrong. See the implementation for more discussion.
|
||||
virtual void fixupAlphaBeforeCompositing() { }
|
||||
|
||||
// Returns if the preferred rendering engine is vectorial or bitmap based.
|
||||
virtual bool IsVectorial() = 0;
|
||||
|
||||
// Initializes the default settings and colors in a device context.
|
||||
static void InitializeDC(HDC context);
|
||||
|
||||
// Loads a SkPath into the GDI context. The path can there after be used for
|
||||
// clipping or as a stroke.
|
||||
static void LoadPathToDC(HDC context, const SkPath& path);
|
||||
|
||||
// Loads a SkRegion into the GDI context.
|
||||
static void LoadClippingRegionToDC(HDC context, const SkRegion& region,
|
||||
const SkMatrix& transformation);
|
||||
|
||||
protected:
|
||||
// Arrays must be inside structures.
|
||||
struct CubicPoints {
|
||||
SkPoint p[4];
|
||||
};
|
||||
typedef std::vector<CubicPoints> CubicPath;
|
||||
typedef std::vector<CubicPath> CubicPaths;
|
||||
|
||||
// Forwards |bitmap| to SkDevice's constructor.
|
||||
PlatformDeviceWin(const SkBitmap& bitmap);
|
||||
|
||||
// Loads the specified Skia transform into the device context, excluding
|
||||
// perspective (which GDI doesn't support).
|
||||
static void LoadTransformToDC(HDC dc, const SkMatrix& matrix);
|
||||
|
||||
// Transforms SkPath's paths into a series of cubic path.
|
||||
static bool SkPathToCubicPaths(CubicPaths* paths, const SkPath& skpath);
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
#endif // BASE_GFX_PLATFORM_DEVICE_WIN_H__
|
||||
|
||||
// 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_WIN_H__
|
||||
#define BASE_GFX_PLATFORM_DEVICE_WIN_H__
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "SkDevice.h"
|
||||
|
||||
class SkMatrix;
|
||||
class SkPath;
|
||||
class SkRegion;
|
||||
|
||||
namespace gfx {
|
||||
|
||||
// A device is basically a wrapper around SkBitmap that provides a surface for
|
||||
// SkCanvas to draw into. Our device provides a surface Windows can also write
|
||||
// to. It also provides functionality to play well with GDI drawing functions.
|
||||
// This class is abstract and must be subclassed. It provides the basic
|
||||
// interface to implement it either with or without a bitmap backend.
|
||||
class PlatformDeviceWin : public SkDevice {
|
||||
public:
|
||||
// The DC that corresponds to the bitmap, used for GDI operations drawing
|
||||
// into the bitmap. This is possibly heavyweight, so it should be existant
|
||||
// only during one pass of rendering.
|
||||
virtual HDC getBitmapDC() = 0;
|
||||
|
||||
// Draws to the given screen DC, if the bitmap DC doesn't exist, this will
|
||||
// temporarily create it. However, if you have created the bitmap DC, it will
|
||||
// be more efficient if you don't free it until after this call so it doesn't
|
||||
// have to be created twice. If src_rect is null, then the entirety of the
|
||||
// source device will be copied.
|
||||
virtual void drawToHDC(HDC dc, int x, int y, const RECT* src_rect) = 0;
|
||||
|
||||
// Invoke before using GDI functions. See description in platform_device.cc
|
||||
// for specifics.
|
||||
// NOTE: x,y,width and height are relative to the current transform.
|
||||
virtual void prepareForGDI(int x, int y, int width, int height) { }
|
||||
|
||||
// Invoke after using GDI functions. See description in platform_device.cc
|
||||
// for specifics.
|
||||
// NOTE: x,y,width and height are relative to the current transform.
|
||||
virtual void postProcessGDI(int x, int y, int width, int height) { }
|
||||
|
||||
// Sets the opacity of each pixel in the specified region to be opaque.
|
||||
virtual void makeOpaque(int x, int y, int width, int height) { }
|
||||
|
||||
// Call this function to fix the alpha channels before compositing this layer
|
||||
// onto another. Internally, the device uses a special alpha method to work
|
||||
// around problems with Windows. This call will put the values into what
|
||||
// Skia expects, so it can be composited onto other layers.
|
||||
//
|
||||
// After this call, no more drawing can be done because the
|
||||
// alpha channels will be "correct", which, if this function is called again
|
||||
// will make them wrong. See the implementation for more discussion.
|
||||
virtual void fixupAlphaBeforeCompositing() { }
|
||||
|
||||
// Returns if the preferred rendering engine is vectorial or bitmap based.
|
||||
virtual bool IsVectorial() = 0;
|
||||
|
||||
// Initializes the default settings and colors in a device context.
|
||||
static void InitializeDC(HDC context);
|
||||
|
||||
// Loads a SkPath into the GDI context. The path can there after be used for
|
||||
// clipping or as a stroke.
|
||||
static void LoadPathToDC(HDC context, const SkPath& path);
|
||||
|
||||
// Loads a SkRegion into the GDI context.
|
||||
static void LoadClippingRegionToDC(HDC context, const SkRegion& region,
|
||||
const SkMatrix& transformation);
|
||||
|
||||
protected:
|
||||
// Arrays must be inside structures.
|
||||
struct CubicPoints {
|
||||
SkPoint p[4];
|
||||
};
|
||||
typedef std::vector<CubicPoints> CubicPath;
|
||||
typedef std::vector<CubicPath> CubicPaths;
|
||||
|
||||
// Forwards |bitmap| to SkDevice's constructor.
|
||||
PlatformDeviceWin(const SkBitmap& bitmap);
|
||||
|
||||
// Loads the specified Skia transform into the device context, excluding
|
||||
// perspective (which GDI doesn't support).
|
||||
static void LoadTransformToDC(HDC dc, const SkMatrix& matrix);
|
||||
|
||||
// Transforms SkPath's paths into a series of cubic path.
|
||||
static bool SkPathToCubicPaths(CubicPaths* paths, const SkPath& skpath);
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
#endif // BASE_GFX_PLATFORM_DEVICE_WIN_H__
|
||||
|
||||
|
@ -1,80 +1,80 @@
|
||||
# Copyright (c) 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.
|
||||
|
||||
# Ripped and modded from chrome.
|
||||
|
||||
Import('env')
|
||||
|
||||
env = env.Clone(
|
||||
)
|
||||
|
||||
env.Replace(
|
||||
LIBGD_DIR = '$THIRD_PARTY_DIR/libgd',
|
||||
CPPPATH = [
|
||||
'$LIBGD_DIR',
|
||||
'$THIRD_PARTY_DIR/libjpeg',
|
||||
'$THIRD_PARTY_DIR/libpng',
|
||||
'$THIRD_PARTY_DIR/zlib',
|
||||
],
|
||||
)
|
||||
|
||||
env.Append(
|
||||
CPPDEFINES = [
|
||||
'HAVE_CONFIG_H',
|
||||
'BGDWIN32',
|
||||
],
|
||||
|
||||
)
|
||||
|
||||
if env['PLATFORM'] == 'win32':
|
||||
env.Append(
|
||||
CPPFLAGS = [
|
||||
# Disable some warnings when building third-party code, so we can enable /WX.
|
||||
# Examples:
|
||||
# warning C4244: conversion from 'type1' to 'type2', possible loss of data
|
||||
# warning C4018: signed/unsigned mismatch in comparison
|
||||
# warning C4003: not enough actual parameters for macro
|
||||
'/wd4244',
|
||||
'/wd4996',
|
||||
'/wd4005',
|
||||
'/wd4142',
|
||||
'/wd4018',
|
||||
'/wd4133',
|
||||
'/wd4102',
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
input_files = [
|
||||
'$LIBGD_DIR/gd.c',
|
||||
'$LIBGD_DIR/gdfx.c',
|
||||
'$LIBGD_DIR/gd_security.c',
|
||||
'$LIBGD_DIR/gd_gd.c',
|
||||
'$LIBGD_DIR/gd_gd2.c',
|
||||
'$LIBGD_DIR/gd_io.c',
|
||||
'$LIBGD_DIR/gd_io_dp.c',
|
||||
'$LIBGD_DIR/gd_gif_in.c',
|
||||
'$LIBGD_DIR/gd_gif_out.c',
|
||||
'$LIBGD_DIR/gd_io_file.c',
|
||||
'$LIBGD_DIR/gd_io_ss.c',
|
||||
'$LIBGD_DIR/gd_jpeg.c',
|
||||
'$LIBGD_DIR/gd_png.c',
|
||||
'$LIBGD_DIR/gd_ss.c',
|
||||
'$LIBGD_DIR/gd_topal.c',
|
||||
'$LIBGD_DIR/gd_wbmp.c',
|
||||
'$LIBGD_DIR/gdcache.c',
|
||||
'$LIBGD_DIR/gdfontg.c',
|
||||
'$LIBGD_DIR/gdfontl.c',
|
||||
'$LIBGD_DIR/gdfontmb.c',
|
||||
'$LIBGD_DIR/gdfonts.c',
|
||||
'$LIBGD_DIR/gdfontt.c',
|
||||
'$LIBGD_DIR/gdft.c',
|
||||
'$LIBGD_DIR/gdhelpers.c',
|
||||
'$LIBGD_DIR/gdkanji.c',
|
||||
'$LIBGD_DIR/gdtables.c',
|
||||
'$LIBGD_DIR/gdxpm.c',
|
||||
'$LIBGD_DIR/wbmp.c',
|
||||
]
|
||||
|
||||
env.ChromeStaticLibrary('gd', input_files)
|
||||
# Copyright (c) 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.
|
||||
|
||||
# Ripped and modded from chrome.
|
||||
|
||||
Import('env')
|
||||
|
||||
env = env.Clone(
|
||||
)
|
||||
|
||||
env.Replace(
|
||||
LIBGD_DIR = '$THIRD_PARTY_DIR/libgd',
|
||||
CPPPATH = [
|
||||
'$LIBGD_DIR',
|
||||
'$THIRD_PARTY_DIR/libjpeg',
|
||||
'$THIRD_PARTY_DIR/libpng',
|
||||
'$THIRD_PARTY_DIR/zlib',
|
||||
],
|
||||
)
|
||||
|
||||
env.Append(
|
||||
CPPDEFINES = [
|
||||
'HAVE_CONFIG_H',
|
||||
'BGDWIN32',
|
||||
],
|
||||
|
||||
)
|
||||
|
||||
if env['PLATFORM'] == 'win32':
|
||||
env.Append(
|
||||
CPPFLAGS = [
|
||||
# Disable some warnings when building third-party code, so we can enable /WX.
|
||||
# Examples:
|
||||
# warning C4244: conversion from 'type1' to 'type2', possible loss of data
|
||||
# warning C4018: signed/unsigned mismatch in comparison
|
||||
# warning C4003: not enough actual parameters for macro
|
||||
'/wd4244',
|
||||
'/wd4996',
|
||||
'/wd4005',
|
||||
'/wd4142',
|
||||
'/wd4018',
|
||||
'/wd4133',
|
||||
'/wd4102',
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
input_files = [
|
||||
'$LIBGD_DIR/gd.c',
|
||||
'$LIBGD_DIR/gdfx.c',
|
||||
'$LIBGD_DIR/gd_security.c',
|
||||
'$LIBGD_DIR/gd_gd.c',
|
||||
'$LIBGD_DIR/gd_gd2.c',
|
||||
'$LIBGD_DIR/gd_io.c',
|
||||
'$LIBGD_DIR/gd_io_dp.c',
|
||||
'$LIBGD_DIR/gd_gif_in.c',
|
||||
'$LIBGD_DIR/gd_gif_out.c',
|
||||
'$LIBGD_DIR/gd_io_file.c',
|
||||
'$LIBGD_DIR/gd_io_ss.c',
|
||||
'$LIBGD_DIR/gd_jpeg.c',
|
||||
'$LIBGD_DIR/gd_png.c',
|
||||
'$LIBGD_DIR/gd_ss.c',
|
||||
'$LIBGD_DIR/gd_topal.c',
|
||||
'$LIBGD_DIR/gd_wbmp.c',
|
||||
'$LIBGD_DIR/gdcache.c',
|
||||
'$LIBGD_DIR/gdfontg.c',
|
||||
'$LIBGD_DIR/gdfontl.c',
|
||||
'$LIBGD_DIR/gdfontmb.c',
|
||||
'$LIBGD_DIR/gdfonts.c',
|
||||
'$LIBGD_DIR/gdfontt.c',
|
||||
'$LIBGD_DIR/gdft.c',
|
||||
'$LIBGD_DIR/gdhelpers.c',
|
||||
'$LIBGD_DIR/gdkanji.c',
|
||||
'$LIBGD_DIR/gdtables.c',
|
||||
'$LIBGD_DIR/gdxpm.c',
|
||||
'$LIBGD_DIR/wbmp.c',
|
||||
]
|
||||
|
||||
env.ChromeStaticLibrary('gd', input_files)
|
||||
|
@ -1,74 +1,74 @@
|
||||
# Copyright (c) 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.
|
||||
|
||||
# Ripped and modded from chrome.
|
||||
|
||||
Import('env')
|
||||
|
||||
env = env.Clone(
|
||||
LIBJPEG_DIR = ''
|
||||
)
|
||||
|
||||
env.Replace(
|
||||
LIBJPEG_DIR = '$THIRD_PARTY_DIR/libjpeg',
|
||||
CPPPATH = [
|
||||
'$LIBJPEG_DIR',
|
||||
],
|
||||
)
|
||||
|
||||
#env.Append(
|
||||
# CPPDEFINES = [
|
||||
# ],
|
||||
#)
|
||||
|
||||
input_files = [
|
||||
'$LIBJPEG_DIR/jcapimin.c',
|
||||
'$LIBJPEG_DIR/jcapistd.c',
|
||||
'$LIBJPEG_DIR/jccoefct.c',
|
||||
'$LIBJPEG_DIR/jccolor.c',
|
||||
'$LIBJPEG_DIR/jcdctmgr.c',
|
||||
'$LIBJPEG_DIR/jchuff.c',
|
||||
'$LIBJPEG_DIR/jcinit.c',
|
||||
'$LIBJPEG_DIR/jcmainct.c',
|
||||
'$LIBJPEG_DIR/jcmarker.c',
|
||||
'$LIBJPEG_DIR/jcmaster.c',
|
||||
'$LIBJPEG_DIR/jcomapi.c',
|
||||
'$LIBJPEG_DIR/jcparam.c',
|
||||
'$LIBJPEG_DIR/jcphuff.c',
|
||||
'$LIBJPEG_DIR/jcprepct.c',
|
||||
'$LIBJPEG_DIR/jcsample.c',
|
||||
'$LIBJPEG_DIR/jctrans.c',
|
||||
'$LIBJPEG_DIR/jdapimin.c',
|
||||
'$LIBJPEG_DIR/jdapistd.c',
|
||||
'$LIBJPEG_DIR/jdatadst.c',
|
||||
'$LIBJPEG_DIR/jdatasrc.c',
|
||||
'$LIBJPEG_DIR/jdcoefct.c',
|
||||
'$LIBJPEG_DIR/jdcolor.c',
|
||||
'$LIBJPEG_DIR/jddctmgr.c',
|
||||
'$LIBJPEG_DIR/jdhuff.c',
|
||||
'$LIBJPEG_DIR/jdinput.c',
|
||||
'$LIBJPEG_DIR/jdmainct.c',
|
||||
'$LIBJPEG_DIR/jdmarker.c',
|
||||
'$LIBJPEG_DIR/jdmaster.c',
|
||||
'$LIBJPEG_DIR/jdmerge.c',
|
||||
'$LIBJPEG_DIR/jdphuff.c',
|
||||
'$LIBJPEG_DIR/jdpostct.c',
|
||||
'$LIBJPEG_DIR/jdsample.c',
|
||||
'$LIBJPEG_DIR/jdtrans.c',
|
||||
'$LIBJPEG_DIR/jerror.c',
|
||||
'$LIBJPEG_DIR/jfdctflt.c',
|
||||
'$LIBJPEG_DIR/jfdctfst.c',
|
||||
'$LIBJPEG_DIR/jfdctint.c',
|
||||
'$LIBJPEG_DIR/jidctflt.c',
|
||||
'$LIBJPEG_DIR/jidctfst.c',
|
||||
'$LIBJPEG_DIR/jidctint.c',
|
||||
'$LIBJPEG_DIR/jidctred.c',
|
||||
'$LIBJPEG_DIR/jquant1.c',
|
||||
'$LIBJPEG_DIR/jquant2.c',
|
||||
'$LIBJPEG_DIR/jutils.c',
|
||||
'$LIBJPEG_DIR/jmemmgr.c',
|
||||
'$LIBJPEG_DIR/jmemnobs.c',
|
||||
]
|
||||
|
||||
env.ChromeStaticLibrary('jpeg', input_files)
|
||||
# Copyright (c) 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.
|
||||
|
||||
# Ripped and modded from chrome.
|
||||
|
||||
Import('env')
|
||||
|
||||
env = env.Clone(
|
||||
LIBJPEG_DIR = ''
|
||||
)
|
||||
|
||||
env.Replace(
|
||||
LIBJPEG_DIR = '$THIRD_PARTY_DIR/libjpeg',
|
||||
CPPPATH = [
|
||||
'$LIBJPEG_DIR',
|
||||
],
|
||||
)
|
||||
|
||||
#env.Append(
|
||||
# CPPDEFINES = [
|
||||
# ],
|
||||
#)
|
||||
|
||||
input_files = [
|
||||
'$LIBJPEG_DIR/jcapimin.c',
|
||||
'$LIBJPEG_DIR/jcapistd.c',
|
||||
'$LIBJPEG_DIR/jccoefct.c',
|
||||
'$LIBJPEG_DIR/jccolor.c',
|
||||
'$LIBJPEG_DIR/jcdctmgr.c',
|
||||
'$LIBJPEG_DIR/jchuff.c',
|
||||
'$LIBJPEG_DIR/jcinit.c',
|
||||
'$LIBJPEG_DIR/jcmainct.c',
|
||||
'$LIBJPEG_DIR/jcmarker.c',
|
||||
'$LIBJPEG_DIR/jcmaster.c',
|
||||
'$LIBJPEG_DIR/jcomapi.c',
|
||||
'$LIBJPEG_DIR/jcparam.c',
|
||||
'$LIBJPEG_DIR/jcphuff.c',
|
||||
'$LIBJPEG_DIR/jcprepct.c',
|
||||
'$LIBJPEG_DIR/jcsample.c',
|
||||
'$LIBJPEG_DIR/jctrans.c',
|
||||
'$LIBJPEG_DIR/jdapimin.c',
|
||||
'$LIBJPEG_DIR/jdapistd.c',
|
||||
'$LIBJPEG_DIR/jdatadst.c',
|
||||
'$LIBJPEG_DIR/jdatasrc.c',
|
||||
'$LIBJPEG_DIR/jdcoefct.c',
|
||||
'$LIBJPEG_DIR/jdcolor.c',
|
||||
'$LIBJPEG_DIR/jddctmgr.c',
|
||||
'$LIBJPEG_DIR/jdhuff.c',
|
||||
'$LIBJPEG_DIR/jdinput.c',
|
||||
'$LIBJPEG_DIR/jdmainct.c',
|
||||
'$LIBJPEG_DIR/jdmarker.c',
|
||||
'$LIBJPEG_DIR/jdmaster.c',
|
||||
'$LIBJPEG_DIR/jdmerge.c',
|
||||
'$LIBJPEG_DIR/jdphuff.c',
|
||||
'$LIBJPEG_DIR/jdpostct.c',
|
||||
'$LIBJPEG_DIR/jdsample.c',
|
||||
'$LIBJPEG_DIR/jdtrans.c',
|
||||
'$LIBJPEG_DIR/jerror.c',
|
||||
'$LIBJPEG_DIR/jfdctflt.c',
|
||||
'$LIBJPEG_DIR/jfdctfst.c',
|
||||
'$LIBJPEG_DIR/jfdctint.c',
|
||||
'$LIBJPEG_DIR/jidctflt.c',
|
||||
'$LIBJPEG_DIR/jidctfst.c',
|
||||
'$LIBJPEG_DIR/jidctint.c',
|
||||
'$LIBJPEG_DIR/jidctred.c',
|
||||
'$LIBJPEG_DIR/jquant1.c',
|
||||
'$LIBJPEG_DIR/jquant2.c',
|
||||
'$LIBJPEG_DIR/jutils.c',
|
||||
'$LIBJPEG_DIR/jmemmgr.c',
|
||||
'$LIBJPEG_DIR/jmemnobs.c',
|
||||
]
|
||||
|
||||
env.ChromeStaticLibrary('jpeg', input_files)
|
||||
|
@ -1,52 +1,52 @@
|
||||
# Copyright (c) 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.
|
||||
|
||||
# Ripped and modded from chrome.
|
||||
|
||||
Import('env')
|
||||
|
||||
env = env.Clone(
|
||||
)
|
||||
|
||||
env.Replace(
|
||||
LIBPNG_DIR = '$THIRD_PARTY_DIR/libpng',
|
||||
CPPPATH = [
|
||||
'$LIBPNG_DIR',
|
||||
'$THIRD_PARTY_DIR/zlib',
|
||||
],
|
||||
)
|
||||
|
||||
env.Append(
|
||||
CPPDEFINES = [
|
||||
],
|
||||
)
|
||||
|
||||
input_files = [
|
||||
# Common Files
|
||||
'$LIBPNG_DIR/png.c',
|
||||
'$LIBPNG_DIR/pngerror.c',
|
||||
'$LIBPNG_DIR/pngget.c',
|
||||
'$LIBPNG_DIR/pngmem.c',
|
||||
'$LIBPNG_DIR/pngset.c',
|
||||
'$LIBPNG_DIR/pngtrans.c',
|
||||
|
||||
# Reading PNGs
|
||||
'$LIBPNG_DIR/pngpread.c',
|
||||
'$LIBPNG_DIR/pngread.c',
|
||||
'$LIBPNG_DIR/pngrio.c',
|
||||
'$LIBPNG_DIR/pngrtran.c',
|
||||
'$LIBPNG_DIR/pngrutil.c',
|
||||
]
|
||||
|
||||
# The following files are not yet needed; exclude them to save size.
|
||||
if not env['OFFICIAL_BUILD']:
|
||||
input_files += [
|
||||
# Writing PNGs
|
||||
'$LIBPNG_DIR/pngwio.c',
|
||||
'$LIBPNG_DIR/pngwrite.c',
|
||||
'$LIBPNG_DIR/pngwtran.c',
|
||||
'$LIBPNG_DIR/pngwutil.c',
|
||||
]
|
||||
|
||||
env.ChromeStaticLibrary('png', input_files)
|
||||
# Copyright (c) 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.
|
||||
|
||||
# Ripped and modded from chrome.
|
||||
|
||||
Import('env')
|
||||
|
||||
env = env.Clone(
|
||||
)
|
||||
|
||||
env.Replace(
|
||||
LIBPNG_DIR = '$THIRD_PARTY_DIR/libpng',
|
||||
CPPPATH = [
|
||||
'$LIBPNG_DIR',
|
||||
'$THIRD_PARTY_DIR/zlib',
|
||||
],
|
||||
)
|
||||
|
||||
env.Append(
|
||||
CPPDEFINES = [
|
||||
],
|
||||
)
|
||||
|
||||
input_files = [
|
||||
# Common Files
|
||||
'$LIBPNG_DIR/png.c',
|
||||
'$LIBPNG_DIR/pngerror.c',
|
||||
'$LIBPNG_DIR/pngget.c',
|
||||
'$LIBPNG_DIR/pngmem.c',
|
||||
'$LIBPNG_DIR/pngset.c',
|
||||
'$LIBPNG_DIR/pngtrans.c',
|
||||
|
||||
# Reading PNGs
|
||||
'$LIBPNG_DIR/pngpread.c',
|
||||
'$LIBPNG_DIR/pngread.c',
|
||||
'$LIBPNG_DIR/pngrio.c',
|
||||
'$LIBPNG_DIR/pngrtran.c',
|
||||
'$LIBPNG_DIR/pngrutil.c',
|
||||
]
|
||||
|
||||
# The following files are not yet needed; exclude them to save size.
|
||||
if not env['OFFICIAL_BUILD']:
|
||||
input_files += [
|
||||
# Writing PNGs
|
||||
'$LIBPNG_DIR/pngwio.c',
|
||||
'$LIBPNG_DIR/pngwrite.c',
|
||||
'$LIBPNG_DIR/pngwtran.c',
|
||||
'$LIBPNG_DIR/pngwutil.c',
|
||||
]
|
||||
|
||||
env.ChromeStaticLibrary('png', input_files)
|
||||
|
@ -1,51 +1,51 @@
|
||||
# Copyright (c) 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.
|
||||
|
||||
Import('env')
|
||||
|
||||
env = env.Clone(
|
||||
)
|
||||
|
||||
env.Replace(
|
||||
PA_DIR = '$THIRD_PARTY_DIR/portaudio',
|
||||
CPPPATH = [
|
||||
'$PA_DIR/include',
|
||||
'$PA_DIR/src/common',
|
||||
'$PA_DIR/src/os/win',
|
||||
],
|
||||
)
|
||||
|
||||
env.Append(
|
||||
CPPDEFINES = [
|
||||
'PA_NO_DS',
|
||||
'PA_NO_ASIO',
|
||||
],
|
||||
)
|
||||
|
||||
if env['PLATFORM'] == 'win32':
|
||||
env.Append(
|
||||
CPPFLAGS = [
|
||||
'/wd4133',
|
||||
'/wd4101',
|
||||
],
|
||||
)
|
||||
|
||||
input_files = [
|
||||
'$PA_DIR/src/common/pa_allocation.c',
|
||||
'$PA_DIR/src/common/pa_converters.c',
|
||||
'$PA_DIR/src/common/pa_cpuload.c',
|
||||
'$PA_DIR/src/common/pa_debugprint.c',
|
||||
'$PA_DIR/src/common/pa_dither.c',
|
||||
'$PA_DIR/src/common/pa_front.c',
|
||||
'$PA_DIR/src/common/pa_process.c',
|
||||
'$PA_DIR/src/common/pa_skeleton.c',
|
||||
'$PA_DIR/src/common/pa_stream.c',
|
||||
'$PA_DIR/src/common/pa_trace.c',
|
||||
'$PA_DIR/src/hostapi/wmme/pa_win_wmme.c',
|
||||
'$PA_DIR/src/os/win/pa_win_hostapis.c',
|
||||
'$PA_DIR/src/os/win/pa_win_util.c',
|
||||
'$PA_DIR/src/os/win/pa_win_waveformat.c',
|
||||
]
|
||||
|
||||
env.ChromeStaticLibrary('portaudio', input_files)
|
||||
# Copyright (c) 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.
|
||||
|
||||
Import('env')
|
||||
|
||||
env = env.Clone(
|
||||
)
|
||||
|
||||
env.Replace(
|
||||
PA_DIR = '$THIRD_PARTY_DIR/portaudio',
|
||||
CPPPATH = [
|
||||
'$PA_DIR/include',
|
||||
'$PA_DIR/src/common',
|
||||
'$PA_DIR/src/os/win',
|
||||
],
|
||||
)
|
||||
|
||||
env.Append(
|
||||
CPPDEFINES = [
|
||||
'PA_NO_DS',
|
||||
'PA_NO_ASIO',
|
||||
],
|
||||
)
|
||||
|
||||
if env['PLATFORM'] == 'win32':
|
||||
env.Append(
|
||||
CPPFLAGS = [
|
||||
'/wd4133',
|
||||
'/wd4101',
|
||||
],
|
||||
)
|
||||
|
||||
input_files = [
|
||||
'$PA_DIR/src/common/pa_allocation.c',
|
||||
'$PA_DIR/src/common/pa_converters.c',
|
||||
'$PA_DIR/src/common/pa_cpuload.c',
|
||||
'$PA_DIR/src/common/pa_debugprint.c',
|
||||
'$PA_DIR/src/common/pa_dither.c',
|
||||
'$PA_DIR/src/common/pa_front.c',
|
||||
'$PA_DIR/src/common/pa_process.c',
|
||||
'$PA_DIR/src/common/pa_skeleton.c',
|
||||
'$PA_DIR/src/common/pa_stream.c',
|
||||
'$PA_DIR/src/common/pa_trace.c',
|
||||
'$PA_DIR/src/hostapi/wmme/pa_win_wmme.c',
|
||||
'$PA_DIR/src/os/win/pa_win_hostapis.c',
|
||||
'$PA_DIR/src/os/win/pa_win_util.c',
|
||||
'$PA_DIR/src/os/win/pa_win_waveformat.c',
|
||||
]
|
||||
|
||||
env.ChromeStaticLibrary('portaudio', input_files)
|
||||
|
@ -1,47 +1,47 @@
|
||||
# Copyright (c) 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.
|
||||
|
||||
# Ripped and modded from chrome.
|
||||
|
||||
Import('env')
|
||||
|
||||
env = env.Clone(
|
||||
)
|
||||
|
||||
env.Replace(
|
||||
ZLIB_DIR = '$THIRD_PARTY_DIR/zlib',
|
||||
CPPPATH = [
|
||||
'$ZLIB_DIR',
|
||||
],
|
||||
)
|
||||
|
||||
#env.Append(
|
||||
# CPPDEFINES = [
|
||||
# ],
|
||||
#)
|
||||
|
||||
input_files = [
|
||||
# Common Files
|
||||
'$ZLIB_DIR/adler32.c',
|
||||
'$ZLIB_DIR/zutil.c',
|
||||
# Inflate Algorithm (use inflate or infback, but not both)
|
||||
'$ZLIB_DIR/inflate.c',
|
||||
'$ZLIB_DIR/inffast.c',
|
||||
'$ZLIB_DIR/inftrees.c',
|
||||
]
|
||||
|
||||
# The following files are not yet needed; exclude them to save size.
|
||||
if not env['OFFICIAL_BUILD']:
|
||||
input_files += [
|
||||
# Other Algorithms
|
||||
'$ZLIB_DIR/compress.c',
|
||||
'$ZLIB_DIR/deflate.c',
|
||||
'$ZLIB_DIR/uncompr.c',
|
||||
# Other Common Files
|
||||
'$ZLIB_DIR/crc32.c',
|
||||
'$ZLIB_DIR/gzio.c',
|
||||
'$ZLIB_DIR/trees.c',
|
||||
]
|
||||
|
||||
env.ChromeStaticLibrary('zlib-gears', input_files)
|
||||
# Copyright (c) 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.
|
||||
|
||||
# Ripped and modded from chrome.
|
||||
|
||||
Import('env')
|
||||
|
||||
env = env.Clone(
|
||||
)
|
||||
|
||||
env.Replace(
|
||||
ZLIB_DIR = '$THIRD_PARTY_DIR/zlib',
|
||||
CPPPATH = [
|
||||
'$ZLIB_DIR',
|
||||
],
|
||||
)
|
||||
|
||||
#env.Append(
|
||||
# CPPDEFINES = [
|
||||
# ],
|
||||
#)
|
||||
|
||||
input_files = [
|
||||
# Common Files
|
||||
'$ZLIB_DIR/adler32.c',
|
||||
'$ZLIB_DIR/zutil.c',
|
||||
# Inflate Algorithm (use inflate or infback, but not both)
|
||||
'$ZLIB_DIR/inflate.c',
|
||||
'$ZLIB_DIR/inffast.c',
|
||||
'$ZLIB_DIR/inftrees.c',
|
||||
]
|
||||
|
||||
# The following files are not yet needed; exclude them to save size.
|
||||
if not env['OFFICIAL_BUILD']:
|
||||
input_files += [
|
||||
# Other Algorithms
|
||||
'$ZLIB_DIR/compress.c',
|
||||
'$ZLIB_DIR/deflate.c',
|
||||
'$ZLIB_DIR/uncompr.c',
|
||||
# Other Common Files
|
||||
'$ZLIB_DIR/crc32.c',
|
||||
'$ZLIB_DIR/gzio.c',
|
||||
'$ZLIB_DIR/trees.c',
|
||||
]
|
||||
|
||||
env.ChromeStaticLibrary('zlib-gears', input_files)
|
||||
|
@ -1,34 +1,34 @@
|
||||
# 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.
|
||||
|
||||
Import('env')
|
||||
|
||||
env = env.Clone()
|
||||
|
||||
env.Prepend(
|
||||
CPPPATH = [
|
||||
'$GTEST_DIR',
|
||||
'$GTEST_DIR/include',
|
||||
],
|
||||
)
|
||||
|
||||
if env['PLATFORM'] == 'win32':
|
||||
env.Append(
|
||||
CCFLAGS = [
|
||||
'/TP',
|
||||
|
||||
'/WX',
|
||||
'/Wp64',
|
||||
],
|
||||
)
|
||||
|
||||
input_files = [
|
||||
'gtest/src/gtest-death-test.cc',
|
||||
'gtest/src/gtest-filepath.cc',
|
||||
'gtest/src/gtest-port.cc',
|
||||
'gtest/src/gtest.cc',
|
||||
]
|
||||
|
||||
env.ChromeStaticLibrary('gtest', input_files)
|
||||
|
||||
# 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.
|
||||
|
||||
Import('env')
|
||||
|
||||
env = env.Clone()
|
||||
|
||||
env.Prepend(
|
||||
CPPPATH = [
|
||||
'$GTEST_DIR',
|
||||
'$GTEST_DIR/include',
|
||||
],
|
||||
)
|
||||
|
||||
if env['PLATFORM'] == 'win32':
|
||||
env.Append(
|
||||
CCFLAGS = [
|
||||
'/TP',
|
||||
|
||||
'/WX',
|
||||
'/Wp64',
|
||||
],
|
||||
)
|
||||
|
||||
input_files = [
|
||||
'gtest/src/gtest-death-test.cc',
|
||||
'gtest/src/gtest-filepath.cc',
|
||||
'gtest/src/gtest-port.cc',
|
||||
'gtest/src/gtest.cc',
|
||||
]
|
||||
|
||||
env.ChromeStaticLibrary('gtest', input_files)
|
||||
|
||||
|
@ -1,269 +1,269 @@
|
||||
#!/bin/env python
|
||||
# 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.
|
||||
|
||||
|
||||
"""Module to setup and generate code coverage data
|
||||
|
||||
This module first sets up the environment for code coverage, instruments the
|
||||
binaries, runs the tests and collects the code coverage data.
|
||||
|
||||
|
||||
Usage:
|
||||
coverage.py --upload=<upload_location>
|
||||
--revision=<revision_number>
|
||||
--src_root=<root_of_source_tree>
|
||||
[--tools_path=<tools_path>]
|
||||
"""
|
||||
|
||||
import logging
|
||||
import optparse
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
import google.logging_utils
|
||||
import google.process_utils as proc
|
||||
|
||||
|
||||
# The list of binaries that will be instrumented for code coverage
|
||||
# TODO(niranjan): Add a complete list of binaries
|
||||
windows_binaries = ['unit_tests.exe',
|
||||
'ui_tests.exe']
|
||||
|
||||
# The list of tests that will be run
|
||||
#TODO(niranjan): Add more tests
|
||||
windows_tests = ['unit_tests.exe',
|
||||
'ui_tests.exe']
|
||||
|
||||
|
||||
def IsWindows():
|
||||
"""Checks if the current platform is Windows.
|
||||
"""
|
||||
return sys.platform[:3] == 'win'
|
||||
|
||||
|
||||
class Coverage(object):
|
||||
"""Class to set up and generate code coverage.
|
||||
|
||||
This class contains methods that are useful to set up the environment for
|
||||
code coverage.
|
||||
|
||||
Attributes:
|
||||
instrumented: A boolean indicating if all the binaries have been
|
||||
instrumented.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
revision,
|
||||
vsts_path = None,
|
||||
lcov_converter_path = None):
|
||||
google.logging_utils.config_root()
|
||||
self.revision = revision
|
||||
self.instrumented = False
|
||||
self.vsts_path = vsts_path
|
||||
self.lcov_converter_path = lcov_converter_path
|
||||
self._dir = None
|
||||
|
||||
|
||||
def SetUp(self, binaries):
|
||||
"""Set up the platform specific environment and instrument the binaries for
|
||||
coverage.
|
||||
|
||||
This method sets up the environment, instruments all the compiled binaries
|
||||
and sets up the code coverage counters.
|
||||
|
||||
Args:
|
||||
binaries: List of binaries that need to be instrumented.
|
||||
|
||||
Returns:
|
||||
Path of the file containing code coverage data on successful
|
||||
instrumentation.
|
||||
None on error.
|
||||
"""
|
||||
if self.instrumented:
|
||||
logging.error('Binaries already instrumented')
|
||||
return None
|
||||
coverage_file = None
|
||||
if IsWindows():
|
||||
# Stop all previous instance of VSPerfMon counters
|
||||
counters_command = ('%s -shutdown' %
|
||||
(os.path.join(self.vsts_path, 'vsperfcmd.exe')))
|
||||
(retcode, output) = proc.RunCommandFull(counters_command,
|
||||
collect_output=True)
|
||||
# TODO(niranjan): Add a check that to verify that the binaries were built
|
||||
# using the /PROFILE linker flag.
|
||||
if self.vsts_path == None or self.lcov_converter_path == None:
|
||||
return None
|
||||
# Remove trailing slashes
|
||||
self.vsts_path = self.vsts_path.rstrip('\\')
|
||||
instrument_command = '%s /COVERAGE ' % (os.path.join(self.vsts_path,
|
||||
'vsinstr.exe'))
|
||||
for binary in binaries:
|
||||
logging.info('binary = %s' % (binary))
|
||||
logging.info('instrument_command = %s' % (instrument_command))
|
||||
# Instrument each binary in the list
|
||||
(retcode, output) = proc.RunCommandFull(instrument_command + binary,
|
||||
collect_output=True)
|
||||
# Check if the file has been instrumented correctly.
|
||||
if output.pop().rfind('Successfully instrumented') == -1:
|
||||
logging.error('Error instrumenting %s' % (binary))
|
||||
return None
|
||||
|
||||
# Generate the file name for the coverage results
|
||||
self._dir = tempfile.mkdtemp()
|
||||
coverage_file = os.path.join(self._dir, 'chrome_win32_%s.coverage' %
|
||||
(self.revision))
|
||||
logging.info('.coverage file: %s' % (coverage_file))
|
||||
|
||||
# After all the binaries have been instrumented, we start the counters.
|
||||
counters_command = ('%s -start:coverage -output:%s' %
|
||||
(os.path.join(self.vsts_path, 'vsperfcmd.exe'),
|
||||
coverage_file))
|
||||
# Here we use subprocess.call() instead of the RunCommandFull because the
|
||||
# VSPerfCmd spawns another process before terminating and this confuses
|
||||
# the subprocess.Popen() used by RunCommandFull.
|
||||
retcode = subprocess.call(counters_command)
|
||||
# TODO(niranjan): Check whether the counters have been started
|
||||
# successfully.
|
||||
|
||||
# We are now ready to run tests and measure code coverage.
|
||||
self.instrumented = True
|
||||
else:
|
||||
return None
|
||||
return coverage_file
|
||||
|
||||
|
||||
def TearDown(self):
|
||||
"""Tear down method.
|
||||
|
||||
This method shuts down the counters, and cleans up all the intermediate
|
||||
artifacts.
|
||||
"""
|
||||
if self.instrumented == False:
|
||||
return
|
||||
|
||||
if IsWindows():
|
||||
# Stop counters
|
||||
counters_command = ('%s -shutdown' %
|
||||
(os.path.join(self.vsts_path, 'vsperfcmd.exe')))
|
||||
(retcode, output) = proc.RunCommandFull(counters_command,
|
||||
collect_output=True)
|
||||
logging.info('Counters shut down: %s' % (output))
|
||||
# TODO(niranjan): Revert the instrumented binaries to their original
|
||||
# versions.
|
||||
else:
|
||||
return
|
||||
# Delete all the temp files and folders
|
||||
if self._dir != None:
|
||||
shutil.rmtree(self._dir, ignore_errors=True)
|
||||
logging.info('Cleaned up temporary files and folders')
|
||||
# Reset the instrumented flag.
|
||||
self.instrumented = False
|
||||
|
||||
|
||||
def Upload(self, coverage_file, upload_path, sym_path=None, src_root=None):
|
||||
"""Upload the results to the dashboard.
|
||||
|
||||
This method uploads the coverage data to a dashboard where it will be
|
||||
processed. On Windows, this method will first convert the .coverage file to
|
||||
the lcov format. This method needs to be called before the TearDown method.
|
||||
|
||||
Args:
|
||||
coverage_file: The coverage data file to upload.
|
||||
upload_path: Destination where the coverage data will be processed.
|
||||
sym_path: Symbol path for the build (Win32 only)
|
||||
src_root: Root folder of the source tree (Win32 only)
|
||||
|
||||
Returns:
|
||||
True on success.
|
||||
False on failure.
|
||||
"""
|
||||
if self.IsWindows():
|
||||
# Stop counters
|
||||
counters_command = ('%s -shutdown' %
|
||||
(os.path.join(self.vsts_path, 'vsperfcmd.exe')))
|
||||
(retcode, output) = proc.RunCommandFull(counters_command,
|
||||
collect_output=True)
|
||||
logging.info('Counters shut down: %s' % (output))
|
||||
# Convert the .coverage file to lcov format
|
||||
if self.lcov_converter_path == False:
|
||||
logging.error('Lcov converter tool not found')
|
||||
return False
|
||||
self.lcov_converter_path = self.lcov_converter_path.rstrip('\\')
|
||||
convert_command = ('%s -sym_path=%s -src_root=%s ' %
|
||||
(os.path.join(self.lcov_converter_path,
|
||||
'coverage_analyzer.exe'),
|
||||
sym_path,
|
||||
src_root))
|
||||
logging.info('Conversion to lcov complete')
|
||||
(retcode, output) = proc.RunCommandFull(convert_command + coverage_file,
|
||||
collect_output=True)
|
||||
shutil.copy(coverage_file, coverage_file.replace('.coverage', ''))
|
||||
# TODO(niranjan): Upload this somewhere!
|
||||
|
||||
|
||||
def main():
|
||||
# Command line parsing
|
||||
parser = optparse.OptionParser()
|
||||
# Path where the .coverage to .lcov converter tools are stored.
|
||||
parser.add_option('-t',
|
||||
'--tools_path',
|
||||
dest='tools_path',
|
||||
default=None,
|
||||
help='Location of the coverage tools (windows only)')
|
||||
parser.add_option('-u',
|
||||
'--upload',
|
||||
dest='upload_path'
|
||||
default=None,
|
||||
help='Location where the results should be uploaded')
|
||||
# We need the revision number so that we can generate the output file of the
|
||||
# format chrome_<platform>_<revision>.lcov
|
||||
parser.add_option('-r',
|
||||
'--revision',
|
||||
dest='revision',
|
||||
default=None,
|
||||
help='Revision number of the Chromium source repo')
|
||||
# Root of the source tree. Needed for converting the generated .coverage file
|
||||
# on Windows to the open source lcov format.
|
||||
parser.add_option('-s',
|
||||
'--src_root',
|
||||
dest='src_root',
|
||||
default=None,
|
||||
help='Root of the source repository')
|
||||
|
||||
if revision == None or src_root == None or upload_path == None:
|
||||
logging.error('Invalid command line arguments')
|
||||
sys.exit(1)
|
||||
|
||||
if IsWindows():
|
||||
# Initialize coverage
|
||||
cov = coverage.Coverage(revision,
|
||||
tools_path,
|
||||
tools_path)
|
||||
# Instrument the binaries
|
||||
coverage_file = cov.SetUp(windows_binaries)
|
||||
if coverage_file != None:
|
||||
# Run all the tests
|
||||
for test in windows_tests:
|
||||
logging.info('Executing test %s: ' % binary)
|
||||
(retcode, output) = proc.RunCommandFull(binary, collect_output=True)
|
||||
if retcode != 0:
|
||||
sys.exit(retcode)
|
||||
else:
|
||||
logging.error('Error during instrumentation.')
|
||||
sys.exit(1)
|
||||
|
||||
cov.Upload(coverage_file,
|
||||
upload_path,
|
||||
os.path.join(src_root, 'chrome', 'Release'),
|
||||
src_root)
|
||||
cov.TearDown()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
|
||||
#!/bin/env python
|
||||
# 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.
|
||||
|
||||
|
||||
"""Module to setup and generate code coverage data
|
||||
|
||||
This module first sets up the environment for code coverage, instruments the
|
||||
binaries, runs the tests and collects the code coverage data.
|
||||
|
||||
|
||||
Usage:
|
||||
coverage.py --upload=<upload_location>
|
||||
--revision=<revision_number>
|
||||
--src_root=<root_of_source_tree>
|
||||
[--tools_path=<tools_path>]
|
||||
"""
|
||||
|
||||
import logging
|
||||
import optparse
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
import google.logging_utils
|
||||
import google.process_utils as proc
|
||||
|
||||
|
||||
# The list of binaries that will be instrumented for code coverage
|
||||
# TODO(niranjan): Add a complete list of binaries
|
||||
windows_binaries = ['unit_tests.exe',
|
||||
'ui_tests.exe']
|
||||
|
||||
# The list of tests that will be run
|
||||
#TODO(niranjan): Add more tests
|
||||
windows_tests = ['unit_tests.exe',
|
||||
'ui_tests.exe']
|
||||
|
||||
|
||||
def IsWindows():
|
||||
"""Checks if the current platform is Windows.
|
||||
"""
|
||||
return sys.platform[:3] == 'win'
|
||||
|
||||
|
||||
class Coverage(object):
|
||||
"""Class to set up and generate code coverage.
|
||||
|
||||
This class contains methods that are useful to set up the environment for
|
||||
code coverage.
|
||||
|
||||
Attributes:
|
||||
instrumented: A boolean indicating if all the binaries have been
|
||||
instrumented.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
revision,
|
||||
vsts_path = None,
|
||||
lcov_converter_path = None):
|
||||
google.logging_utils.config_root()
|
||||
self.revision = revision
|
||||
self.instrumented = False
|
||||
self.vsts_path = vsts_path
|
||||
self.lcov_converter_path = lcov_converter_path
|
||||
self._dir = None
|
||||
|
||||
|
||||
def SetUp(self, binaries):
|
||||
"""Set up the platform specific environment and instrument the binaries for
|
||||
coverage.
|
||||
|
||||
This method sets up the environment, instruments all the compiled binaries
|
||||
and sets up the code coverage counters.
|
||||
|
||||
Args:
|
||||
binaries: List of binaries that need to be instrumented.
|
||||
|
||||
Returns:
|
||||
Path of the file containing code coverage data on successful
|
||||
instrumentation.
|
||||
None on error.
|
||||
"""
|
||||
if self.instrumented:
|
||||
logging.error('Binaries already instrumented')
|
||||
return None
|
||||
coverage_file = None
|
||||
if IsWindows():
|
||||
# Stop all previous instance of VSPerfMon counters
|
||||
counters_command = ('%s -shutdown' %
|
||||
(os.path.join(self.vsts_path, 'vsperfcmd.exe')))
|
||||
(retcode, output) = proc.RunCommandFull(counters_command,
|
||||
collect_output=True)
|
||||
# TODO(niranjan): Add a check that to verify that the binaries were built
|
||||
# using the /PROFILE linker flag.
|
||||
if self.vsts_path == None or self.lcov_converter_path == None:
|
||||
return None
|
||||
# Remove trailing slashes
|
||||
self.vsts_path = self.vsts_path.rstrip('\\')
|
||||
instrument_command = '%s /COVERAGE ' % (os.path.join(self.vsts_path,
|
||||
'vsinstr.exe'))
|
||||
for binary in binaries:
|
||||
logging.info('binary = %s' % (binary))
|
||||
logging.info('instrument_command = %s' % (instrument_command))
|
||||
# Instrument each binary in the list
|
||||
(retcode, output) = proc.RunCommandFull(instrument_command + binary,
|
||||
collect_output=True)
|
||||
# Check if the file has been instrumented correctly.
|
||||
if output.pop().rfind('Successfully instrumented') == -1:
|
||||
logging.error('Error instrumenting %s' % (binary))
|
||||
return None
|
||||
|
||||
# Generate the file name for the coverage results
|
||||
self._dir = tempfile.mkdtemp()
|
||||
coverage_file = os.path.join(self._dir, 'chrome_win32_%s.coverage' %
|
||||
(self.revision))
|
||||
logging.info('.coverage file: %s' % (coverage_file))
|
||||
|
||||
# After all the binaries have been instrumented, we start the counters.
|
||||
counters_command = ('%s -start:coverage -output:%s' %
|
||||
(os.path.join(self.vsts_path, 'vsperfcmd.exe'),
|
||||
coverage_file))
|
||||
# Here we use subprocess.call() instead of the RunCommandFull because the
|
||||
# VSPerfCmd spawns another process before terminating and this confuses
|
||||
# the subprocess.Popen() used by RunCommandFull.
|
||||
retcode = subprocess.call(counters_command)
|
||||
# TODO(niranjan): Check whether the counters have been started
|
||||
# successfully.
|
||||
|
||||
# We are now ready to run tests and measure code coverage.
|
||||
self.instrumented = True
|
||||
else:
|
||||
return None
|
||||
return coverage_file
|
||||
|
||||
|
||||
def TearDown(self):
|
||||
"""Tear down method.
|
||||
|
||||
This method shuts down the counters, and cleans up all the intermediate
|
||||
artifacts.
|
||||
"""
|
||||
if self.instrumented == False:
|
||||
return
|
||||
|
||||
if IsWindows():
|
||||
# Stop counters
|
||||
counters_command = ('%s -shutdown' %
|
||||
(os.path.join(self.vsts_path, 'vsperfcmd.exe')))
|
||||
(retcode, output) = proc.RunCommandFull(counters_command,
|
||||
collect_output=True)
|
||||
logging.info('Counters shut down: %s' % (output))
|
||||
# TODO(niranjan): Revert the instrumented binaries to their original
|
||||
# versions.
|
||||
else:
|
||||
return
|
||||
# Delete all the temp files and folders
|
||||
if self._dir != None:
|
||||
shutil.rmtree(self._dir, ignore_errors=True)
|
||||
logging.info('Cleaned up temporary files and folders')
|
||||
# Reset the instrumented flag.
|
||||
self.instrumented = False
|
||||
|
||||
|
||||
def Upload(self, coverage_file, upload_path, sym_path=None, src_root=None):
|
||||
"""Upload the results to the dashboard.
|
||||
|
||||
This method uploads the coverage data to a dashboard where it will be
|
||||
processed. On Windows, this method will first convert the .coverage file to
|
||||
the lcov format. This method needs to be called before the TearDown method.
|
||||
|
||||
Args:
|
||||
coverage_file: The coverage data file to upload.
|
||||
upload_path: Destination where the coverage data will be processed.
|
||||
sym_path: Symbol path for the build (Win32 only)
|
||||
src_root: Root folder of the source tree (Win32 only)
|
||||
|
||||
Returns:
|
||||
True on success.
|
||||
False on failure.
|
||||
"""
|
||||
if self.IsWindows():
|
||||
# Stop counters
|
||||
counters_command = ('%s -shutdown' %
|
||||
(os.path.join(self.vsts_path, 'vsperfcmd.exe')))
|
||||
(retcode, output) = proc.RunCommandFull(counters_command,
|
||||
collect_output=True)
|
||||
logging.info('Counters shut down: %s' % (output))
|
||||
# Convert the .coverage file to lcov format
|
||||
if self.lcov_converter_path == False:
|
||||
logging.error('Lcov converter tool not found')
|
||||
return False
|
||||
self.lcov_converter_path = self.lcov_converter_path.rstrip('\\')
|
||||
convert_command = ('%s -sym_path=%s -src_root=%s ' %
|
||||
(os.path.join(self.lcov_converter_path,
|
||||
'coverage_analyzer.exe'),
|
||||
sym_path,
|
||||
src_root))
|
||||
logging.info('Conversion to lcov complete')
|
||||
(retcode, output) = proc.RunCommandFull(convert_command + coverage_file,
|
||||
collect_output=True)
|
||||
shutil.copy(coverage_file, coverage_file.replace('.coverage', ''))
|
||||
# TODO(niranjan): Upload this somewhere!
|
||||
|
||||
|
||||
def main():
|
||||
# Command line parsing
|
||||
parser = optparse.OptionParser()
|
||||
# Path where the .coverage to .lcov converter tools are stored.
|
||||
parser.add_option('-t',
|
||||
'--tools_path',
|
||||
dest='tools_path',
|
||||
default=None,
|
||||
help='Location of the coverage tools (windows only)')
|
||||
parser.add_option('-u',
|
||||
'--upload',
|
||||
dest='upload_path'
|
||||
default=None,
|
||||
help='Location where the results should be uploaded')
|
||||
# We need the revision number so that we can generate the output file of the
|
||||
# format chrome_<platform>_<revision>.lcov
|
||||
parser.add_option('-r',
|
||||
'--revision',
|
||||
dest='revision',
|
||||
default=None,
|
||||
help='Revision number of the Chromium source repo')
|
||||
# Root of the source tree. Needed for converting the generated .coverage file
|
||||
# on Windows to the open source lcov format.
|
||||
parser.add_option('-s',
|
||||
'--src_root',
|
||||
dest='src_root',
|
||||
default=None,
|
||||
help='Root of the source repository')
|
||||
|
||||
if revision == None or src_root == None or upload_path == None:
|
||||
logging.error('Invalid command line arguments')
|
||||
sys.exit(1)
|
||||
|
||||
if IsWindows():
|
||||
# Initialize coverage
|
||||
cov = coverage.Coverage(revision,
|
||||
tools_path,
|
||||
tools_path)
|
||||
# Instrument the binaries
|
||||
coverage_file = cov.SetUp(windows_binaries)
|
||||
if coverage_file != None:
|
||||
# Run all the tests
|
||||
for test in windows_tests:
|
||||
logging.info('Executing test %s: ' % binary)
|
||||
(retcode, output) = proc.RunCommandFull(binary, collect_output=True)
|
||||
if retcode != 0:
|
||||
sys.exit(retcode)
|
||||
else:
|
||||
logging.error('Error during instrumentation.')
|
||||
sys.exit(1)
|
||||
|
||||
cov.Upload(coverage_file,
|
||||
upload_path,
|
||||
os.path.join(src_root, 'chrome', 'Release'),
|
||||
src_root)
|
||||
cov.TearDown()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
|
||||
|
@ -1,233 +1,233 @@
|
||||
#!/usr/bin/python2.4
|
||||
#
|
||||
# Copyright 2008, Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
"""Script to clean the lcov files and convert it to HTML
|
||||
|
||||
TODO(niranjan): Add usage information here
|
||||
"""
|
||||
|
||||
|
||||
import optparse
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
|
||||
# These are source files that were generated during compile time. We want to
|
||||
# remove references to these files from the lcov file otherwise genhtml will
|
||||
# throw an error.
|
||||
win32_srcs_exclude = ['parse.y',
|
||||
'xpathgrammar.cpp',
|
||||
'cssgrammar.cpp']
|
||||
|
||||
|
||||
def CleanPathNames(dir):
|
||||
"""Clean the pathnames of the HTML generated by genhtml.
|
||||
|
||||
This method is required only for code coverage on Win32. Due to a known issue
|
||||
with reading from CIFS shares mounted on Linux, genhtml appends a ^M to every
|
||||
file name it reads from the Windows share, causing corrupt filenames in
|
||||
genhtml's output folder.
|
||||
|
||||
Args:
|
||||
dir: Output folder of the genhtml output.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
# Stip off the ^M characters that get appended to the file name
|
||||
for file in os.walk(dir):
|
||||
file_clean = file.replace('\r', '')
|
||||
if file_clean != file:
|
||||
os.rename(file, file_clean)
|
||||
|
||||
|
||||
def GenerateHtml(lcov_path, dash_root):
|
||||
"""Runs genhtml to convert lcov data to human readable HTML.
|
||||
|
||||
This script expects the LCOV file name to be in the format:
|
||||
chrome_<platform>_<revision#>.lcov.
|
||||
This method parses the file name and then sets up the correct folder
|
||||
hierarchy for the coverage data and then runs genhtml to get the actual HTML
|
||||
formatted coverage data.
|
||||
|
||||
Args:
|
||||
lcov_path: Path of the lcov data file.
|
||||
dash_root: Root location of the dashboard.
|
||||
|
||||
Returns:
|
||||
Code coverage percentage on sucess.
|
||||
None on failure.
|
||||
"""
|
||||
# Parse the LCOV file name.
|
||||
filename = os.path.basename(lcov_path).split('.')[0]
|
||||
buffer = filename.split('_')
|
||||
dash_root = dash_root.rstrip('/') # Remove trailing '/'
|
||||
|
||||
# Set up correct folder heirarchy in the dashboard root
|
||||
# TODO(niranjan): Check the formatting using a regexp
|
||||
if len(buffer) >= 3: # Check if filename has right formatting
|
||||
platform = buffer[len(buffer) - 2]
|
||||
revision = buffer[len(buffer) - 1]
|
||||
if os.path.exists(os.path.join(dash_root, platform)) == False:
|
||||
os.mkdir(os.path.join(dash_root, platform))
|
||||
output_dir = os.join.path(dash_root, platform, revision)
|
||||
os.mkdir(output_dir)
|
||||
else:
|
||||
# TODO(niranjan): Add failure logging here.
|
||||
return None # File not formatted correctly
|
||||
|
||||
# Run genhtml
|
||||
os.system('/usr/bin/genhtml -o %s %s' % (output_dir, lcov_path))
|
||||
# TODO(niranjan): Check the exit status of the genhtml command.
|
||||
# TODO(niranjan): Parse the stdout and return coverage percentage.
|
||||
CleanPathNames(output_dir)
|
||||
return 'dummy' # TODO(niranjan): Return actual percentage.
|
||||
|
||||
|
||||
def CleanWin32Lcov(lcov_path, src_root):
|
||||
"""Cleanup the lcov data generated on Windows.
|
||||
|
||||
This method fixes up the paths inside the lcov file from the Win32 specific
|
||||
paths to the actual paths of the mounted CIFS share. The lcov files generated
|
||||
on Windows have the following format:
|
||||
|
||||
SF:c:\chrome_src\src\skia\sgl\skscan_antihair.cpp
|
||||
DA:97,0
|
||||
DA:106,0
|
||||
DA:107,0
|
||||
DA:109,0
|
||||
...
|
||||
end_of_record
|
||||
|
||||
This method changes the source-file (SF) lines to a format compatible with
|
||||
genhtml on Linux by fixing paths. This method also removes references to
|
||||
certain dynamically generated files to be excluded from the code ceverage.
|
||||
|
||||
Args:
|
||||
lcov_path: Path of the Win32 lcov file to be cleaned.
|
||||
src_root: Location of the source and symbols dir.
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
strip_flag = False
|
||||
lcov = open(lcov_path, 'r')
|
||||
(tmpfile, tmpfile_name) = tempfile.mkstemp()
|
||||
src_root = src_root.rstrip('/') # Remove trailing '/'
|
||||
for line in lcov:
|
||||
if line.startswith('SF'):
|
||||
# We want to exclude certain auto-generated files otherwise genhtml will
|
||||
# fail to convert lcov to HTML.
|
||||
for exp in win32_srcs_exclude:
|
||||
if line.rfind(exp) != -1:
|
||||
strip_flag = True # Indicates that we want to remove this section
|
||||
|
||||
# Now we normalize the paths
|
||||
# e.g. Change SF:c:\foo\src\... to SF:/chrome_src/...
|
||||
parse_buffer = line.split(':')
|
||||
buffer = '%s:%s%s' % (parse_buffer[0],
|
||||
src_root,
|
||||
parse_buffer[2])
|
||||
buffer = buffer.replace('\\', '/')
|
||||
line = buffer
|
||||
|
||||
# Write to the temp file if the section to write is valid
|
||||
if strip_flag == False:
|
||||
tmpfile.write('%s' % (line))
|
||||
|
||||
# Reset the strip flag
|
||||
if line.endswith('end_of_record'):
|
||||
strip_flag = False
|
||||
|
||||
# Close the files and replace the lcov file by the 'clean' tmpfile
|
||||
tmpfile.close()
|
||||
lcov.close()
|
||||
shutil.move(tmpfile_name, lcov_path)
|
||||
|
||||
|
||||
def main():
|
||||
if sys.platform[:5] != 'linux': # Run this only on Linux
|
||||
print 'This script is supported only on Linux'
|
||||
os.exit(1)
|
||||
|
||||
# Command line parsing
|
||||
parser = optparse.OptionParser()
|
||||
parser.add_option('-p',
|
||||
'--platform',
|
||||
dest='platform',
|
||||
default=None,
|
||||
help='Platform that the locv file was generated on. Must be
|
||||
one of {win32, linux2, macosx}')
|
||||
parser.add_option('-s',
|
||||
'--source',
|
||||
dest='src_dir',
|
||||
default=None,
|
||||
help='Path to the source code and symbols')
|
||||
parser.add_option('-d',
|
||||
'--dash_root',
|
||||
dest='dash_root',
|
||||
default=None,
|
||||
help='Root directory for the dashboard')
|
||||
parser.add_option('-l',
|
||||
'--lcov',
|
||||
dest='lcov_path',
|
||||
default=None,
|
||||
help='Location of the LCOV file to process')
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if options.platform == None:
|
||||
parser.error('Platform not specified')
|
||||
if options.lcov_path == None:
|
||||
parser.error('lcov file path not specified')
|
||||
if options.src_dir == None:
|
||||
parser.error('Source directory not specified')
|
||||
if options.dash_root == None:
|
||||
parser.error('Dashboard root not specified')
|
||||
if options.platform == 'win32':
|
||||
CleanWin32Lcov(options.lcov_path, options.src_dir)
|
||||
percent = GenerateHtml(options.lcov_path, options.dash_root)
|
||||
if percent == None:
|
||||
# TODO(niranjan): Add logging.
|
||||
print 'Failed to generate code coverage'
|
||||
os.exit(1)
|
||||
else:
|
||||
# TODO(niranjan): Do something with the code coverage numbers
|
||||
pass
|
||||
else:
|
||||
print 'Unsupported platform'
|
||||
os.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
#!/usr/bin/python2.4
|
||||
#
|
||||
# Copyright 2008, Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
"""Script to clean the lcov files and convert it to HTML
|
||||
|
||||
TODO(niranjan): Add usage information here
|
||||
"""
|
||||
|
||||
|
||||
import optparse
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
|
||||
# These are source files that were generated during compile time. We want to
|
||||
# remove references to these files from the lcov file otherwise genhtml will
|
||||
# throw an error.
|
||||
win32_srcs_exclude = ['parse.y',
|
||||
'xpathgrammar.cpp',
|
||||
'cssgrammar.cpp']
|
||||
|
||||
|
||||
def CleanPathNames(dir):
|
||||
"""Clean the pathnames of the HTML generated by genhtml.
|
||||
|
||||
This method is required only for code coverage on Win32. Due to a known issue
|
||||
with reading from CIFS shares mounted on Linux, genhtml appends a ^M to every
|
||||
file name it reads from the Windows share, causing corrupt filenames in
|
||||
genhtml's output folder.
|
||||
|
||||
Args:
|
||||
dir: Output folder of the genhtml output.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
# Stip off the ^M characters that get appended to the file name
|
||||
for file in os.walk(dir):
|
||||
file_clean = file.replace('\r', '')
|
||||
if file_clean != file:
|
||||
os.rename(file, file_clean)
|
||||
|
||||
|
||||
def GenerateHtml(lcov_path, dash_root):
|
||||
"""Runs genhtml to convert lcov data to human readable HTML.
|
||||
|
||||
This script expects the LCOV file name to be in the format:
|
||||
chrome_<platform>_<revision#>.lcov.
|
||||
This method parses the file name and then sets up the correct folder
|
||||
hierarchy for the coverage data and then runs genhtml to get the actual HTML
|
||||
formatted coverage data.
|
||||
|
||||
Args:
|
||||
lcov_path: Path of the lcov data file.
|
||||
dash_root: Root location of the dashboard.
|
||||
|
||||
Returns:
|
||||
Code coverage percentage on sucess.
|
||||
None on failure.
|
||||
"""
|
||||
# Parse the LCOV file name.
|
||||
filename = os.path.basename(lcov_path).split('.')[0]
|
||||
buffer = filename.split('_')
|
||||
dash_root = dash_root.rstrip('/') # Remove trailing '/'
|
||||
|
||||
# Set up correct folder heirarchy in the dashboard root
|
||||
# TODO(niranjan): Check the formatting using a regexp
|
||||
if len(buffer) >= 3: # Check if filename has right formatting
|
||||
platform = buffer[len(buffer) - 2]
|
||||
revision = buffer[len(buffer) - 1]
|
||||
if os.path.exists(os.path.join(dash_root, platform)) == False:
|
||||
os.mkdir(os.path.join(dash_root, platform))
|
||||
output_dir = os.join.path(dash_root, platform, revision)
|
||||
os.mkdir(output_dir)
|
||||
else:
|
||||
# TODO(niranjan): Add failure logging here.
|
||||
return None # File not formatted correctly
|
||||
|
||||
# Run genhtml
|
||||
os.system('/usr/bin/genhtml -o %s %s' % (output_dir, lcov_path))
|
||||
# TODO(niranjan): Check the exit status of the genhtml command.
|
||||
# TODO(niranjan): Parse the stdout and return coverage percentage.
|
||||
CleanPathNames(output_dir)
|
||||
return 'dummy' # TODO(niranjan): Return actual percentage.
|
||||
|
||||
|
||||
def CleanWin32Lcov(lcov_path, src_root):
|
||||
"""Cleanup the lcov data generated on Windows.
|
||||
|
||||
This method fixes up the paths inside the lcov file from the Win32 specific
|
||||
paths to the actual paths of the mounted CIFS share. The lcov files generated
|
||||
on Windows have the following format:
|
||||
|
||||
SF:c:\chrome_src\src\skia\sgl\skscan_antihair.cpp
|
||||
DA:97,0
|
||||
DA:106,0
|
||||
DA:107,0
|
||||
DA:109,0
|
||||
...
|
||||
end_of_record
|
||||
|
||||
This method changes the source-file (SF) lines to a format compatible with
|
||||
genhtml on Linux by fixing paths. This method also removes references to
|
||||
certain dynamically generated files to be excluded from the code ceverage.
|
||||
|
||||
Args:
|
||||
lcov_path: Path of the Win32 lcov file to be cleaned.
|
||||
src_root: Location of the source and symbols dir.
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
strip_flag = False
|
||||
lcov = open(lcov_path, 'r')
|
||||
(tmpfile, tmpfile_name) = tempfile.mkstemp()
|
||||
src_root = src_root.rstrip('/') # Remove trailing '/'
|
||||
for line in lcov:
|
||||
if line.startswith('SF'):
|
||||
# We want to exclude certain auto-generated files otherwise genhtml will
|
||||
# fail to convert lcov to HTML.
|
||||
for exp in win32_srcs_exclude:
|
||||
if line.rfind(exp) != -1:
|
||||
strip_flag = True # Indicates that we want to remove this section
|
||||
|
||||
# Now we normalize the paths
|
||||
# e.g. Change SF:c:\foo\src\... to SF:/chrome_src/...
|
||||
parse_buffer = line.split(':')
|
||||
buffer = '%s:%s%s' % (parse_buffer[0],
|
||||
src_root,
|
||||
parse_buffer[2])
|
||||
buffer = buffer.replace('\\', '/')
|
||||
line = buffer
|
||||
|
||||
# Write to the temp file if the section to write is valid
|
||||
if strip_flag == False:
|
||||
tmpfile.write('%s' % (line))
|
||||
|
||||
# Reset the strip flag
|
||||
if line.endswith('end_of_record'):
|
||||
strip_flag = False
|
||||
|
||||
# Close the files and replace the lcov file by the 'clean' tmpfile
|
||||
tmpfile.close()
|
||||
lcov.close()
|
||||
shutil.move(tmpfile_name, lcov_path)
|
||||
|
||||
|
||||
def main():
|
||||
if sys.platform[:5] != 'linux': # Run this only on Linux
|
||||
print 'This script is supported only on Linux'
|
||||
os.exit(1)
|
||||
|
||||
# Command line parsing
|
||||
parser = optparse.OptionParser()
|
||||
parser.add_option('-p',
|
||||
'--platform',
|
||||
dest='platform',
|
||||
default=None,
|
||||
help='Platform that the locv file was generated on. Must be
|
||||
one of {win32, linux2, macosx}')
|
||||
parser.add_option('-s',
|
||||
'--source',
|
||||
dest='src_dir',
|
||||
default=None,
|
||||
help='Path to the source code and symbols')
|
||||
parser.add_option('-d',
|
||||
'--dash_root',
|
||||
dest='dash_root',
|
||||
default=None,
|
||||
help='Root directory for the dashboard')
|
||||
parser.add_option('-l',
|
||||
'--lcov',
|
||||
dest='lcov_path',
|
||||
default=None,
|
||||
help='Location of the LCOV file to process')
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if options.platform == None:
|
||||
parser.error('Platform not specified')
|
||||
if options.lcov_path == None:
|
||||
parser.error('lcov file path not specified')
|
||||
if options.src_dir == None:
|
||||
parser.error('Source directory not specified')
|
||||
if options.dash_root == None:
|
||||
parser.error('Dashboard root not specified')
|
||||
if options.platform == 'win32':
|
||||
CleanWin32Lcov(options.lcov_path, options.src_dir)
|
||||
percent = GenerateHtml(options.lcov_path, options.dash_root)
|
||||
if percent == None:
|
||||
# TODO(niranjan): Add logging.
|
||||
print 'Failed to generate code coverage'
|
||||
os.exit(1)
|
||||
else:
|
||||
# TODO(niranjan): Do something with the code coverage numbers
|
||||
pass
|
||||
else:
|
||||
print 'Unsupported platform'
|
||||
os.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
@ -1,376 +1,376 @@
|
||||
// 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 "call_stack.h"
|
||||
#include <shlwapi.h>
|
||||
#include <tlhelp32.h>
|
||||
|
||||
#include "memory_hook.h"
|
||||
#include "base/string_util.h"
|
||||
|
||||
// Typedefs for explicit dynamic linking with functions exported from
|
||||
// dbghelp.dll.
|
||||
typedef BOOL (__stdcall *t_StackWalk64)(DWORD, HANDLE, HANDLE,
|
||||
LPSTACKFRAME64, PVOID,
|
||||
PREAD_PROCESS_MEMORY_ROUTINE64,
|
||||
PFUNCTION_TABLE_ACCESS_ROUTINE64,
|
||||
PGET_MODULE_BASE_ROUTINE64,
|
||||
PTRANSLATE_ADDRESS_ROUTINE64);
|
||||
typedef PVOID (__stdcall *t_SymFunctionTableAccess64)(HANDLE, DWORD64);
|
||||
typedef DWORD64 (__stdcall *t_SymGetModuleBase64)(HANDLE, DWORD64);
|
||||
typedef BOOL (__stdcall *t_SymCleanup)(HANDLE);
|
||||
typedef BOOL (__stdcall *t_SymGetSymFromAddr64)(HANDLE, DWORD64,
|
||||
PDWORD64, PIMAGEHLP_SYMBOL64);
|
||||
typedef BOOL (__stdcall *t_SymGetLineFromAddr64)(HANDLE, DWORD64, PDWORD,
|
||||
PIMAGEHLP_LINE64);
|
||||
typedef BOOL (__stdcall *t_SymInitialize)(HANDLE, PCTSTR, BOOL);
|
||||
typedef DWORD (__stdcall *t_SymGetOptions)(void);
|
||||
typedef DWORD (__stdcall *t_SymSetOptions)(DWORD);
|
||||
typedef BOOL (__stdcall *t_SymGetSearchPath)(HANDLE, PTSTR, DWORD);
|
||||
typedef DWORD64 (__stdcall *t_SymLoadModule64)(HANDLE, HANDLE, PCSTR,
|
||||
PCSTR, DWORD64, DWORD);
|
||||
typedef BOOL (__stdcall *t_SymGetModuleInfo64)(HANDLE, DWORD64,
|
||||
PIMAGEHLP_MODULE64);
|
||||
|
||||
// According to http://msdn2.microsoft.com/en-us/library/ms680650(VS.85).aspx
|
||||
// "All DbgHelp functions, such as this one, are single threaded. Therefore,
|
||||
// calls from more than one thread to this function will likely result in
|
||||
// unexpected behavior or memory corruption. To avoid this, you must
|
||||
// synchromize all concurrent calls from one thread to this function."
|
||||
//
|
||||
// dbghelp_lock_ is used to serialize access across all calls to the DbgHelp
|
||||
// library. This may be overly conservative (serializing them all together),
|
||||
// but does guarantee correctness.
|
||||
static Lock dbghelp_lock_;
|
||||
|
||||
static t_StackWalk64 pStackWalk64 = NULL;
|
||||
static t_SymCleanup pSymCleanup = NULL;
|
||||
static t_SymGetSymFromAddr64 pSymGetSymFromAddr64 = NULL;
|
||||
static t_SymFunctionTableAccess64 pSymFunctionTableAccess64 = NULL;
|
||||
static t_SymGetModuleBase64 pSymGetModuleBase64 = NULL;
|
||||
static t_SymGetLineFromAddr64 pSymGetLineFromAddr64 = NULL;
|
||||
static t_SymInitialize pSymInitialize = NULL;
|
||||
static t_SymGetOptions pSymGetOptions = NULL;
|
||||
static t_SymSetOptions pSymSetOptions = NULL;
|
||||
static t_SymGetModuleInfo64 pSymGetModuleInfo64 = NULL;
|
||||
static t_SymGetSearchPath pSymGetSearchPath = NULL;
|
||||
static t_SymLoadModule64 pSymLoadModule64 = NULL;
|
||||
|
||||
#define LOADPROC(module, name) do { \
|
||||
p##name = reinterpret_cast<t_##name>(GetProcAddress(module, #name)); \
|
||||
if (p##name == NULL) return false; \
|
||||
} while (0)
|
||||
|
||||
// Dynamically load the DbgHelp library and supporting routines that we
|
||||
// will use.
|
||||
static bool LoadDbgHelp() {
|
||||
static bool loaded = false;
|
||||
if (!loaded) {
|
||||
AutoLock Lock(dbghelp_lock_);
|
||||
|
||||
// Re-check if we've loaded successfully now that we have the lock.
|
||||
if (loaded)
|
||||
return true;
|
||||
|
||||
// Load dbghelp.dll, and obtain pointers to the exported functions that we
|
||||
// will be using.
|
||||
HMODULE dbghelp_module = LoadLibrary(L"dbghelp.dll");
|
||||
if (dbghelp_module) {
|
||||
LOADPROC(dbghelp_module, StackWalk64);
|
||||
LOADPROC(dbghelp_module, SymFunctionTableAccess64);
|
||||
LOADPROC(dbghelp_module, SymGetModuleBase64);
|
||||
LOADPROC(dbghelp_module, SymCleanup);
|
||||
LOADPROC(dbghelp_module, SymGetSymFromAddr64);
|
||||
LOADPROC(dbghelp_module, SymGetLineFromAddr64);
|
||||
LOADPROC(dbghelp_module, SymInitialize);
|
||||
LOADPROC(dbghelp_module, SymGetOptions);
|
||||
LOADPROC(dbghelp_module, SymSetOptions);
|
||||
LOADPROC(dbghelp_module, SymGetModuleInfo64);
|
||||
LOADPROC(dbghelp_module, SymGetSearchPath);
|
||||
LOADPROC(dbghelp_module, SymLoadModule64);
|
||||
loaded = true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return loaded;
|
||||
}
|
||||
|
||||
// Load the symbols for generating stack traces.
|
||||
static bool LoadSymbols(HANDLE process_handle) {
|
||||
static bool symbols_loaded = false;
|
||||
if (symbols_loaded) return true;
|
||||
|
||||
BOOL ok;
|
||||
|
||||
// Initialize the symbol engine.
|
||||
ok = pSymInitialize(process_handle, /* hProcess */
|
||||
NULL, /* UserSearchPath */
|
||||
FALSE); /* fInvadeProcess */
|
||||
if (!ok) return false;
|
||||
|
||||
DWORD options = pSymGetOptions();
|
||||
options |= SYMOPT_LOAD_LINES;
|
||||
options |= SYMOPT_FAIL_CRITICAL_ERRORS;
|
||||
options |= SYMOPT_UNDNAME;
|
||||
options = pSymSetOptions(options);
|
||||
|
||||
const DWORD kMaxSearchPath = 1024;
|
||||
TCHAR buf[kMaxSearchPath] = {0};
|
||||
ok = pSymGetSearchPath(process_handle, buf, kMaxSearchPath);
|
||||
if (!ok)
|
||||
return false;
|
||||
|
||||
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,
|
||||
GetCurrentProcessId());
|
||||
if (snapshot == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
MODULEENTRY32W module;
|
||||
module.dwSize = sizeof(module); // Set the size of the structure.
|
||||
BOOL cont = Module32FirstW(snapshot, &module);
|
||||
while (cont) {
|
||||
DWORD64 base;
|
||||
// NOTE the SymLoadModule64 function has the peculiarity of accepting a
|
||||
// both unicode and ASCII strings even though the parameter is PSTR.
|
||||
base = pSymLoadModule64(process_handle,
|
||||
0,
|
||||
reinterpret_cast<PSTR>(module.szExePath),
|
||||
reinterpret_cast<PSTR>(module.szModule),
|
||||
reinterpret_cast<DWORD64>(module.modBaseAddr),
|
||||
module.modBaseSize);
|
||||
if (base == 0) {
|
||||
int err = GetLastError();
|
||||
if (err != ERROR_MOD_NOT_FOUND && err != ERROR_INVALID_HANDLE)
|
||||
return false;
|
||||
}
|
||||
cont = Module32NextW(snapshot, &module);
|
||||
}
|
||||
CloseHandle(snapshot);
|
||||
|
||||
symbols_loaded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
CallStack::SymbolCache* CallStack::symbol_cache_;
|
||||
|
||||
bool CallStack::Initialize() {
|
||||
// We need to delay load the symbol cache until after
|
||||
// the MemoryHook heap is alive.
|
||||
symbol_cache_ = new SymbolCache();
|
||||
return LoadDbgHelp();
|
||||
}
|
||||
|
||||
CallStack::CallStack() {
|
||||
static LONG callstack_id = 0;
|
||||
frame_count_ = 0;
|
||||
hash_ = 0;
|
||||
id_ = InterlockedIncrement(&callstack_id);
|
||||
|
||||
LoadDbgHelp();
|
||||
CHECK(GetStackTrace());
|
||||
}
|
||||
|
||||
bool CallStack::IsEqual(const CallStack &target) {
|
||||
if (frame_count_ != target.frame_count_)
|
||||
return false; // They can't be equal if the sizes are different.
|
||||
|
||||
// Walk the frames array until we
|
||||
// either find a mismatch, or until we reach the end of the call stacks.
|
||||
for (int index = 0; index < frame_count_; index++) {
|
||||
if (frames_[index] != target.frames_[index])
|
||||
return false; // Found a mismatch. They are not equal.
|
||||
}
|
||||
|
||||
// Reached the end of the call stacks. They are equal.
|
||||
return true;
|
||||
}
|
||||
|
||||
void CallStack::AddFrame(DWORD_PTR pc) {
|
||||
DCHECK(frame_count_ < kMaxTraceFrames);
|
||||
frames_[frame_count_++] = pc;
|
||||
|
||||
// Create a unique id for this CallStack.
|
||||
pc = pc + (frame_count_ * 13); // Alter the PC based on position in stack.
|
||||
hash_ = ~hash_ + (pc << 15);
|
||||
hash_ = hash_ ^ (pc >> 12);
|
||||
hash_ = hash_ + (pc << 2);
|
||||
hash_ = hash_ ^ (pc >> 4);
|
||||
hash_ = hash_ * 2057;
|
||||
hash_ = hash_ ^ (pc >> 16);
|
||||
}
|
||||
|
||||
bool CallStack::GetStackTrace() {
|
||||
// Initialize the context record.
|
||||
CONTEXT context;
|
||||
memset(&context, 0, sizeof(context));
|
||||
context.ContextFlags = CONTEXT_FULL;
|
||||
__asm call x
|
||||
__asm x: pop eax
|
||||
__asm mov context.Eip, eax
|
||||
__asm mov context.Ebp, ebp
|
||||
__asm mov context.Esp, esp
|
||||
|
||||
STACKFRAME64 frame;
|
||||
memset(&frame, 0, sizeof(frame));
|
||||
|
||||
#ifdef _M_IX86
|
||||
DWORD image_type = IMAGE_FILE_MACHINE_I386;
|
||||
frame.AddrPC.Offset = context.Eip;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.Ebp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context.Esp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
#elif
|
||||
NOT IMPLEMENTED!
|
||||
#endif
|
||||
|
||||
HANDLE current_process = GetCurrentProcess();
|
||||
HANDLE current_thread = GetCurrentThread();
|
||||
|
||||
// Walk the stack.
|
||||
unsigned int count = 0;
|
||||
{
|
||||
AutoLock lock(dbghelp_lock_);
|
||||
|
||||
while (count < kMaxTraceFrames) {
|
||||
count++;
|
||||
if (!pStackWalk64(image_type,
|
||||
current_process,
|
||||
current_thread,
|
||||
&frame,
|
||||
&context,
|
||||
0,
|
||||
pSymFunctionTableAccess64,
|
||||
pSymGetModuleBase64,
|
||||
NULL))
|
||||
break; // Couldn't trace back through any more frames.
|
||||
|
||||
if (frame.AddrFrame.Offset == 0)
|
||||
continue; // End of stack.
|
||||
|
||||
// Push this frame's program counter onto the provided CallStack.
|
||||
AddFrame((DWORD_PTR)frame.AddrPC.Offset);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CallStack::ToString(std::string* output) {
|
||||
static const int kStackWalkMaxNameLen = MAX_SYM_NAME;
|
||||
HANDLE current_process = GetCurrentProcess();
|
||||
|
||||
if (!LoadSymbols(current_process)) {
|
||||
*output = "Error";
|
||||
return;
|
||||
}
|
||||
|
||||
AutoLock lock(dbghelp_lock_);
|
||||
|
||||
// Iterate through each frame in the call stack.
|
||||
for (int32 index = 0; index < frame_count_; index++) {
|
||||
std::string line;
|
||||
|
||||
DWORD_PTR intruction_pointer = frame(index);
|
||||
|
||||
SymbolCache::iterator it;
|
||||
it = symbol_cache_->find( intruction_pointer );
|
||||
if (it != symbol_cache_->end()) {
|
||||
line = it->second;
|
||||
} else {
|
||||
// Try to locate a symbol for this frame.
|
||||
DWORD64 symbol_displacement = 0;
|
||||
ULONG64 buffer[(sizeof(IMAGEHLP_SYMBOL64) +
|
||||
sizeof(TCHAR)*kStackWalkMaxNameLen +
|
||||
sizeof(ULONG64) - 1) / sizeof(ULONG64)];
|
||||
IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(buffer);
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
symbol->MaxNameLength = kStackWalkMaxNameLen;
|
||||
BOOL ok = pSymGetSymFromAddr64(current_process, // hProcess
|
||||
intruction_pointer, // Address
|
||||
&symbol_displacement, // Displacement
|
||||
symbol); // Symbol
|
||||
if (ok) {
|
||||
// Try to locate more source information for the symbol.
|
||||
IMAGEHLP_LINE64 Line;
|
||||
memset(&Line, 0, sizeof(Line));
|
||||
Line.SizeOfStruct = sizeof(Line);
|
||||
DWORD line_displacement;
|
||||
ok = pSymGetLineFromAddr64(current_process,
|
||||
intruction_pointer,
|
||||
&line_displacement,
|
||||
&Line);
|
||||
if (ok) {
|
||||
// Skip junk symbols from our internal stuff.
|
||||
if (strstr(symbol->Name, "CallStack::") ||
|
||||
strstr(symbol->Name, "MemoryWatcher::") ||
|
||||
strstr(symbol->Name, "Perftools_") ||
|
||||
strstr(symbol->Name, "MemoryHook::") ) {
|
||||
// Just record a blank string.
|
||||
(*symbol_cache_)[intruction_pointer] = std::string("");
|
||||
continue;
|
||||
}
|
||||
|
||||
line += " ";
|
||||
line += static_cast<char*>(Line.FileName);
|
||||
line += " (";
|
||||
line += IntToString(Line.LineNumber);
|
||||
line += "): ";
|
||||
line += symbol->Name;
|
||||
line += "\n";
|
||||
} else {
|
||||
line += " unknown (0):";
|
||||
line += symbol->Name;
|
||||
line += "\n";
|
||||
}
|
||||
} else {
|
||||
// OK - couldn't get any info. Try for the module.
|
||||
IMAGEHLP_MODULE64 module_info;
|
||||
module_info.SizeOfStruct = sizeof(module_info);
|
||||
if (pSymGetModuleInfo64(current_process, intruction_pointer,
|
||||
&module_info)) {
|
||||
line += " (";
|
||||
line += static_cast<char*>(module_info.ModuleName);
|
||||
line += ")\n";
|
||||
} else {
|
||||
line += " ???\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(*symbol_cache_)[intruction_pointer] = line;
|
||||
*output += line;
|
||||
}
|
||||
*output += "==================\n";
|
||||
}
|
||||
|
||||
|
||||
Lock AllocationStack::freelist_lock_;
|
||||
AllocationStack* AllocationStack::freelist_ = NULL;
|
||||
|
||||
void* AllocationStack::operator new(size_t size) {
|
||||
DCHECK(size == sizeof(AllocationStack));
|
||||
{
|
||||
AutoLock lock(freelist_lock_);
|
||||
if (freelist_ != NULL) {
|
||||
AllocationStack* stack = freelist_;
|
||||
freelist_ = freelist_->next_;
|
||||
stack->next_ = NULL;
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
return MemoryHook::Alloc(size);
|
||||
}
|
||||
|
||||
void AllocationStack::operator delete(void* ptr) {
|
||||
AllocationStack *stack = reinterpret_cast<AllocationStack*>(ptr);
|
||||
AutoLock lock(freelist_lock_);
|
||||
DCHECK(stack->next_ == NULL);
|
||||
stack->next_ = freelist_;
|
||||
freelist_ = stack;
|
||||
}
|
||||
|
||||
// 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 "call_stack.h"
|
||||
#include <shlwapi.h>
|
||||
#include <tlhelp32.h>
|
||||
|
||||
#include "memory_hook.h"
|
||||
#include "base/string_util.h"
|
||||
|
||||
// Typedefs for explicit dynamic linking with functions exported from
|
||||
// dbghelp.dll.
|
||||
typedef BOOL (__stdcall *t_StackWalk64)(DWORD, HANDLE, HANDLE,
|
||||
LPSTACKFRAME64, PVOID,
|
||||
PREAD_PROCESS_MEMORY_ROUTINE64,
|
||||
PFUNCTION_TABLE_ACCESS_ROUTINE64,
|
||||
PGET_MODULE_BASE_ROUTINE64,
|
||||
PTRANSLATE_ADDRESS_ROUTINE64);
|
||||
typedef PVOID (__stdcall *t_SymFunctionTableAccess64)(HANDLE, DWORD64);
|
||||
typedef DWORD64 (__stdcall *t_SymGetModuleBase64)(HANDLE, DWORD64);
|
||||
typedef BOOL (__stdcall *t_SymCleanup)(HANDLE);
|
||||
typedef BOOL (__stdcall *t_SymGetSymFromAddr64)(HANDLE, DWORD64,
|
||||
PDWORD64, PIMAGEHLP_SYMBOL64);
|
||||
typedef BOOL (__stdcall *t_SymGetLineFromAddr64)(HANDLE, DWORD64, PDWORD,
|
||||
PIMAGEHLP_LINE64);
|
||||
typedef BOOL (__stdcall *t_SymInitialize)(HANDLE, PCTSTR, BOOL);
|
||||
typedef DWORD (__stdcall *t_SymGetOptions)(void);
|
||||
typedef DWORD (__stdcall *t_SymSetOptions)(DWORD);
|
||||
typedef BOOL (__stdcall *t_SymGetSearchPath)(HANDLE, PTSTR, DWORD);
|
||||
typedef DWORD64 (__stdcall *t_SymLoadModule64)(HANDLE, HANDLE, PCSTR,
|
||||
PCSTR, DWORD64, DWORD);
|
||||
typedef BOOL (__stdcall *t_SymGetModuleInfo64)(HANDLE, DWORD64,
|
||||
PIMAGEHLP_MODULE64);
|
||||
|
||||
// According to http://msdn2.microsoft.com/en-us/library/ms680650(VS.85).aspx
|
||||
// "All DbgHelp functions, such as this one, are single threaded. Therefore,
|
||||
// calls from more than one thread to this function will likely result in
|
||||
// unexpected behavior or memory corruption. To avoid this, you must
|
||||
// synchromize all concurrent calls from one thread to this function."
|
||||
//
|
||||
// dbghelp_lock_ is used to serialize access across all calls to the DbgHelp
|
||||
// library. This may be overly conservative (serializing them all together),
|
||||
// but does guarantee correctness.
|
||||
static Lock dbghelp_lock_;
|
||||
|
||||
static t_StackWalk64 pStackWalk64 = NULL;
|
||||
static t_SymCleanup pSymCleanup = NULL;
|
||||
static t_SymGetSymFromAddr64 pSymGetSymFromAddr64 = NULL;
|
||||
static t_SymFunctionTableAccess64 pSymFunctionTableAccess64 = NULL;
|
||||
static t_SymGetModuleBase64 pSymGetModuleBase64 = NULL;
|
||||
static t_SymGetLineFromAddr64 pSymGetLineFromAddr64 = NULL;
|
||||
static t_SymInitialize pSymInitialize = NULL;
|
||||
static t_SymGetOptions pSymGetOptions = NULL;
|
||||
static t_SymSetOptions pSymSetOptions = NULL;
|
||||
static t_SymGetModuleInfo64 pSymGetModuleInfo64 = NULL;
|
||||
static t_SymGetSearchPath pSymGetSearchPath = NULL;
|
||||
static t_SymLoadModule64 pSymLoadModule64 = NULL;
|
||||
|
||||
#define LOADPROC(module, name) do { \
|
||||
p##name = reinterpret_cast<t_##name>(GetProcAddress(module, #name)); \
|
||||
if (p##name == NULL) return false; \
|
||||
} while (0)
|
||||
|
||||
// Dynamically load the DbgHelp library and supporting routines that we
|
||||
// will use.
|
||||
static bool LoadDbgHelp() {
|
||||
static bool loaded = false;
|
||||
if (!loaded) {
|
||||
AutoLock Lock(dbghelp_lock_);
|
||||
|
||||
// Re-check if we've loaded successfully now that we have the lock.
|
||||
if (loaded)
|
||||
return true;
|
||||
|
||||
// Load dbghelp.dll, and obtain pointers to the exported functions that we
|
||||
// will be using.
|
||||
HMODULE dbghelp_module = LoadLibrary(L"dbghelp.dll");
|
||||
if (dbghelp_module) {
|
||||
LOADPROC(dbghelp_module, StackWalk64);
|
||||
LOADPROC(dbghelp_module, SymFunctionTableAccess64);
|
||||
LOADPROC(dbghelp_module, SymGetModuleBase64);
|
||||
LOADPROC(dbghelp_module, SymCleanup);
|
||||
LOADPROC(dbghelp_module, SymGetSymFromAddr64);
|
||||
LOADPROC(dbghelp_module, SymGetLineFromAddr64);
|
||||
LOADPROC(dbghelp_module, SymInitialize);
|
||||
LOADPROC(dbghelp_module, SymGetOptions);
|
||||
LOADPROC(dbghelp_module, SymSetOptions);
|
||||
LOADPROC(dbghelp_module, SymGetModuleInfo64);
|
||||
LOADPROC(dbghelp_module, SymGetSearchPath);
|
||||
LOADPROC(dbghelp_module, SymLoadModule64);
|
||||
loaded = true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return loaded;
|
||||
}
|
||||
|
||||
// Load the symbols for generating stack traces.
|
||||
static bool LoadSymbols(HANDLE process_handle) {
|
||||
static bool symbols_loaded = false;
|
||||
if (symbols_loaded) return true;
|
||||
|
||||
BOOL ok;
|
||||
|
||||
// Initialize the symbol engine.
|
||||
ok = pSymInitialize(process_handle, /* hProcess */
|
||||
NULL, /* UserSearchPath */
|
||||
FALSE); /* fInvadeProcess */
|
||||
if (!ok) return false;
|
||||
|
||||
DWORD options = pSymGetOptions();
|
||||
options |= SYMOPT_LOAD_LINES;
|
||||
options |= SYMOPT_FAIL_CRITICAL_ERRORS;
|
||||
options |= SYMOPT_UNDNAME;
|
||||
options = pSymSetOptions(options);
|
||||
|
||||
const DWORD kMaxSearchPath = 1024;
|
||||
TCHAR buf[kMaxSearchPath] = {0};
|
||||
ok = pSymGetSearchPath(process_handle, buf, kMaxSearchPath);
|
||||
if (!ok)
|
||||
return false;
|
||||
|
||||
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,
|
||||
GetCurrentProcessId());
|
||||
if (snapshot == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
MODULEENTRY32W module;
|
||||
module.dwSize = sizeof(module); // Set the size of the structure.
|
||||
BOOL cont = Module32FirstW(snapshot, &module);
|
||||
while (cont) {
|
||||
DWORD64 base;
|
||||
// NOTE the SymLoadModule64 function has the peculiarity of accepting a
|
||||
// both unicode and ASCII strings even though the parameter is PSTR.
|
||||
base = pSymLoadModule64(process_handle,
|
||||
0,
|
||||
reinterpret_cast<PSTR>(module.szExePath),
|
||||
reinterpret_cast<PSTR>(module.szModule),
|
||||
reinterpret_cast<DWORD64>(module.modBaseAddr),
|
||||
module.modBaseSize);
|
||||
if (base == 0) {
|
||||
int err = GetLastError();
|
||||
if (err != ERROR_MOD_NOT_FOUND && err != ERROR_INVALID_HANDLE)
|
||||
return false;
|
||||
}
|
||||
cont = Module32NextW(snapshot, &module);
|
||||
}
|
||||
CloseHandle(snapshot);
|
||||
|
||||
symbols_loaded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
CallStack::SymbolCache* CallStack::symbol_cache_;
|
||||
|
||||
bool CallStack::Initialize() {
|
||||
// We need to delay load the symbol cache until after
|
||||
// the MemoryHook heap is alive.
|
||||
symbol_cache_ = new SymbolCache();
|
||||
return LoadDbgHelp();
|
||||
}
|
||||
|
||||
CallStack::CallStack() {
|
||||
static LONG callstack_id = 0;
|
||||
frame_count_ = 0;
|
||||
hash_ = 0;
|
||||
id_ = InterlockedIncrement(&callstack_id);
|
||||
|
||||
LoadDbgHelp();
|
||||
CHECK(GetStackTrace());
|
||||
}
|
||||
|
||||
bool CallStack::IsEqual(const CallStack &target) {
|
||||
if (frame_count_ != target.frame_count_)
|
||||
return false; // They can't be equal if the sizes are different.
|
||||
|
||||
// Walk the frames array until we
|
||||
// either find a mismatch, or until we reach the end of the call stacks.
|
||||
for (int index = 0; index < frame_count_; index++) {
|
||||
if (frames_[index] != target.frames_[index])
|
||||
return false; // Found a mismatch. They are not equal.
|
||||
}
|
||||
|
||||
// Reached the end of the call stacks. They are equal.
|
||||
return true;
|
||||
}
|
||||
|
||||
void CallStack::AddFrame(DWORD_PTR pc) {
|
||||
DCHECK(frame_count_ < kMaxTraceFrames);
|
||||
frames_[frame_count_++] = pc;
|
||||
|
||||
// Create a unique id for this CallStack.
|
||||
pc = pc + (frame_count_ * 13); // Alter the PC based on position in stack.
|
||||
hash_ = ~hash_ + (pc << 15);
|
||||
hash_ = hash_ ^ (pc >> 12);
|
||||
hash_ = hash_ + (pc << 2);
|
||||
hash_ = hash_ ^ (pc >> 4);
|
||||
hash_ = hash_ * 2057;
|
||||
hash_ = hash_ ^ (pc >> 16);
|
||||
}
|
||||
|
||||
bool CallStack::GetStackTrace() {
|
||||
// Initialize the context record.
|
||||
CONTEXT context;
|
||||
memset(&context, 0, sizeof(context));
|
||||
context.ContextFlags = CONTEXT_FULL;
|
||||
__asm call x
|
||||
__asm x: pop eax
|
||||
__asm mov context.Eip, eax
|
||||
__asm mov context.Ebp, ebp
|
||||
__asm mov context.Esp, esp
|
||||
|
||||
STACKFRAME64 frame;
|
||||
memset(&frame, 0, sizeof(frame));
|
||||
|
||||
#ifdef _M_IX86
|
||||
DWORD image_type = IMAGE_FILE_MACHINE_I386;
|
||||
frame.AddrPC.Offset = context.Eip;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.Ebp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context.Esp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
#elif
|
||||
NOT IMPLEMENTED!
|
||||
#endif
|
||||
|
||||
HANDLE current_process = GetCurrentProcess();
|
||||
HANDLE current_thread = GetCurrentThread();
|
||||
|
||||
// Walk the stack.
|
||||
unsigned int count = 0;
|
||||
{
|
||||
AutoLock lock(dbghelp_lock_);
|
||||
|
||||
while (count < kMaxTraceFrames) {
|
||||
count++;
|
||||
if (!pStackWalk64(image_type,
|
||||
current_process,
|
||||
current_thread,
|
||||
&frame,
|
||||
&context,
|
||||
0,
|
||||
pSymFunctionTableAccess64,
|
||||
pSymGetModuleBase64,
|
||||
NULL))
|
||||
break; // Couldn't trace back through any more frames.
|
||||
|
||||
if (frame.AddrFrame.Offset == 0)
|
||||
continue; // End of stack.
|
||||
|
||||
// Push this frame's program counter onto the provided CallStack.
|
||||
AddFrame((DWORD_PTR)frame.AddrPC.Offset);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CallStack::ToString(std::string* output) {
|
||||
static const int kStackWalkMaxNameLen = MAX_SYM_NAME;
|
||||
HANDLE current_process = GetCurrentProcess();
|
||||
|
||||
if (!LoadSymbols(current_process)) {
|
||||
*output = "Error";
|
||||
return;
|
||||
}
|
||||
|
||||
AutoLock lock(dbghelp_lock_);
|
||||
|
||||
// Iterate through each frame in the call stack.
|
||||
for (int32 index = 0; index < frame_count_; index++) {
|
||||
std::string line;
|
||||
|
||||
DWORD_PTR intruction_pointer = frame(index);
|
||||
|
||||
SymbolCache::iterator it;
|
||||
it = symbol_cache_->find( intruction_pointer );
|
||||
if (it != symbol_cache_->end()) {
|
||||
line = it->second;
|
||||
} else {
|
||||
// Try to locate a symbol for this frame.
|
||||
DWORD64 symbol_displacement = 0;
|
||||
ULONG64 buffer[(sizeof(IMAGEHLP_SYMBOL64) +
|
||||
sizeof(TCHAR)*kStackWalkMaxNameLen +
|
||||
sizeof(ULONG64) - 1) / sizeof(ULONG64)];
|
||||
IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(buffer);
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
symbol->MaxNameLength = kStackWalkMaxNameLen;
|
||||
BOOL ok = pSymGetSymFromAddr64(current_process, // hProcess
|
||||
intruction_pointer, // Address
|
||||
&symbol_displacement, // Displacement
|
||||
symbol); // Symbol
|
||||
if (ok) {
|
||||
// Try to locate more source information for the symbol.
|
||||
IMAGEHLP_LINE64 Line;
|
||||
memset(&Line, 0, sizeof(Line));
|
||||
Line.SizeOfStruct = sizeof(Line);
|
||||
DWORD line_displacement;
|
||||
ok = pSymGetLineFromAddr64(current_process,
|
||||
intruction_pointer,
|
||||
&line_displacement,
|
||||
&Line);
|
||||
if (ok) {
|
||||
// Skip junk symbols from our internal stuff.
|
||||
if (strstr(symbol->Name, "CallStack::") ||
|
||||
strstr(symbol->Name, "MemoryWatcher::") ||
|
||||
strstr(symbol->Name, "Perftools_") ||
|
||||
strstr(symbol->Name, "MemoryHook::") ) {
|
||||
// Just record a blank string.
|
||||
(*symbol_cache_)[intruction_pointer] = std::string("");
|
||||
continue;
|
||||
}
|
||||
|
||||
line += " ";
|
||||
line += static_cast<char*>(Line.FileName);
|
||||
line += " (";
|
||||
line += IntToString(Line.LineNumber);
|
||||
line += "): ";
|
||||
line += symbol->Name;
|
||||
line += "\n";
|
||||
} else {
|
||||
line += " unknown (0):";
|
||||
line += symbol->Name;
|
||||
line += "\n";
|
||||
}
|
||||
} else {
|
||||
// OK - couldn't get any info. Try for the module.
|
||||
IMAGEHLP_MODULE64 module_info;
|
||||
module_info.SizeOfStruct = sizeof(module_info);
|
||||
if (pSymGetModuleInfo64(current_process, intruction_pointer,
|
||||
&module_info)) {
|
||||
line += " (";
|
||||
line += static_cast<char*>(module_info.ModuleName);
|
||||
line += ")\n";
|
||||
} else {
|
||||
line += " ???\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(*symbol_cache_)[intruction_pointer] = line;
|
||||
*output += line;
|
||||
}
|
||||
*output += "==================\n";
|
||||
}
|
||||
|
||||
|
||||
Lock AllocationStack::freelist_lock_;
|
||||
AllocationStack* AllocationStack::freelist_ = NULL;
|
||||
|
||||
void* AllocationStack::operator new(size_t size) {
|
||||
DCHECK(size == sizeof(AllocationStack));
|
||||
{
|
||||
AutoLock lock(freelist_lock_);
|
||||
if (freelist_ != NULL) {
|
||||
AllocationStack* stack = freelist_;
|
||||
freelist_ = freelist_->next_;
|
||||
stack->next_ = NULL;
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
return MemoryHook::Alloc(size);
|
||||
}
|
||||
|
||||
void AllocationStack::operator delete(void* ptr) {
|
||||
AllocationStack *stack = reinterpret_cast<AllocationStack*>(ptr);
|
||||
AutoLock lock(freelist_lock_);
|
||||
DCHECK(stack->next_ == NULL);
|
||||
stack->next_ = freelist_;
|
||||
freelist_ = stack;
|
||||
}
|
||||
|
||||
|
@ -1,46 +1,46 @@
|
||||
# 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.
|
||||
|
||||
Import('env')
|
||||
|
||||
env = env.Clone(
|
||||
PCRE_DIR = '$WEBKIT_DIR/port/JavaScriptCore/pcre',
|
||||
)
|
||||
|
||||
env.Prepend(
|
||||
CPPPATH = [
|
||||
'$WEBKIT_DIR/port/JavaScriptCore',
|
||||
'$WEBKIT_DIR/port/JavaScriptCore/pcre',
|
||||
'$WEBKIT_DIR/build/JSConfig/WebCore/v8',
|
||||
])
|
||||
|
||||
if env['PLATFORM'] == 'win32':
|
||||
env.Prepend(
|
||||
CCFLAGS = [
|
||||
'/TP',
|
||||
'/wd4127',
|
||||
'/wd4355',
|
||||
'/wd4510',
|
||||
'/wd4512',
|
||||
'/wd4610',
|
||||
'/wd4706',
|
||||
'/wd4800',
|
||||
],
|
||||
)
|
||||
|
||||
dir = env.Dir('$PCRE_DIR')
|
||||
|
||||
dir.addRepository(env.Dir('#/../webkit/pending'))
|
||||
dir.addRepository(env.Dir('#/../third_party/WebKit/JavaScriptCore/pcre'))
|
||||
|
||||
input_files = [
|
||||
'$PCRE_DIR/pcre_compile.cpp',
|
||||
'$PCRE_DIR/pcre_xclass.cpp',
|
||||
'$PCRE_DIR/pcre_ucp_searchfuncs.cpp',
|
||||
'$PCRE_DIR/pcre_tables.cpp',
|
||||
'$PCRE_DIR/pcre_exec.cpp',
|
||||
]
|
||||
|
||||
env.ChromeStaticLibrary('JavaScriptCore_pcre', input_files)
|
||||
|
||||
# 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.
|
||||
|
||||
Import('env')
|
||||
|
||||
env = env.Clone(
|
||||
PCRE_DIR = '$WEBKIT_DIR/port/JavaScriptCore/pcre',
|
||||
)
|
||||
|
||||
env.Prepend(
|
||||
CPPPATH = [
|
||||
'$WEBKIT_DIR/port/JavaScriptCore',
|
||||
'$WEBKIT_DIR/port/JavaScriptCore/pcre',
|
||||
'$WEBKIT_DIR/build/JSConfig/WebCore/v8',
|
||||
])
|
||||
|
||||
if env['PLATFORM'] == 'win32':
|
||||
env.Prepend(
|
||||
CCFLAGS = [
|
||||
'/TP',
|
||||
'/wd4127',
|
||||
'/wd4355',
|
||||
'/wd4510',
|
||||
'/wd4512',
|
||||
'/wd4610',
|
||||
'/wd4706',
|
||||
'/wd4800',
|
||||
],
|
||||
)
|
||||
|
||||
dir = env.Dir('$PCRE_DIR')
|
||||
|
||||
dir.addRepository(env.Dir('#/../webkit/pending'))
|
||||
dir.addRepository(env.Dir('#/../third_party/WebKit/JavaScriptCore/pcre'))
|
||||
|
||||
input_files = [
|
||||
'$PCRE_DIR/pcre_compile.cpp',
|
||||
'$PCRE_DIR/pcre_xclass.cpp',
|
||||
'$PCRE_DIR/pcre_ucp_searchfuncs.cpp',
|
||||
'$PCRE_DIR/pcre_tables.cpp',
|
||||
'$PCRE_DIR/pcre_exec.cpp',
|
||||
]
|
||||
|
||||
env.ChromeStaticLibrary('JavaScriptCore_pcre', input_files)
|
||||
|
||||
|
@ -1,127 +1,127 @@
|
||||
# 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.
|
||||
|
||||
Import('env')
|
||||
|
||||
env = env.Clone()
|
||||
|
||||
if env['PLATFORM'] == 'win32':
|
||||
env.Prepend(
|
||||
CCFLAGS = [
|
||||
'/TP',
|
||||
|
||||
'/wd4244',
|
||||
'/wd4291',
|
||||
'/wd4345',
|
||||
'/wd4521',
|
||||
'/wd4800',
|
||||
],)
|
||||
|
||||
input_files = [
|
||||
'$PORT_DIR/css/RGBColor.cpp',
|
||||
'$PORT_DIR/history/CachedPage.cpp',
|
||||
'$PORT_DIR/platform/TemporaryLinkStubs.cpp',
|
||||
]
|
||||
|
||||
if env['PLATFORM'] == 'win32':
|
||||
# TODO(erg): Temporarily disabling these until the big webkit merge is
|
||||
# complete; we're just out of date here.
|
||||
input_files += [
|
||||
'$PORT_DIR/platform/graphics/AffineTransformSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/ImageSourceSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/NativeImageSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/PathSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/SkiaUtils.cpp',
|
||||
'$PORT_DIR/platform/graphics/svg/SkiaSupport.cpp',
|
||||
'$PORT_DIR/platform/graphics/svg/RenderPathSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/svg/SVGPaintServerGradientSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/svg/SVGPaintServerPatternSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/svg/SVGPaintServerSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/svg/SVGPaintServerSolidSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/svg/SVGResourceClipperSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/svg/SVGResourceFilterSkia.cpp',
|
||||
'$PORT_DIR/platform/image-decoders/bmp/BMPImageDecoder.cpp',
|
||||
'$PORT_DIR/platform/image-decoders/bmp/BMPImageReader.cpp',
|
||||
'$PORT_DIR/platform/image-decoders/gif/GIFImageDecoder.cpp',
|
||||
'$PORT_DIR/platform/image-decoders/gif/GIFImageReader.cpp',
|
||||
'$PORT_DIR/platform/image-decoders/ico/ICOImageDecoder.cpp',
|
||||
'$PORT_DIR/platform/image-decoders/jpeg/JPEGImageDecoder.cpp',
|
||||
'$PORT_DIR/platform/image-decoders/png/PNGImageDecoder.cpp',
|
||||
'$PORT_DIR/platform/image-decoders/xbm/XBMImageDecoder.cpp',
|
||||
]
|
||||
|
||||
if env['PLATFORM'] == 'win32':
|
||||
# These files aren't win32-specific, they're just files that haven't yet been
|
||||
# made portable.
|
||||
input_files = [
|
||||
'$PORT_DIR/bridge/FrameWin.cpp',
|
||||
'$PORT_DIR/bridge/HistoryWin.cpp',
|
||||
'$PORT_DIR/bridge/PageWin.cpp',
|
||||
'$PORT_DIR/bridge/PluginsWin.cpp',
|
||||
'$PORT_DIR/history/BackForwardList.cpp',
|
||||
'$PORT_DIR/loader/IconDatabaseNone.cpp',
|
||||
'$PORT_DIR/loader/IconLoader.cpp',
|
||||
'$PORT_DIR/page/AXObjectCacheWin.cpp',
|
||||
'$PORT_DIR/page/DragControllerWin.cpp',
|
||||
'$PORT_DIR/page/EventHandlerWin.cpp',
|
||||
'$PORT_DIR/platform/BString.cpp',
|
||||
'$PORT_DIR/platform/ClipboardUtilitiesWin.cpp',
|
||||
'$PORT_DIR/platform/ClipboardWin.cpp',
|
||||
'$PORT_DIR/platform/ContextMenuItemWin.cpp',
|
||||
'$PORT_DIR/platform/ContextMenuWin.cpp',
|
||||
'$PORT_DIR/platform/CursorWin.cpp',
|
||||
'$PORT_DIR/platform/DragDataWin.cpp',
|
||||
'$PORT_DIR/platform/DragImageWin.cpp',
|
||||
'$PORT_DIR/platform/EditorWin.cpp',
|
||||
'$PORT_DIR/platform/FileChooserWin.cpp',
|
||||
'$PORT_DIR/platform/FramelessScrollView.cpp',
|
||||
'$PORT_DIR/platform/GKURL.cpp',
|
||||
'$PORT_DIR/platform/KeyEventWin.cpp',
|
||||
'$PORT_DIR/platform/Language.cpp',
|
||||
'$PORT_DIR/platform/LogWin.cpp',
|
||||
'$PORT_DIR/platform/MimeTypeRegistryWin.cpp',
|
||||
'$PORT_DIR/platform/PasteboardWin.cpp',
|
||||
'$PORT_DIR/platform/PlatformMouseEventWin.cpp',
|
||||
'$PORT_DIR/platform/PlatformScrollBarWin.cpp',
|
||||
'$PORT_DIR/platform/PopupMenuWin.cpp',
|
||||
'$PORT_DIR/platform/SSLKeyGeneratorWin.cpp',
|
||||
'$PORT_DIR/platform/ScreenWin.cpp',
|
||||
'$PORT_DIR/platform/ScrollViewWin.cpp',
|
||||
'$PORT_DIR/platform/SearchPopupMenuWin.cpp',
|
||||
'$PORT_DIR/platform/SharedTimerWin.cpp',
|
||||
'$PORT_DIR/platform/SoundWin.cpp',
|
||||
'$PORT_DIR/platform/SystemTimeWin.cpp',
|
||||
'$PORT_DIR/platform/TextBoundariesWin.cpp',
|
||||
'$PORT_DIR/platform/TextBreakIteratorInternalICUWin.cpp',
|
||||
'$PORT_DIR/platform/UniscribeStateTextRun.cpp',
|
||||
'$PORT_DIR/platform/WCDataObject.cpp',
|
||||
'$PORT_DIR/platform/WheelEventWin.cpp',
|
||||
'$PORT_DIR/platform/WidgetWin.cpp',
|
||||
'$PORT_DIR/platform/graphics/FontCacheWin.cpp',
|
||||
'$PORT_DIR/platform/graphics/FontCustomPlatformData.cpp',
|
||||
'$PORT_DIR/platform/graphics/FontPlatformDataWin.cpp',
|
||||
'$PORT_DIR/platform/graphics/FontWin.cpp',
|
||||
'$PORT_DIR/platform/graphics/GlyphPageTreeNodeWin.cpp',
|
||||
'$PORT_DIR/platform/graphics/GraphicsContextSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/IconWin.cpp',
|
||||
'$PORT_DIR/platform/graphics/ImageBufferSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/ImageSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/PlatformContextSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/SimpleFontDataWin.cpp',
|
||||
'$PORT_DIR/platform/graphics/SkGraphicsContext.cpp',
|
||||
'$PORT_DIR/platform/graphics/SkPaintContext.cpp',
|
||||
'$PORT_DIR/platform/graphics/svg/SVGResourceMaskerSkia.cpp',
|
||||
'$PORT_DIR/platform/network/CookieJarWin.cpp',
|
||||
'$PORT_DIR/rendering/RenderThemeWin.cpp',
|
||||
]
|
||||
|
||||
if env['PLATFORM'] == 'win32':
|
||||
# These are extremely win32 specific and will never be ported.
|
||||
input_files = [
|
||||
'$PORT_DIR/platform/graphics/IntPointWin.cpp',
|
||||
'$PORT_DIR/platform/graphics/IntRectWin.cpp',
|
||||
'$PORT_DIR/platform/graphics/IntSizeWin.cpp',
|
||||
]
|
||||
|
||||
env.ChromeStaticLibrary("port", input_files)
|
||||
# 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.
|
||||
|
||||
Import('env')
|
||||
|
||||
env = env.Clone()
|
||||
|
||||
if env['PLATFORM'] == 'win32':
|
||||
env.Prepend(
|
||||
CCFLAGS = [
|
||||
'/TP',
|
||||
|
||||
'/wd4244',
|
||||
'/wd4291',
|
||||
'/wd4345',
|
||||
'/wd4521',
|
||||
'/wd4800',
|
||||
],)
|
||||
|
||||
input_files = [
|
||||
'$PORT_DIR/css/RGBColor.cpp',
|
||||
'$PORT_DIR/history/CachedPage.cpp',
|
||||
'$PORT_DIR/platform/TemporaryLinkStubs.cpp',
|
||||
]
|
||||
|
||||
if env['PLATFORM'] == 'win32':
|
||||
# TODO(erg): Temporarily disabling these until the big webkit merge is
|
||||
# complete; we're just out of date here.
|
||||
input_files += [
|
||||
'$PORT_DIR/platform/graphics/AffineTransformSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/ImageSourceSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/NativeImageSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/PathSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/SkiaUtils.cpp',
|
||||
'$PORT_DIR/platform/graphics/svg/SkiaSupport.cpp',
|
||||
'$PORT_DIR/platform/graphics/svg/RenderPathSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/svg/SVGPaintServerGradientSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/svg/SVGPaintServerPatternSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/svg/SVGPaintServerSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/svg/SVGPaintServerSolidSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/svg/SVGResourceClipperSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/svg/SVGResourceFilterSkia.cpp',
|
||||
'$PORT_DIR/platform/image-decoders/bmp/BMPImageDecoder.cpp',
|
||||
'$PORT_DIR/platform/image-decoders/bmp/BMPImageReader.cpp',
|
||||
'$PORT_DIR/platform/image-decoders/gif/GIFImageDecoder.cpp',
|
||||
'$PORT_DIR/platform/image-decoders/gif/GIFImageReader.cpp',
|
||||
'$PORT_DIR/platform/image-decoders/ico/ICOImageDecoder.cpp',
|
||||
'$PORT_DIR/platform/image-decoders/jpeg/JPEGImageDecoder.cpp',
|
||||
'$PORT_DIR/platform/image-decoders/png/PNGImageDecoder.cpp',
|
||||
'$PORT_DIR/platform/image-decoders/xbm/XBMImageDecoder.cpp',
|
||||
]
|
||||
|
||||
if env['PLATFORM'] == 'win32':
|
||||
# These files aren't win32-specific, they're just files that haven't yet been
|
||||
# made portable.
|
||||
input_files = [
|
||||
'$PORT_DIR/bridge/FrameWin.cpp',
|
||||
'$PORT_DIR/bridge/HistoryWin.cpp',
|
||||
'$PORT_DIR/bridge/PageWin.cpp',
|
||||
'$PORT_DIR/bridge/PluginsWin.cpp',
|
||||
'$PORT_DIR/history/BackForwardList.cpp',
|
||||
'$PORT_DIR/loader/IconDatabaseNone.cpp',
|
||||
'$PORT_DIR/loader/IconLoader.cpp',
|
||||
'$PORT_DIR/page/AXObjectCacheWin.cpp',
|
||||
'$PORT_DIR/page/DragControllerWin.cpp',
|
||||
'$PORT_DIR/page/EventHandlerWin.cpp',
|
||||
'$PORT_DIR/platform/BString.cpp',
|
||||
'$PORT_DIR/platform/ClipboardUtilitiesWin.cpp',
|
||||
'$PORT_DIR/platform/ClipboardWin.cpp',
|
||||
'$PORT_DIR/platform/ContextMenuItemWin.cpp',
|
||||
'$PORT_DIR/platform/ContextMenuWin.cpp',
|
||||
'$PORT_DIR/platform/CursorWin.cpp',
|
||||
'$PORT_DIR/platform/DragDataWin.cpp',
|
||||
'$PORT_DIR/platform/DragImageWin.cpp',
|
||||
'$PORT_DIR/platform/EditorWin.cpp',
|
||||
'$PORT_DIR/platform/FileChooserWin.cpp',
|
||||
'$PORT_DIR/platform/FramelessScrollView.cpp',
|
||||
'$PORT_DIR/platform/GKURL.cpp',
|
||||
'$PORT_DIR/platform/KeyEventWin.cpp',
|
||||
'$PORT_DIR/platform/Language.cpp',
|
||||
'$PORT_DIR/platform/LogWin.cpp',
|
||||
'$PORT_DIR/platform/MimeTypeRegistryWin.cpp',
|
||||
'$PORT_DIR/platform/PasteboardWin.cpp',
|
||||
'$PORT_DIR/platform/PlatformMouseEventWin.cpp',
|
||||
'$PORT_DIR/platform/PlatformScrollBarWin.cpp',
|
||||
'$PORT_DIR/platform/PopupMenuWin.cpp',
|
||||
'$PORT_DIR/platform/SSLKeyGeneratorWin.cpp',
|
||||
'$PORT_DIR/platform/ScreenWin.cpp',
|
||||
'$PORT_DIR/platform/ScrollViewWin.cpp',
|
||||
'$PORT_DIR/platform/SearchPopupMenuWin.cpp',
|
||||
'$PORT_DIR/platform/SharedTimerWin.cpp',
|
||||
'$PORT_DIR/platform/SoundWin.cpp',
|
||||
'$PORT_DIR/platform/SystemTimeWin.cpp',
|
||||
'$PORT_DIR/platform/TextBoundariesWin.cpp',
|
||||
'$PORT_DIR/platform/TextBreakIteratorInternalICUWin.cpp',
|
||||
'$PORT_DIR/platform/UniscribeStateTextRun.cpp',
|
||||
'$PORT_DIR/platform/WCDataObject.cpp',
|
||||
'$PORT_DIR/platform/WheelEventWin.cpp',
|
||||
'$PORT_DIR/platform/WidgetWin.cpp',
|
||||
'$PORT_DIR/platform/graphics/FontCacheWin.cpp',
|
||||
'$PORT_DIR/platform/graphics/FontCustomPlatformData.cpp',
|
||||
'$PORT_DIR/platform/graphics/FontPlatformDataWin.cpp',
|
||||
'$PORT_DIR/platform/graphics/FontWin.cpp',
|
||||
'$PORT_DIR/platform/graphics/GlyphPageTreeNodeWin.cpp',
|
||||
'$PORT_DIR/platform/graphics/GraphicsContextSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/IconWin.cpp',
|
||||
'$PORT_DIR/platform/graphics/ImageBufferSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/ImageSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/PlatformContextSkia.cpp',
|
||||
'$PORT_DIR/platform/graphics/SimpleFontDataWin.cpp',
|
||||
'$PORT_DIR/platform/graphics/SkGraphicsContext.cpp',
|
||||
'$PORT_DIR/platform/graphics/SkPaintContext.cpp',
|
||||
'$PORT_DIR/platform/graphics/svg/SVGResourceMaskerSkia.cpp',
|
||||
'$PORT_DIR/platform/network/CookieJarWin.cpp',
|
||||
'$PORT_DIR/rendering/RenderThemeWin.cpp',
|
||||
]
|
||||
|
||||
if env['PLATFORM'] == 'win32':
|
||||
# These are extremely win32 specific and will never be ported.
|
||||
input_files = [
|
||||
'$PORT_DIR/platform/graphics/IntPointWin.cpp',
|
||||
'$PORT_DIR/platform/graphics/IntRectWin.cpp',
|
||||
'$PORT_DIR/platform/graphics/IntSizeWin.cpp',
|
||||
]
|
||||
|
||||
env.ChromeStaticLibrary("port", input_files)
|
||||
|
@ -1,25 +1,25 @@
|
||||
// Copyright (c) 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 Peerable_h
|
||||
#define Peerable_h
|
||||
|
||||
#include <wtf/Noncopyable.h>
|
||||
|
||||
#if USE(V8_BINDING)
|
||||
|
||||
namespace WebCore {
|
||||
|
||||
class Peerable : Noncopyable {
|
||||
public:
|
||||
virtual void setPeer(void* peer) = 0;
|
||||
virtual void* peer() const = 0;
|
||||
protected:
|
||||
virtual ~Peerable() { }
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif // USE(V8_BINDING)
|
||||
#endif // Peerable_h
|
||||
// Copyright (c) 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 Peerable_h
|
||||
#define Peerable_h
|
||||
|
||||
#include <wtf/Noncopyable.h>
|
||||
|
||||
#if USE(V8_BINDING)
|
||||
|
||||
namespace WebCore {
|
||||
|
||||
class Peerable : Noncopyable {
|
||||
public:
|
||||
virtual void setPeer(void* peer) = 0;
|
||||
virtual void* peer() const = 0;
|
||||
protected:
|
||||
virtual ~Peerable() { }
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif // USE(V8_BINDING)
|
||||
#endif // Peerable_h
|
||||
|
@ -1,259 +1,259 @@
|
||||
// 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.
|
||||
// Copied from base/basictypes.h with some modifications
|
||||
|
||||
#ifndef V8_PROPERTY_H__
|
||||
#define V8_PROPERTY_H__
|
||||
|
||||
#include <v8.h>
|
||||
#include "v8_proxy.h"
|
||||
|
||||
namespace WebCore {
|
||||
|
||||
// Returns named property of a collection.
|
||||
template <class C>
|
||||
static v8::Handle<v8::Value> GetNamedPropertyOfCollection(
|
||||
v8::Local<v8::String> name,
|
||||
v8::Local<v8::Object> object,
|
||||
v8::Local<v8::Value> data) {
|
||||
// TODO: assert object is a collection type
|
||||
ASSERT(V8Proxy::MaybeDOMWrapper(object));
|
||||
V8ClassIndex::V8WrapperType t = V8Proxy::GetDOMWrapperType(object);
|
||||
ASSERT(t != V8ClassIndex::NODE);
|
||||
C* collection = V8Proxy::ToNativeObject<C>(t, object);
|
||||
String prop_name = ToWebCoreString(name);
|
||||
void* result = collection->namedItem(prop_name);
|
||||
if (!result) return v8::Handle<v8::Value>();
|
||||
V8ClassIndex::V8WrapperType type = V8ClassIndex::ToWrapperType(data);
|
||||
if (type == V8ClassIndex::NODE)
|
||||
return V8Proxy::NodeToV8Object(static_cast<Node*>(result));
|
||||
else
|
||||
return V8Proxy::ToV8Object(type, result);
|
||||
}
|
||||
|
||||
// A template of named property accessor of collections.
|
||||
template <class C>
|
||||
static v8::Handle<v8::Value> CollectionNamedPropertyGetter(
|
||||
v8::Local<v8::String> name, const v8::AccessorInfo& info) {
|
||||
return GetNamedPropertyOfCollection<C>(name, info.Holder(), info.Data());
|
||||
}
|
||||
|
||||
|
||||
// A template of named property accessor of HTMLSelectElement and
|
||||
// HTMLFormElement.
|
||||
template <class C>
|
||||
static v8::Handle<v8::Value> NodeCollectionNamedPropertyGetter(
|
||||
v8::Local<v8::String> name, const v8::AccessorInfo& info) {
|
||||
ASSERT(V8Proxy::MaybeDOMWrapper(info.Holder()));
|
||||
ASSERT(V8Proxy::GetDOMWrapperType(info.Holder()) == V8ClassIndex::NODE);
|
||||
C* collection = V8Proxy::DOMWrapperToNode<C>(info.Holder());
|
||||
String prop_name = ToWebCoreString(name);
|
||||
void* result = collection->namedItem(prop_name);
|
||||
if (!result) return v8::Handle<v8::Value>();
|
||||
V8ClassIndex::V8WrapperType type = V8ClassIndex::ToWrapperType(info.Data());
|
||||
if (type == V8ClassIndex::NODE)
|
||||
return V8Proxy::NodeToV8Object(static_cast<Node*>(result));
|
||||
else
|
||||
return V8Proxy::ToV8Object(type, result);
|
||||
}
|
||||
|
||||
|
||||
// A template returns whether a collection has a named property.
|
||||
// This function does not cause JS heap allocation.
|
||||
template <class C>
|
||||
static bool HasNamedPropertyOfCollection(v8::Local<v8::String> name,
|
||||
v8::Local<v8::Object> object,
|
||||
v8::Local<v8::Value> data) {
|
||||
// TODO: assert object is a collection type
|
||||
ASSERT(V8Proxy::MaybeDOMWrapper(object));
|
||||
|
||||
V8ClassIndex::V8WrapperType t = V8Proxy::GetDOMWrapperType(object);
|
||||
C* collection = V8Proxy::ToNativeObject<C>(t, object);
|
||||
String prop_name = ToWebCoreString(name);
|
||||
void* result = collection->namedItem(prop_name);
|
||||
return result != NULL;
|
||||
}
|
||||
|
||||
|
||||
// Returns the property at the index of a collection.
|
||||
template <class C>
|
||||
static v8::Handle<v8::Value> GetIndexedPropertyOfCollection(
|
||||
uint32_t index, v8::Local<v8::Object> object, v8::Local<v8::Value> data) {
|
||||
// TODO, assert that object must be a collection type
|
||||
ASSERT(V8Proxy::MaybeDOMWrapper(object));
|
||||
V8ClassIndex::V8WrapperType t = V8Proxy::GetDOMWrapperType(object);
|
||||
ASSERT(t != V8ClassIndex::NODE);
|
||||
C* collection = V8Proxy::ToNativeObject<C>(t, object);
|
||||
void* result = collection->item(index);
|
||||
if (!result) return v8::Handle<v8::Value>();
|
||||
V8ClassIndex::V8WrapperType type = V8ClassIndex::ToWrapperType(data);
|
||||
if (type == V8ClassIndex::NODE)
|
||||
return V8Proxy::NodeToV8Object(static_cast<Node*>(result));
|
||||
else
|
||||
return V8Proxy::ToV8Object(type, result);
|
||||
}
|
||||
|
||||
|
||||
// A template of index interceptor of collections.
|
||||
template <class C>
|
||||
static v8::Handle<v8::Value> CollectionIndexedPropertyGetter(
|
||||
uint32_t index, const v8::AccessorInfo& info) {
|
||||
return GetIndexedPropertyOfCollection<C>(index, info.Holder(), info.Data());
|
||||
}
|
||||
|
||||
|
||||
// A template of index interceptor of HTMLSelectElement and HTMLFormElement.
|
||||
template <class C>
|
||||
static v8::Handle<v8::Value> NodeCollectionIndexedPropertyGetter(
|
||||
uint32_t index, const v8::AccessorInfo& info) {
|
||||
ASSERT(V8Proxy::MaybeDOMWrapper(info.Holder()));
|
||||
ASSERT(V8Proxy::GetDOMWrapperType(info.Holder()) == V8ClassIndex::NODE);
|
||||
C* collection = V8Proxy::DOMWrapperToNode<C>(info.Holder());
|
||||
void* result = collection->item(index);
|
||||
if (!result) return v8::Handle<v8::Value>();
|
||||
V8ClassIndex::V8WrapperType type = V8ClassIndex::ToWrapperType(info.Data());
|
||||
if (type == V8ClassIndex::NODE)
|
||||
return V8Proxy::NodeToV8Object(static_cast<Node*>(result));
|
||||
else
|
||||
return V8Proxy::ToV8Object(type, result);
|
||||
}
|
||||
|
||||
|
||||
// Get an array containing the names of indexed properties of
|
||||
// HTMLSelectElement and HTMLFormElement.
|
||||
template <class C>
|
||||
static v8::Handle<v8::Array> NodeCollectionIndexedPropertyEnumerator(
|
||||
const v8::AccessorInfo& info) {
|
||||
ASSERT(V8Proxy::MaybeDOMWrapper(info.Holder()));
|
||||
ASSERT(V8Proxy::GetDOMWrapperType(info.Holder()) == V8ClassIndex::NODE);
|
||||
C* collection = V8Proxy::DOMWrapperToNode<C>(info.Holder());
|
||||
int length = collection->length();
|
||||
v8::Handle<v8::Array> properties = v8::Array::New(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
// TODO(ager): Do we need to check that the item function returns
|
||||
// a non-null value for this index?
|
||||
v8::Handle<v8::Integer> integer = v8::Integer::New(i);
|
||||
properties->Set(integer, integer);
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
// Get an array containing the names of indexed properties in a collection.
|
||||
template <class C>
|
||||
static v8::Handle<v8::Array> CollectionIndexedPropertyEnumerator(
|
||||
const v8::AccessorInfo& info) {
|
||||
ASSERT(V8Proxy::MaybeDOMWrapper(info.Holder()));
|
||||
V8ClassIndex::V8WrapperType t = V8Proxy::GetDOMWrapperType(info.Holder());
|
||||
C* collection = V8Proxy::ToNativeObject<C>(t, info.Holder());
|
||||
int length = collection->length();
|
||||
v8::Handle<v8::Array> properties = v8::Array::New(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
// TODO(ager): Do we need to check that the item function returns
|
||||
// a non-null value for this index?
|
||||
v8::Handle<v8::Integer> integer = v8::Integer::New(i);
|
||||
properties->Set(integer, integer);
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
||||
// Returns whether a collection has a property at a given index.
|
||||
// This function does not cause JS heap allocation.
|
||||
template <class C>
|
||||
static bool HasIndexedPropertyOfCollection(uint32_t index,
|
||||
v8::Local<v8::Object> object,
|
||||
v8::Local<v8::Value> data) {
|
||||
// TODO, assert that object must be a collection type
|
||||
ASSERT(V8Proxy::MaybeDOMWrapper(object));
|
||||
V8ClassIndex::V8WrapperType t = V8Proxy::GetDOMWrapperType(object);
|
||||
C* collection = V8Proxy::ToNativeObject<C>(t, object);
|
||||
void* result = collection->item(index);
|
||||
return result != NULL;
|
||||
}
|
||||
|
||||
|
||||
// A template for indexed getters on collections of strings that should return
|
||||
// null if the resulting string is a null string.
|
||||
template <class C>
|
||||
static v8::Handle<v8::Value> CollectionStringOrNullIndexedPropertyGetter(
|
||||
uint32_t index, const v8::AccessorInfo& info) {
|
||||
// TODO, assert that object must be a collection type
|
||||
ASSERT(V8Proxy::MaybeDOMWrapper(info.Holder()));
|
||||
V8ClassIndex::V8WrapperType t = V8Proxy::GetDOMWrapperType(info.Holder());
|
||||
C* collection = V8Proxy::ToNativeObject<C>(t, info.Holder());
|
||||
String result = collection->item(index);
|
||||
return v8StringOrNull(result);
|
||||
}
|
||||
|
||||
|
||||
// Add indexed getter to the function template for a collection.
|
||||
template <class T>
|
||||
static void SetCollectionIndexedGetter(v8::Handle<v8::FunctionTemplate> desc,
|
||||
V8ClassIndex::V8WrapperType type) {
|
||||
desc->InstanceTemplate()->SetIndexedPropertyHandler(
|
||||
CollectionIndexedPropertyGetter<T>,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
CollectionIndexedPropertyEnumerator<T>,
|
||||
v8::External::New(reinterpret_cast<void*>(type)));
|
||||
}
|
||||
|
||||
|
||||
// Add named getter to the function template for a collection.
|
||||
template <class T>
|
||||
static void SetCollectionNamedGetter(v8::Handle<v8::FunctionTemplate> desc,
|
||||
V8ClassIndex::V8WrapperType type) {
|
||||
desc->InstanceTemplate()->SetNamedPropertyHandler(
|
||||
CollectionNamedPropertyGetter<T>,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
v8::External::New(reinterpret_cast<void*>(type)));
|
||||
}
|
||||
|
||||
|
||||
// Add named and indexed getters to the function template for a collection.
|
||||
template <class T>
|
||||
static void SetCollectionIndexedAndNamedGetters(
|
||||
v8::Handle<v8::FunctionTemplate> desc, V8ClassIndex::V8WrapperType type) {
|
||||
// If we interceptor before object, accessing 'length' can trigger
|
||||
// a webkit assertion error.
|
||||
// (see fast/dom/HTMLDocument/document-special-properties.html
|
||||
desc->InstanceTemplate()->SetNamedPropertyHandler(
|
||||
CollectionNamedPropertyGetter<T>,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
v8::External::New(reinterpret_cast<void*>(type)));
|
||||
desc->InstanceTemplate()->SetIndexedPropertyHandler(
|
||||
CollectionIndexedPropertyGetter<T>,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
CollectionIndexedPropertyEnumerator<T>,
|
||||
v8::External::New(reinterpret_cast<void*>(type)));
|
||||
}
|
||||
|
||||
|
||||
// Add indexed getter returning a string or null to a function template
|
||||
// for a collection.
|
||||
template <class T>
|
||||
static void SetCollectionStringOrNullIndexedGetter(
|
||||
v8::Handle<v8::FunctionTemplate> desc) {
|
||||
desc->InstanceTemplate()->SetIndexedPropertyHandler(
|
||||
CollectionStringOrNullIndexedPropertyGetter<T>,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
CollectionIndexedPropertyEnumerator<T>);
|
||||
}
|
||||
|
||||
|
||||
} // namespace WebCore
|
||||
|
||||
#endif // V8_PROPERTY_H__
|
||||
|
||||
// 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.
|
||||
// Copied from base/basictypes.h with some modifications
|
||||
|
||||
#ifndef V8_PROPERTY_H__
|
||||
#define V8_PROPERTY_H__
|
||||
|
||||
#include <v8.h>
|
||||
#include "v8_proxy.h"
|
||||
|
||||
namespace WebCore {
|
||||
|
||||
// Returns named property of a collection.
|
||||
template <class C>
|
||||
static v8::Handle<v8::Value> GetNamedPropertyOfCollection(
|
||||
v8::Local<v8::String> name,
|
||||
v8::Local<v8::Object> object,
|
||||
v8::Local<v8::Value> data) {
|
||||
// TODO: assert object is a collection type
|
||||
ASSERT(V8Proxy::MaybeDOMWrapper(object));
|
||||
V8ClassIndex::V8WrapperType t = V8Proxy::GetDOMWrapperType(object);
|
||||
ASSERT(t != V8ClassIndex::NODE);
|
||||
C* collection = V8Proxy::ToNativeObject<C>(t, object);
|
||||
String prop_name = ToWebCoreString(name);
|
||||
void* result = collection->namedItem(prop_name);
|
||||
if (!result) return v8::Handle<v8::Value>();
|
||||
V8ClassIndex::V8WrapperType type = V8ClassIndex::ToWrapperType(data);
|
||||
if (type == V8ClassIndex::NODE)
|
||||
return V8Proxy::NodeToV8Object(static_cast<Node*>(result));
|
||||
else
|
||||
return V8Proxy::ToV8Object(type, result);
|
||||
}
|
||||
|
||||
// A template of named property accessor of collections.
|
||||
template <class C>
|
||||
static v8::Handle<v8::Value> CollectionNamedPropertyGetter(
|
||||
v8::Local<v8::String> name, const v8::AccessorInfo& info) {
|
||||
return GetNamedPropertyOfCollection<C>(name, info.Holder(), info.Data());
|
||||
}
|
||||
|
||||
|
||||
// A template of named property accessor of HTMLSelectElement and
|
||||
// HTMLFormElement.
|
||||
template <class C>
|
||||
static v8::Handle<v8::Value> NodeCollectionNamedPropertyGetter(
|
||||
v8::Local<v8::String> name, const v8::AccessorInfo& info) {
|
||||
ASSERT(V8Proxy::MaybeDOMWrapper(info.Holder()));
|
||||
ASSERT(V8Proxy::GetDOMWrapperType(info.Holder()) == V8ClassIndex::NODE);
|
||||
C* collection = V8Proxy::DOMWrapperToNode<C>(info.Holder());
|
||||
String prop_name = ToWebCoreString(name);
|
||||
void* result = collection->namedItem(prop_name);
|
||||
if (!result) return v8::Handle<v8::Value>();
|
||||
V8ClassIndex::V8WrapperType type = V8ClassIndex::ToWrapperType(info.Data());
|
||||
if (type == V8ClassIndex::NODE)
|
||||
return V8Proxy::NodeToV8Object(static_cast<Node*>(result));
|
||||
else
|
||||
return V8Proxy::ToV8Object(type, result);
|
||||
}
|
||||
|
||||
|
||||
// A template returns whether a collection has a named property.
|
||||
// This function does not cause JS heap allocation.
|
||||
template <class C>
|
||||
static bool HasNamedPropertyOfCollection(v8::Local<v8::String> name,
|
||||
v8::Local<v8::Object> object,
|
||||
v8::Local<v8::Value> data) {
|
||||
// TODO: assert object is a collection type
|
||||
ASSERT(V8Proxy::MaybeDOMWrapper(object));
|
||||
|
||||
V8ClassIndex::V8WrapperType t = V8Proxy::GetDOMWrapperType(object);
|
||||
C* collection = V8Proxy::ToNativeObject<C>(t, object);
|
||||
String prop_name = ToWebCoreString(name);
|
||||
void* result = collection->namedItem(prop_name);
|
||||
return result != NULL;
|
||||
}
|
||||
|
||||
|
||||
// Returns the property at the index of a collection.
|
||||
template <class C>
|
||||
static v8::Handle<v8::Value> GetIndexedPropertyOfCollection(
|
||||
uint32_t index, v8::Local<v8::Object> object, v8::Local<v8::Value> data) {
|
||||
// TODO, assert that object must be a collection type
|
||||
ASSERT(V8Proxy::MaybeDOMWrapper(object));
|
||||
V8ClassIndex::V8WrapperType t = V8Proxy::GetDOMWrapperType(object);
|
||||
ASSERT(t != V8ClassIndex::NODE);
|
||||
C* collection = V8Proxy::ToNativeObject<C>(t, object);
|
||||
void* result = collection->item(index);
|
||||
if (!result) return v8::Handle<v8::Value>();
|
||||
V8ClassIndex::V8WrapperType type = V8ClassIndex::ToWrapperType(data);
|
||||
if (type == V8ClassIndex::NODE)
|
||||
return V8Proxy::NodeToV8Object(static_cast<Node*>(result));
|
||||
else
|
||||
return V8Proxy::ToV8Object(type, result);
|
||||
}
|
||||
|
||||
|
||||
// A template of index interceptor of collections.
|
||||
template <class C>
|
||||
static v8::Handle<v8::Value> CollectionIndexedPropertyGetter(
|
||||
uint32_t index, const v8::AccessorInfo& info) {
|
||||
return GetIndexedPropertyOfCollection<C>(index, info.Holder(), info.Data());
|
||||
}
|
||||
|
||||
|
||||
// A template of index interceptor of HTMLSelectElement and HTMLFormElement.
|
||||
template <class C>
|
||||
static v8::Handle<v8::Value> NodeCollectionIndexedPropertyGetter(
|
||||
uint32_t index, const v8::AccessorInfo& info) {
|
||||
ASSERT(V8Proxy::MaybeDOMWrapper(info.Holder()));
|
||||
ASSERT(V8Proxy::GetDOMWrapperType(info.Holder()) == V8ClassIndex::NODE);
|
||||
C* collection = V8Proxy::DOMWrapperToNode<C>(info.Holder());
|
||||
void* result = collection->item(index);
|
||||
if (!result) return v8::Handle<v8::Value>();
|
||||
V8ClassIndex::V8WrapperType type = V8ClassIndex::ToWrapperType(info.Data());
|
||||
if (type == V8ClassIndex::NODE)
|
||||
return V8Proxy::NodeToV8Object(static_cast<Node*>(result));
|
||||
else
|
||||
return V8Proxy::ToV8Object(type, result);
|
||||
}
|
||||
|
||||
|
||||
// Get an array containing the names of indexed properties of
|
||||
// HTMLSelectElement and HTMLFormElement.
|
||||
template <class C>
|
||||
static v8::Handle<v8::Array> NodeCollectionIndexedPropertyEnumerator(
|
||||
const v8::AccessorInfo& info) {
|
||||
ASSERT(V8Proxy::MaybeDOMWrapper(info.Holder()));
|
||||
ASSERT(V8Proxy::GetDOMWrapperType(info.Holder()) == V8ClassIndex::NODE);
|
||||
C* collection = V8Proxy::DOMWrapperToNode<C>(info.Holder());
|
||||
int length = collection->length();
|
||||
v8::Handle<v8::Array> properties = v8::Array::New(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
// TODO(ager): Do we need to check that the item function returns
|
||||
// a non-null value for this index?
|
||||
v8::Handle<v8::Integer> integer = v8::Integer::New(i);
|
||||
properties->Set(integer, integer);
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
// Get an array containing the names of indexed properties in a collection.
|
||||
template <class C>
|
||||
static v8::Handle<v8::Array> CollectionIndexedPropertyEnumerator(
|
||||
const v8::AccessorInfo& info) {
|
||||
ASSERT(V8Proxy::MaybeDOMWrapper(info.Holder()));
|
||||
V8ClassIndex::V8WrapperType t = V8Proxy::GetDOMWrapperType(info.Holder());
|
||||
C* collection = V8Proxy::ToNativeObject<C>(t, info.Holder());
|
||||
int length = collection->length();
|
||||
v8::Handle<v8::Array> properties = v8::Array::New(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
// TODO(ager): Do we need to check that the item function returns
|
||||
// a non-null value for this index?
|
||||
v8::Handle<v8::Integer> integer = v8::Integer::New(i);
|
||||
properties->Set(integer, integer);
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
||||
// Returns whether a collection has a property at a given index.
|
||||
// This function does not cause JS heap allocation.
|
||||
template <class C>
|
||||
static bool HasIndexedPropertyOfCollection(uint32_t index,
|
||||
v8::Local<v8::Object> object,
|
||||
v8::Local<v8::Value> data) {
|
||||
// TODO, assert that object must be a collection type
|
||||
ASSERT(V8Proxy::MaybeDOMWrapper(object));
|
||||
V8ClassIndex::V8WrapperType t = V8Proxy::GetDOMWrapperType(object);
|
||||
C* collection = V8Proxy::ToNativeObject<C>(t, object);
|
||||
void* result = collection->item(index);
|
||||
return result != NULL;
|
||||
}
|
||||
|
||||
|
||||
// A template for indexed getters on collections of strings that should return
|
||||
// null if the resulting string is a null string.
|
||||
template <class C>
|
||||
static v8::Handle<v8::Value> CollectionStringOrNullIndexedPropertyGetter(
|
||||
uint32_t index, const v8::AccessorInfo& info) {
|
||||
// TODO, assert that object must be a collection type
|
||||
ASSERT(V8Proxy::MaybeDOMWrapper(info.Holder()));
|
||||
V8ClassIndex::V8WrapperType t = V8Proxy::GetDOMWrapperType(info.Holder());
|
||||
C* collection = V8Proxy::ToNativeObject<C>(t, info.Holder());
|
||||
String result = collection->item(index);
|
||||
return v8StringOrNull(result);
|
||||
}
|
||||
|
||||
|
||||
// Add indexed getter to the function template for a collection.
|
||||
template <class T>
|
||||
static void SetCollectionIndexedGetter(v8::Handle<v8::FunctionTemplate> desc,
|
||||
V8ClassIndex::V8WrapperType type) {
|
||||
desc->InstanceTemplate()->SetIndexedPropertyHandler(
|
||||
CollectionIndexedPropertyGetter<T>,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
CollectionIndexedPropertyEnumerator<T>,
|
||||
v8::External::New(reinterpret_cast<void*>(type)));
|
||||
}
|
||||
|
||||
|
||||
// Add named getter to the function template for a collection.
|
||||
template <class T>
|
||||
static void SetCollectionNamedGetter(v8::Handle<v8::FunctionTemplate> desc,
|
||||
V8ClassIndex::V8WrapperType type) {
|
||||
desc->InstanceTemplate()->SetNamedPropertyHandler(
|
||||
CollectionNamedPropertyGetter<T>,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
v8::External::New(reinterpret_cast<void*>(type)));
|
||||
}
|
||||
|
||||
|
||||
// Add named and indexed getters to the function template for a collection.
|
||||
template <class T>
|
||||
static void SetCollectionIndexedAndNamedGetters(
|
||||
v8::Handle<v8::FunctionTemplate> desc, V8ClassIndex::V8WrapperType type) {
|
||||
// If we interceptor before object, accessing 'length' can trigger
|
||||
// a webkit assertion error.
|
||||
// (see fast/dom/HTMLDocument/document-special-properties.html
|
||||
desc->InstanceTemplate()->SetNamedPropertyHandler(
|
||||
CollectionNamedPropertyGetter<T>,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
v8::External::New(reinterpret_cast<void*>(type)));
|
||||
desc->InstanceTemplate()->SetIndexedPropertyHandler(
|
||||
CollectionIndexedPropertyGetter<T>,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
CollectionIndexedPropertyEnumerator<T>,
|
||||
v8::External::New(reinterpret_cast<void*>(type)));
|
||||
}
|
||||
|
||||
|
||||
// Add indexed getter returning a string or null to a function template
|
||||
// for a collection.
|
||||
template <class T>
|
||||
static void SetCollectionStringOrNullIndexedGetter(
|
||||
v8::Handle<v8::FunctionTemplate> desc) {
|
||||
desc->InstanceTemplate()->SetIndexedPropertyHandler(
|
||||
CollectionStringOrNullIndexedPropertyGetter<T>,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
CollectionIndexedPropertyEnumerator<T>);
|
||||
}
|
||||
|
||||
|
||||
} // namespace WebCore
|
||||
|
||||
#endif // V8_PROPERTY_H__
|
||||
|
||||
|
Reference in New Issue
Block a user