blob: 553fc55b8329b8e79a3c97e86e464a21c1e7d1a4 [file] [log] [blame]
// Copyright 2013 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 <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include "sprite.h"
namespace {
inline uint32_t Blend(uint32_t src1, uint32_t src2) {
// Divide both sources by 2, then add them together using a mask
// to avoid overflow.
src1 = (src1 >> 1) & 0x7F7F7F7F;
src2 = (src2 >> 1) & 0x7F7F7F7F;
return src1 + src2;
}
} // namespace
Sprite::Sprite(uint32_t* pixel_buffer,
const pp::Size& size,
int32_t row_bytes) {
SetPixelBuffer(pixel_buffer, size, row_bytes);
}
Sprite::~Sprite() {
delete[] pixel_buffer_;
}
void Sprite::SetPixelBuffer(uint32_t* pixel_buffer,
const pp::Size& size,
int32_t row_bytes) {
pixel_buffer_ = pixel_buffer;
pixel_buffer_size_ = size;
row_bytes_ = row_bytes ? row_bytes : size.width() * sizeof(uint32_t);
}
void Sprite::CompositeFromRectToPoint(const pp::Rect& src_rect,
uint32_t* dest_pixel_buffer,
const pp::Rect& dest_bounds,
int32_t dest_row_bytes,
const pp::Point& dest_point) const {
// Clip the source rect to the source image bounds.
pp::Rect src_bounds(pp::Point(), size());
pp::Rect src_rect_clipped(src_rect.Intersect(src_bounds));
if (src_rect_clipped.IsEmpty())
return;
// Create a clipped rect in the destination coordinate space that contains the
// final image.
pp::Rect draw_rect(dest_point, src_rect_clipped.size());
pp::Rect draw_rect_clipped(dest_bounds.Intersect(draw_rect));
if (draw_rect_clipped.IsEmpty())
return;
// Transform the dest rect to the source image coordinate system.
pp::Point src_offset(draw_rect_clipped.point());
src_offset -= dest_point;
src_rect_clipped.Offset(src_offset);
src_rect_clipped.set_size(draw_rect_clipped.size());
size_t src_byte_offset = src_rect_clipped.x() * sizeof(uint32_t) +
src_rect_clipped.y() * row_bytes_;
const uint8_t* src_pixels =
reinterpret_cast<const uint8_t*>(pixel_buffer_) + src_byte_offset;
if (dest_row_bytes == 0)
dest_row_bytes = dest_bounds.width() * sizeof(uint32_t);
size_t dest_byte_offset = draw_rect_clipped.point().x() * sizeof(uint32_t) +
draw_rect_clipped.point().y() * dest_row_bytes;
uint8_t* dest_pixels = reinterpret_cast<uint8_t*>(dest_pixel_buffer) +
dest_byte_offset;
for (int32_t y = 0; y < src_rect_clipped.height(); ++y) {
const uint32_t* src_scanline =
reinterpret_cast<const uint32_t*>(src_pixels);
uint32_t* dest_scanline = reinterpret_cast<uint32_t*>(dest_pixels);
for (int32_t x = 0; x < src_rect_clipped.width(); ++x) {
uint32_t src = *src_scanline++;
uint32_t dst = *dest_scanline;
*dest_scanline++ = Blend(dst, src);
}
src_pixels += row_bytes_;
dest_pixels += dest_row_bytes;
}
}