/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- _cachedBitmap
- setReachable
- setPixel32
- setPixel
- updateObjects
- getPixel
- fillRect
- dispose
- draw
- floodFill
- bitmapdata_class_init
- registerBitmapDataNative
- bitmapdata_applyFilter
- bitmapdata_clone
- bitmapdata_colorTransform
- bitmapdata_copyChannel
- bitmapdata_copyPixels
- bitmapdata_dispose
- bitmapdata_draw
- bitmapdata_fillRect
- bitmapdata_floodFill
- bitmapdata_generateFilterRect
- bitmapdata_getColorBoundsRect
- bitmapdata_getPixel
- bitmapdata_getPixel32
- bitmapdata_hitTest
- bitmapdata_merge
- bitmapdata_noise
- bitmapdata_paletteMap
- bitmapdata_perlinNoise
- bitmapdata_pixelDissolve
- bitmapdata_scroll
- bitmapdata_setPixel
- bitmapdata_setPixel32
- bitmapdata_compare
- bitmapdata_threshold
- bitmapdata_width
- bitmapdata_height
- bitmapdata_transparent
- bitmapdata_rectangle
- bitmapdata_loadBitmap
- get_flash_display_bitmap_data_constructor
- bitmapdata_ctor
- attachBitmapDataInterface
- attachBitmapDataStaticProperties
- pixelAt
// BitmapData_as.cpp: ActionScript "BitmapData" class, for Gnash.
//
// Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
// 2011 Free Software Foundation, Inc
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
#include "BitmapData_as.h"
#include <vector>
#include <sstream>
#include <algorithm>
#include <queue>
#include "MovieClip.h"
#include "GnashImage.h"
#include "DisplayObject.h"
#include "as_object.h"
#include "log.h"
#include "fn_call.h"
#include "Global_as.h"
#include "smart_ptr.h"
#include "GnashException.h"
#include "VM.h"
#include "Renderer.h"
#include "RunResources.h"
#include "namedStrings.h"
#include "Movie.h"
#include "movie_definition.h"
#include "Transform.h"
#include "ASConversions.h"
#include "flash/geom/ColorTransform_as.h"
#include "NativeFunction.h"
namespace gnash {
namespace {
as_value bitmapdata_applyFilter(const fn_call& fn);
as_value bitmapdata_clone(const fn_call& fn);
as_value bitmapdata_colorTransform(const fn_call& fn);
as_value bitmapdata_copyChannel(const fn_call& fn);
as_value bitmapdata_copyPixels(const fn_call& fn);
as_value bitmapdata_dispose(const fn_call& fn);
as_value bitmapdata_draw(const fn_call& fn);
as_value bitmapdata_fillRect(const fn_call& fn);
as_value bitmapdata_floodFill(const fn_call& fn);
as_value bitmapdata_generateFilterRect(const fn_call& fn);
as_value bitmapdata_getColorBoundsRect(const fn_call& fn);
as_value bitmapdata_getPixel(const fn_call& fn);
as_value bitmapdata_getPixel32(const fn_call& fn);
as_value bitmapdata_hitTest(const fn_call& fn);
as_value bitmapdata_merge(const fn_call& fn);
as_value bitmapdata_noise(const fn_call& fn);
as_value bitmapdata_paletteMap(const fn_call& fn);
as_value bitmapdata_perlinNoise(const fn_call& fn);
as_value bitmapdata_pixelDissolve(const fn_call& fn);
as_value bitmapdata_scroll(const fn_call& fn);
as_value bitmapdata_setPixel(const fn_call& fn);
as_value bitmapdata_setPixel32(const fn_call& fn);
as_value bitmapdata_threshold(const fn_call& fn);
as_value bitmapdata_height(const fn_call& fn);
as_value bitmapdata_rectangle(const fn_call& fn);
as_value bitmapdata_transparent(const fn_call& fn);
as_value bitmapdata_width(const fn_call& fn);
as_value bitmapdata_loadBitmap(const fn_call& fn);
as_value bitmapdata_compare(const fn_call& fn);
as_value bitmapdata_ctor(const fn_call& fn);
void attachBitmapDataInterface(as_object& o);
void attachBitmapDataStaticProperties(as_object& o);
as_value get_flash_display_bitmap_data_constructor(const fn_call& fn);
BitmapData_as::iterator pixelAt(const BitmapData_as& bd, size_t x,
size_t y);
}
BitmapData_as::BitmapData_as(as_object* owner,
std::auto_ptr<image::GnashImage> im)
:
_owner(owner),
_cachedBitmap(0)
{
assert(im->width() <= 2880);
assert(im->width() <= 2880);
// If there is a renderer, cache the image there, otherwise we store it.
Renderer* r = getRunResources(*_owner).renderer();
if (r) _cachedBitmap = r->createCachedBitmap(im);
else _image.reset(im.release());
}
void
BitmapData_as::setReachable()
{
std::for_each(_attachedObjects.begin(), _attachedObjects.end(),
std::mem_fun(&DisplayObject::setReachable));
_owner->setReachable();
}
void
BitmapData_as::setPixel32(size_t x, size_t y, boost::uint32_t color) const
{
if (disposed()) return;
if (x >= width() || y >= height()) return;
iterator it = pixelAt(*this, x, y);
*it = color;
}
void
BitmapData_as::setPixel(size_t x, size_t y, boost::uint32_t color) const
{
if (disposed()) return;
if (x >= width() || y >= height()) return;
iterator it = pixelAt(*this, x, y);
const boost::uint32_t val = *it;
*it = (color & 0xffffff) | (val & 0xff000000);
}
void
BitmapData_as::updateObjects()
{
std::for_each(_attachedObjects.begin(), _attachedObjects.end(),
std::mem_fun(&DisplayObject::update));
}
boost::uint32_t
BitmapData_as::getPixel(size_t x, size_t y) const
{
if (disposed()) return 0;
if (x >= width() || y >= height()) return 0;
return *pixelAt(*this, x, y);
}
void
BitmapData_as::fillRect(int x, int y, int w, int h, boost::uint32_t color)
{
if (disposed()) return;
if (w < 0 || h < 0) return;
if (x >= static_cast<int>(width()) || y >= static_cast<int>(height())) {
return;
}
// If x or y is less than 0, make a rectangle of the
// intersection with the bitmap.
if (x < 0) {
w += x;
x = 0;
}
if (y < 0) {
h += y;
y = 0;
}
// Make sure that the rectangle has some area in the
// bitmap and that its bottom corner is within the
// the bitmap.
if (w <= 0 || h <= 0) return;
w = std::min<size_t>(width() - x, w);
h = std::min<size_t>(height() - y, h);
iterator it = begin() + y * width();
iterator e = it + width() * h;
assert(e <= end());
while (it != e) {
// Fill from x for the width of the rectangle.
std::fill_n(it + x, w, color);
it += width();
}
updateObjects();
}
void
BitmapData_as::dispose()
{
if (_cachedBitmap) _cachedBitmap->dispose();
_cachedBitmap = 0;
_image.reset();
updateObjects();
}
void
BitmapData_as::draw(MovieClip& mc, const Transform& transform)
{
if (disposed()) return;
image::GnashImage& im = *data();
Renderer* base = getRunResources(*_owner).renderer();
if (!base) {
log_debug(_("BitmapData.draw() called without an active renderer"));
return;
}
Renderer::Internal in(*base, im);
Renderer* internal = in.renderer();
if (!internal) {
log_debug(_("Current renderer does not support internal rendering"));
return;
}
mc.draw(*internal, transform);
updateObjects();
}
void
BitmapData_as::floodFill(size_t startx, size_t starty, boost::uint32_t old,
boost::uint32_t fill)
{
if (startx >= width() || starty >= height()) return;
// We never compare alpha for RGB images.
if (!transparent()) fill |= 0xff000000;
if (old == fill) return;
std::queue<std::pair<size_t, size_t> > pixelQueue;
pixelQueue.push(std::make_pair(startx, starty));
while (!pixelQueue.empty()) {
const std::pair<size_t, size_t>& p = pixelQueue.front();
const size_t x = p.first;
const size_t y = p.second;
pixelQueue.pop();
iterator pix = pixelAt(*this, x, y);
assert(pix != end());
if (*pix != old) continue;
// Go east!
iterator east(pix);
if (x + 1 < width()) {
++east;
const iterator eaststop(pix + (width() - x));
while (east != eaststop && *east == old) ++east;
std::fill(pix, east, fill);
}
size_t edone = (east - pix);
if (!edone) ++edone;
// Add north pixels
if (y > 0) {
const size_t ny = y - 1;
for (size_t nx = x; nx != (x + edone); ++nx) {
if (*pixelAt(*this, nx, ny) == old) {
pixelQueue.push(std::make_pair(nx, ny));
}
}
}
// Go west!
iterator west(pix);
if (x > 0) {
--west;
const iterator weststop(pix - x);
while (west != weststop && *west == old) --west;
std::fill(west + 1, pix, fill);
}
size_t wdone = (pix - west);
if (!wdone) ++wdone;
// Add south pixels
if (y + 1 < height()) {
const size_t sy = y + 1;
for (size_t sx = x; sx != x - wdone; --sx) {
if (*pixelAt(*this, sx, sy) == old) {
pixelQueue.push(std::make_pair(sx, sy));
}
}
}
}
updateObjects();
}
// extern
void
bitmapdata_class_init(as_object& where, const ObjectURI& uri)
{
// TODO: this may not be correct, but it should be enumerable.
const int flags = 0;
where.init_destructive_property(uri,
get_flash_display_bitmap_data_constructor, flags);
}
void
registerBitmapDataNative(as_object& global)
{
VM& vm = getVM(global);
vm.registerNative(bitmapdata_getPixel, 1100, 1);
vm.registerNative(bitmapdata_setPixel, 1100, 2);
vm.registerNative(bitmapdata_fillRect, 1100, 3);
vm.registerNative(bitmapdata_copyPixels, 1100, 4);
vm.registerNative(bitmapdata_applyFilter, 1100, 5);
vm.registerNative(bitmapdata_scroll, 1100, 6);
vm.registerNative(bitmapdata_threshold, 1100, 7);
vm.registerNative(bitmapdata_draw, 1100, 8);
vm.registerNative(bitmapdata_pixelDissolve, 1100, 9);
vm.registerNative(bitmapdata_getPixel32, 1100, 10);
vm.registerNative(bitmapdata_setPixel32, 1100, 11);
vm.registerNative(bitmapdata_floodFill, 1100, 12);
vm.registerNative(bitmapdata_getColorBoundsRect, 1100, 13);
vm.registerNative(bitmapdata_perlinNoise, 1100, 14);
vm.registerNative(bitmapdata_colorTransform, 1100, 15);
vm.registerNative(bitmapdata_hitTest, 1100, 16);
vm.registerNative(bitmapdata_paletteMap, 1100, 17);
vm.registerNative(bitmapdata_merge, 1100, 18);
vm.registerNative(bitmapdata_noise, 1100, 19);
vm.registerNative(bitmapdata_copyChannel, 1100, 20);
vm.registerNative(bitmapdata_clone, 1100, 21);
vm.registerNative(bitmapdata_dispose, 1100, 22);
vm.registerNative(bitmapdata_generateFilterRect, 1100, 23);
vm.registerNative(bitmapdata_compare, 1100, 24);
vm.registerNative(bitmapdata_width, 1100, 100);
vm.registerNative(bitmapdata_height, 1100, 101);
vm.registerNative(bitmapdata_rectangle, 1100, 102);
vm.registerNative(bitmapdata_transparent, 1100, 103);
vm.registerNative(bitmapdata_loadBitmap, 1100, 40);
}
namespace {
as_value
bitmapdata_applyFilter(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
UNUSED(ptr);
LOG_ONCE( log_unimpl (__FUNCTION__) );
return as_value();
}
as_value
bitmapdata_clone(const fn_call& fn)
{
as_object* obj = ensure<ValidThis>(fn);
BitmapData_as* bm = ensure<ThisIsNative<BitmapData_as> >(fn);
if (bm->disposed()) return as_value();
const size_t width = bm->width();
const size_t height = bm->height();
std::auto_ptr<image::GnashImage> im;
if (bm->transparent()) {
im.reset(new image::ImageRGBA(width, height));
}
else {
im.reset(new image::ImageRGB(width, height));
}
// Note that it would be much faster to copy the pixels, but BitmapData
// currently doesn't expose a way to do this.
std::copy(bm->begin(), bm->end(), image::begin<image::ARGB>(*im));
Global_as& gl = getGlobal(fn);
as_object* ret = createObject(gl);
const as_value& proto = getMember(*obj, NSV::PROP_uuPROTOuu);
if (proto.is_object()) {
ret->set_member(NSV::PROP_uuPROTOuu, proto);
}
ret->setRelay(new BitmapData_as(ret, im));
return as_value(ret);
}
as_value
bitmapdata_colorTransform(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
UNUSED(ptr);
LOG_ONCE( log_unimpl (__FUNCTION__) );
return as_value();
}
as_value
bitmapdata_copyChannel(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
UNUSED(ptr);
LOG_ONCE( log_unimpl (__FUNCTION__) );
return as_value();
}
as_value
bitmapdata_copyPixels(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
UNUSED(ptr);
LOG_ONCE( log_unimpl (__FUNCTION__) );
return as_value();
}
as_value
bitmapdata_dispose(const fn_call& fn)
{
// Should free the memory storing the bitmap.
// All properties afterwards are -1 (even the rectangle)
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
ptr->dispose();
return as_value();
}
as_value
bitmapdata_draw(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
if (!fn.nargs) {
IF_VERBOSE_ASCODING_ERRORS(
std::ostringstream ss;
fn.dump_args(ss);
log_aserror("BitmapData.draw(%s) requires at least one argument",
ss.str());
);
return as_value();
}
as_object* o = toObject(fn.arg(0), getVM(fn));
MovieClip* mc = get<MovieClip>(o);
if (!mc) {
IF_VERBOSE_ASCODING_ERRORS(
std::ostringstream ss;
fn.dump_args(ss);
log_aserror("BitmapData.draw(%s): first argument must be a "
"MovieClip", ss.str());
);
return as_value();
}
Transform t;
if (fn.nargs > 1) {
as_object* o = toObject(fn.arg(1), getVM(fn));
if (o) t.matrix = toSWFMatrix(*o);
}
if (fn.nargs > 2) {
as_object* o = toObject(fn.arg(2), getVM(fn));
ColorTransform_as* tr;
if (isNativeType(o, tr)) {
t.colorTransform = toCxForm(*tr);
}
}
ptr->draw(*mc, t);
return as_value();
}
as_value
bitmapdata_fillRect(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
if (fn.nargs < 2) return as_value();
const as_value& arg = fn.arg(0);
if (!arg.is_object()) {
/// Isn't an object...
IF_VERBOSE_ASCODING_ERRORS(
std::ostringstream ss;
fn.dump_args(ss);
log_aserror("BitmapData.fillRect(%s): needs an object", ss.str());
);
return as_value();
}
// This can be any object with the right properties.
as_object* obj = toObject(arg, getVM(fn));
assert(obj);
as_value x, y, w, h;
obj->get_member(NSV::PROP_X, &x);
obj->get_member(NSV::PROP_Y, &y);
obj->get_member(NSV::PROP_WIDTH, &w);
obj->get_member(NSV::PROP_HEIGHT, &h);
const boost::uint32_t color = toInt(fn.arg(1), getVM(fn));
ptr->fillRect(toInt(x, getVM(fn)), toInt(y, getVM(fn)),
toInt(w, getVM(fn)), toInt(h, getVM(fn)), color);
return as_value();
}
// Fills the bitmap with a colour starting at point x, y.
as_value
bitmapdata_floodFill(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
if (fn.nargs < 3) {
return as_value();
}
if (ptr->disposed()) {
IF_VERBOSE_ASCODING_ERRORS(
log_aserror("floodFill called on disposed BitmapData!");
);
return as_value();
}
const int x = toInt(fn.arg(0), getVM(fn));
const int y = toInt(fn.arg(1), getVM(fn));
if (x < 0 || y < 0) {
return as_value();
}
const boost::uint32_t fill = toInt(fn.arg(2), getVM(fn));
const boost::uint32_t old = *pixelAt(*ptr, x, y);
// This checks whether the colours are the same.
ptr->floodFill(x, y, old, fill);
return as_value();
}
as_value
bitmapdata_generateFilterRect(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
UNUSED(ptr);
LOG_ONCE( log_unimpl (__FUNCTION__) );
return as_value();
}
as_value
bitmapdata_getColorBoundsRect(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
UNUSED(ptr);
LOG_ONCE( log_unimpl (__FUNCTION__) );
return as_value();
}
as_value
bitmapdata_getPixel(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
if (fn.nargs < 2) {
return as_value();
}
if (ptr->disposed()) {
IF_VERBOSE_ASCODING_ERRORS(
log_aserror("getPixel called on disposed BitmapData!");
);
return as_value();
}
const int x = toInt(fn.arg(0), getVM(fn));
const int y = toInt(fn.arg(1), getVM(fn));
// Will return 0 if the pixel is outside the image or the image has
// been disposed.
return static_cast<boost::int32_t>(ptr->getPixel(x, y) & 0xffffff);
}
as_value
bitmapdata_getPixel32(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
if (fn.nargs < 2) {
return as_value();
}
if (ptr->disposed()) {
IF_VERBOSE_ASCODING_ERRORS(
log_aserror("getPixel32 called on disposed BitmapData!");
);
return as_value();
}
// TODO: what happens when the pixel is outside the image?
const int x = toInt(fn.arg(0), getVM(fn));
const int y = toInt(fn.arg(1), getVM(fn));
return static_cast<boost::int32_t>(ptr->getPixel(x, y));
}
as_value
bitmapdata_hitTest(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
UNUSED(ptr);
LOG_ONCE( log_unimpl (__FUNCTION__) );
return as_value();
}
as_value
bitmapdata_merge(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
UNUSED(ptr);
LOG_ONCE( log_unimpl (__FUNCTION__) );
return as_value();
}
as_value
bitmapdata_noise(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
UNUSED(ptr);
LOG_ONCE( log_unimpl (__FUNCTION__) );
return as_value();
}
as_value
bitmapdata_paletteMap(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
UNUSED(ptr);
LOG_ONCE( log_unimpl (__FUNCTION__) );
return as_value();
}
as_value
bitmapdata_perlinNoise(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
UNUSED(ptr);
LOG_ONCE( log_unimpl (__FUNCTION__) );
return as_value();
}
as_value
bitmapdata_pixelDissolve(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
UNUSED(ptr);
LOG_ONCE( log_unimpl (__FUNCTION__) );
return as_value();
}
as_value
bitmapdata_scroll(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
UNUSED(ptr);
LOG_ONCE( log_unimpl (__FUNCTION__) );
return as_value();
}
as_value
bitmapdata_setPixel(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
if (fn.nargs < 3) {
return as_value();
}
const double x = toNumber(fn.arg(0), getVM(fn));
const double y = toNumber(fn.arg(1), getVM(fn));
if (isNaN(x) || isNaN(y) || x < 0 || y < 0) return as_value();
if (x >= ptr->width() || y >= ptr->height()) {
return as_value();
}
// Ignore any transparency here.
const boost::uint32_t color = toInt(fn.arg(2), getVM(fn));
ptr->setPixel(x, y, color);
return as_value();
}
as_value
bitmapdata_setPixel32(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
if (fn.nargs < 3) {
return as_value();
}
const double x = toNumber(fn.arg(0), getVM(fn));
const double y = toNumber(fn.arg(1), getVM(fn));
if (isNaN(x) || isNaN(y) || x < 0 || y < 0) return as_value();
if (x >= ptr->width() || y >= ptr->height()) {
return as_value();
}
// TODO: multiply.
const boost::uint32_t color = toInt(fn.arg(2), getVM(fn));
ptr->setPixel32(x, y, color);
return as_value();
}
as_value
bitmapdata_compare(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
UNUSED(ptr);
LOG_ONCE( log_unimpl (__FUNCTION__) );
return as_value();
}
as_value
bitmapdata_threshold(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
UNUSED(ptr);
LOG_ONCE( log_unimpl (__FUNCTION__) );
return as_value();
}
as_value
bitmapdata_width(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
// Returns the immutable width of the bitmap or -1 if dispose() has
// been called.
if (ptr->disposed()) return -1;
return as_value(ptr->width());
}
as_value
bitmapdata_height(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
// Returns the immutable height of the bitmap or -1 if dispose() has
// been called.
if (ptr->disposed()) return -1;
return as_value(ptr->height());
}
as_value
bitmapdata_transparent(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
// Returns whether bitmap is transparent or -1 if dispose() has been called.
if (ptr->disposed()) return -1;
return as_value(ptr->transparent());
}
as_value
bitmapdata_rectangle(const fn_call& fn)
{
BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
// Returns the immutable rectangle of the bitmap or -1 if dispose()
// has been called.
if (ptr->disposed()) return -1;
// If it's not found construction will fail.
as_value rectangle(findObject(fn.env(), "flash.geom.Rectangle"));
as_function* rectCtor = rectangle.to_function();
if (!rectCtor) {
IF_VERBOSE_ASCODING_ERRORS(
log_aserror("Failed to construct flash.geom.Rectangle!");
);
return -1;
}
fn_call::Args args;
args += 0.0, 0.0, ptr->width(), ptr->height();
as_object* newRect = constructInstance(*rectCtor, fn.env(), args);
return as_value(newRect);
}
as_value
bitmapdata_loadBitmap(const fn_call& fn)
{
// This is a static method, but still requires a parent object for
// the prototype.
as_object* ptr = ensure<ValidThis>(fn);
if (!fn.nargs) {
IF_VERBOSE_ASCODING_ERRORS(
log_aserror("BitmapData.loadBitmap requires one argument");
);
return as_value();
}
const std::string linkage = fn.arg(0).to_string();
DisplayObject* tgt = fn.env().target();
if (!tgt) return as_value();
Movie* root = tgt->get_root();
assert(root);
const movie_definition* def = root->definition();
const boost::uint16_t id = def->exportID(linkage);
CachedBitmap* bit = def->getBitmap(id);
if (!bit) return as_value();
image::GnashImage& im = bit->image();
const size_t width = im.width();
const size_t height = im.height();
if (width > 2880 || height > 2880) {
return as_value();
}
std::auto_ptr<image::GnashImage> newImage;
if (im.type() == image::TYPE_RGBA) {
newImage.reset(new image::ImageRGBA(width, height));
}
else {
newImage.reset(new image::ImageRGB(width, height));
}
// The properties come from the 'this' object.
Global_as& gl = getGlobal(fn);
as_object* ret = createObject(gl);
ret->set_member(NSV::PROP_uuPROTOuu, getMember(*ptr, NSV::PROP_PROTOTYPE));
newImage->update(im.begin());
ret->setRelay(new BitmapData_as(ret, newImage));
return as_value(ret);
}
as_value
get_flash_display_bitmap_data_constructor(const fn_call& fn)
{
log_debug("Loading flash.display.BitmapData class");
Global_as& gl = getGlobal(fn);
as_object* proto = createObject(gl);
attachBitmapDataInterface(*proto);
as_object* cl = gl.createClass(&bitmapdata_ctor, proto);
attachBitmapDataStaticProperties(*cl);
return cl;
}
as_value
bitmapdata_ctor(const fn_call& fn)
{
as_object* ptr = ensure<ValidThis>(fn);
if (fn.nargs < 2) {
IF_VERBOSE_ASCODING_ERRORS(
log_aserror("BitmapData constructor requires at least two "
"arguments. Will not construct a BitmapData");
);
throw ActionTypeError();
}
size_t width = toInt(fn.arg(0), getVM(fn));
size_t height = toInt(fn.arg(1), getVM(fn));
const bool transparent = fn.nargs > 2 ? toBool(fn.arg(2), getVM(fn)) : true;
boost::uint32_t fillColor = fn.nargs > 3 ? toInt(fn.arg(3), getVM(fn)) : 0xffffffff;
if (width > 2880 || height > 2880 || width < 1 || height < 1) {
IF_VERBOSE_ASCODING_ERRORS(
log_aserror("BitmapData width and height must be between "
"1 and 2880. Will not construct a BitmapData");
);
throw ActionTypeError();
}
std::auto_ptr<image::GnashImage> im;
if (transparent) {
im.reset(new image::ImageRGBA(width, height));
}
else {
im.reset(new image::ImageRGB(width, height));
}
// There is one special case for completely transparent colours. This
// might be a part of a more general pre-treatment as other colours
// vary slightly, but we haven't worked it out yet.
if (transparent && !(fillColor & 0xff000000)) fillColor = 0;
std::fill(image::begin<image::ARGB>(*im), image::end<image::ARGB>(*im),
fillColor);
ptr->setRelay(new BitmapData_as(ptr, im));
return as_value();
}
void
attachBitmapDataInterface(as_object& o)
{
const int flags = PropFlags::onlySWF8Up;
VM& vm = getVM(o);
o.init_member("getPixel", vm.getNative(1100, 1));
o.init_member("setPixel", vm.getNative(1100, 2));
o.init_member("fillRect", vm.getNative(1100, 3));
o.init_member("copyPixels", vm.getNative(1100, 4));
o.init_member("applyFilter", vm.getNative(1100, 5));
o.init_member("scroll", vm.getNative(1100, 6));
o.init_member("threshold", vm.getNative(1100, 7));
o.init_member("draw", vm.getNative(1100, 8));
o.init_member("pixelDissolve", vm.getNative(1100, 9));
o.init_member("getPixel32", vm.getNative(1100, 10));
o.init_member("setPixel32", vm.getNative(1100, 11));
o.init_member("floodFill", vm.getNative(1100, 12));
o.init_member("getColorBoundsRect", vm.getNative(1100, 13));
o.init_member("perlinNoise", vm.getNative(1100, 14));
o.init_member("colorTransform", vm.getNative(1100, 15));
o.init_member("hitTest", vm.getNative(1100, 16));
o.init_member("paletteMap", vm.getNative(1100, 17));
o.init_member("merge", vm.getNative(1100, 18));
o.init_member("noise", vm.getNative(1100, 19));
o.init_member("copyChannel", vm.getNative(1100, 20));
o.init_member("clone", vm.getNative(1100, 21));
o.init_member("dispose", vm.getNative(1100, 22));
o.init_member("generateFilterRect", vm.getNative(1100, 23));
o.init_member("compare", vm.getNative(1100, 24));
o.init_readonly_property("width", *vm.getNative(1100, 100), flags);
o.init_readonly_property("height", *vm.getNative(1100, 101), flags);
o.init_readonly_property("rectangle", *vm.getNative(1100, 102), flags);
o.init_readonly_property("transparent", *vm.getNative(1100, 103), flags);
}
void
attachBitmapDataStaticProperties(as_object& o)
{
VM& vm = getVM(o);
o.init_member("loadBitmap", vm.getNative(1100, 40));
o.init_member("RED_CHANNEL", 1.0);
o.init_member("GREEN_CHANNEL", 2.0);
o.init_member("BLUE_CHANNEL", 4.0);
o.init_member("ALPHA_CHANNEL", 8.0);
}
BitmapData_as::iterator
pixelAt(const BitmapData_as& bd, size_t x, size_t y)
{
if (x >= bd.width() || y >= bd.height()) return bd.end();
return (bd.begin() + y * bd.width() + x);
}
} // anonymous namespace
} // end of gnash namespace