Fix a bug with invalid m_ptr in image iterators when we merge down layers (fix issue 358)

The ImageIteratorT implementation was simplified to avoid invalid m_ptrs.
This commit is contained in:
David Capello 2014-03-02 17:02:03 -03:00
parent 316223cee9
commit 77cd0e9cc6

View File

@ -19,19 +19,12 @@
#ifndef RASTER_IMAGE_ITERATOR_H_INCLUDED #ifndef RASTER_IMAGE_ITERATOR_H_INCLUDED
#define RASTER_IMAGE_ITERATOR_H_INCLUDED #define RASTER_IMAGE_ITERATOR_H_INCLUDED
#ifndef NDEBUG #include "gfx/point.h"
#define RASTER_DEBUG_ITERATORS
#endif
#include "gfx/rect.h" #include "gfx/rect.h"
#include "raster/color.h" #include "raster/color.h"
#include "raster/image.h" #include "raster/image.h"
#include "raster/image_traits.h" #include "raster/image_traits.h"
#ifdef RASTER_DEBUG_ITERATORS
#include "gfx/point.h"
#endif
#include <cstdlib> #include <cstdlib>
#include <iterator> #include <iterator>
@ -57,66 +50,53 @@ namespace raster {
} }
ImageIteratorT(const ImageIteratorT& other) : ImageIteratorT(const ImageIteratorT& other) :
m_image(other.m_image),
m_ptr(other.m_ptr), m_ptr(other.m_ptr),
m_x(other.m_x), m_x(other.m_x),
m_width(other.m_width), m_y(other.m_y),
m_nextRow(other.m_nextRow) m_xbegin(other.m_xbegin),
#ifdef RASTER_DEBUG_ITERATORS m_xend(other.m_xend)
, m_image(other.m_image)
, m_X0(other.m_X0), m_X(other.m_X), m_Y(other.m_Y)
#endif
{ {
} }
ImageIteratorT(const Image* image, const gfx::Rect& bounds, int x, int y) : ImageIteratorT(const Image* image, const gfx::Rect& bounds, int x, int y) :
m_image(const_cast<Image*>(image)),
m_ptr((pointer)image->getPixelAddress(x, y)), m_ptr((pointer)image->getPixelAddress(x, y)),
m_x(x - bounds.x), m_x(x),
m_width(bounds.w), m_y(y),
m_nextRow(image->getWidth() - bounds.w) m_xbegin(bounds.x),
#ifdef RASTER_DEBUG_ITERATORS m_xend(bounds.x + bounds.w)
, m_image(const_cast<Image*>(image))
, m_X0(bounds.x)
, m_X(x), m_Y(y)
#endif
{ {
ASSERT(bounds.contains(gfx::Point(x, y))); ASSERT(bounds.contains(gfx::Point(x, y)));
ASSERT(image->getBounds().contains(bounds)); ASSERT(image->getBounds().contains(bounds));
} }
ImageIteratorT& operator=(const ImageIteratorT& other) { ImageIteratorT& operator=(const ImageIteratorT& other) {
m_image = other.m_image;
m_ptr = other.m_ptr; m_ptr = other.m_ptr;
m_x = other.m_x; m_x = other.m_x;
m_width = other.m_width; m_y = other.m_y;
m_nextRow = other.m_nextRow; m_xbegin = other.m_xbegin;
#ifdef RASTER_DEBUG_ITERATORS m_xend = other.m_xend;
m_image = other.m_image;
m_X0 = other.m_X0;
m_X = other.m_X;
m_Y = other.m_Y;
#endif
return *this; return *this;
} }
bool operator==(const ImageIteratorT& other) const { bool operator==(const ImageIteratorT& other) const {
#ifdef RASTER_DEBUG_ITERATORS
if (m_ptr == other.m_ptr) { if (m_ptr == other.m_ptr) {
ASSERT(m_X == other.m_X && m_Y == other.m_Y); ASSERT(m_x == other.m_x && m_y == other.m_y);
} }
else { else {
ASSERT(m_X != other.m_X || m_Y != other.m_Y); ASSERT(m_x != other.m_x || m_y != other.m_y);
} }
#endif
return m_ptr == other.m_ptr; return m_ptr == other.m_ptr;
} }
bool operator!=(const ImageIteratorT& other) const { bool operator!=(const ImageIteratorT& other) const {
#ifdef RASTER_DEBUG_ITERATORS
if (m_ptr != other.m_ptr) { if (m_ptr != other.m_ptr) {
ASSERT(m_X != other.m_X || m_Y != other.m_Y); ASSERT(m_x != other.m_x || m_y != other.m_y);
} }
else { else {
ASSERT(m_X == other.m_X && m_Y == other.m_Y); ASSERT(m_x == other.m_x && m_y == other.m_y);
} }
#endif
return m_ptr != other.m_ptr; return m_ptr != other.m_ptr;
} }
bool operator<(const ImageIteratorT& other) const { return m_ptr < other.m_ptr; } bool operator<(const ImageIteratorT& other) const { return m_ptr < other.m_ptr; }
@ -125,37 +105,18 @@ namespace raster {
bool operator>=(const ImageIteratorT& other) const { return m_ptr >= other.m_ptr; } bool operator>=(const ImageIteratorT& other) const { return m_ptr >= other.m_ptr; }
ImageIteratorT& operator++() { ImageIteratorT& operator++() {
#ifdef RASTER_DEBUG_ITERATORS ASSERT(m_image->getBounds().contains(gfx::Point(m_x, m_y)));
ASSERT(m_image->getBounds().contains(gfx::Point(m_X, m_Y)));
#endif
++m_ptr; ++m_ptr;
++m_x; ++m_x;
#ifdef RASTER_DEBUG_ITERATORS if (m_x == m_xend) {
++m_X; m_x = m_xbegin;
#endif ++m_y;
if (m_x == m_width) { if (m_y < m_image->getHeight())
m_ptr += m_nextRow; m_ptr = (pointer)m_image->getPixelAddress(m_x, m_y);
m_x = 0;
#ifdef RASTER_DEBUG_ITERATORS
m_X = m_X0;
++m_Y;
if (m_Y < m_image->getHeight()) {
pointer expected_ptr = (pointer)m_image->getPixelAddress(m_X, m_Y);
ASSERT(expected_ptr == m_ptr);
}
#endif
} }
#ifdef RASTER_DEBUG_ITERATORS
else {
pointer expected_ptr = (pointer)m_image->getPixelAddress(m_X, m_Y);
ASSERT(expected_ptr == m_ptr);
}
#endif
return *this; return *this;
} }
@ -175,15 +136,11 @@ namespace raster {
reference operator*() { return *m_ptr; } reference operator*() { return *m_ptr; }
private: private:
pointer m_ptr;
int m_bit;
int m_x;
int m_width;
int m_nextRow;
#ifdef RASTER_DEBUG_ITERATORS // Data used for debugging purposes.
Image* m_image; Image* m_image;
int m_X0, m_X, m_Y; pointer m_ptr;
#endif int m_x, m_y;
int m_xbegin;
int m_xend;
}; };
template<typename ImageTraits> template<typename ImageTraits>
@ -329,122 +286,81 @@ namespace raster {
} }
ImageIteratorT(const ImageIteratorT& other) : ImageIteratorT(const ImageIteratorT& other) :
m_image(other.m_image),
m_ptr(other.m_ptr), m_ptr(other.m_ptr),
m_x(other.m_x), m_x(other.m_x),
m_y(other.m_y),
m_subPixel(other.m_subPixel), m_subPixel(other.m_subPixel),
m_subPixel0(other.m_subPixel0), m_xbegin(other.m_xbegin),
m_width(other.m_width), m_xend(other.m_xend)
m_nextRow(other.m_nextRow)
#ifdef RASTER_DEBUG_ITERATORS
, m_image(other.m_image)
, m_X0(other.m_X0), m_X(other.m_X), m_Y(other.m_Y)
#endif
{ {
} }
ImageIteratorT(const Image* image, const gfx::Rect& bounds, int x, int y) : ImageIteratorT(const Image* image, const gfx::Rect& bounds, int x, int y) :
m_image(const_cast<Image*>(image)),
m_ptr((pointer)image->getPixelAddress(x, y)), m_ptr((pointer)image->getPixelAddress(x, y)),
m_x(x - bounds.x), m_x(x),
m_y(y),
m_subPixel(x % 8), m_subPixel(x % 8),
m_subPixel0(bounds.x % 8), m_xbegin(bounds.x),
m_width(bounds.w), m_xend(bounds.x + bounds.w)
m_nextRow(// Bytes on the right of this row to jump to the beginning of the next one
BitmapTraits::getRowStrideBytes((pixels_per_byte*BitmapTraits::getRowStrideBytes(image->getWidth()))
- (bounds.x+bounds.w))
// Bytes on the left of the next row to go to bounds.x byte
+ bounds.x/pixels_per_byte)
#ifdef RASTER_DEBUG_ITERATORS
, m_image(const_cast<Image*>(image))
, m_X0(bounds.x)
, m_X(x), m_Y(y)
#endif
{ {
ASSERT(bounds.contains(gfx::Point(x, y))); ASSERT(bounds.contains(gfx::Point(x, y)));
} }
ImageIteratorT& operator=(const ImageIteratorT& other) { ImageIteratorT& operator=(const ImageIteratorT& other) {
m_image = other.m_image;
m_ptr = other.m_ptr; m_ptr = other.m_ptr;
m_x = other.m_x; m_x = other.m_x;
m_y = other.m_y;
m_subPixel = other.m_subPixel; m_subPixel = other.m_subPixel;
m_subPixel0 = other.m_subPixel0; m_xbegin = other.m_xbegin;
m_width = other.m_width; m_xend = other.m_xend;
m_nextRow = other.m_nextRow;
#ifdef RASTER_DEBUG_ITERATORS
m_image = other.m_image;
m_X0 = other.m_X0;
m_X = other.m_X;
m_Y = other.m_Y;
#endif
return *this; return *this;
} }
bool operator==(const ImageIteratorT& other) const { bool operator==(const ImageIteratorT& other) const {
#ifdef RASTER_DEBUG_ITERATORS
if (m_ptr == other.m_ptr && if (m_ptr == other.m_ptr &&
m_subPixel == other.m_subPixel) { m_subPixel == other.m_subPixel) {
ASSERT(m_X == other.m_X && m_Y == other.m_Y); ASSERT(m_x == other.m_x && m_y == other.m_y);
} }
else { else {
ASSERT(m_X != other.m_X || m_Y != other.m_Y); ASSERT(m_x != other.m_x || m_y != other.m_y);
} }
#endif
return m_ptr == other.m_ptr; return m_ptr == other.m_ptr;
} }
bool operator!=(const ImageIteratorT& other) const { bool operator!=(const ImageIteratorT& other) const {
#ifdef RASTER_DEBUG_ITERATORS
if (m_ptr != other.m_ptr || if (m_ptr != other.m_ptr ||
m_subPixel != other.m_subPixel) { m_subPixel != other.m_subPixel) {
ASSERT(m_X != other.m_X || m_Y != other.m_Y); ASSERT(m_x != other.m_x || m_y != other.m_y);
} }
else { else {
ASSERT(m_X == other.m_X && m_Y == other.m_Y); ASSERT(m_x == other.m_x && m_y == other.m_y);
} }
#endif
return m_ptr != other.m_ptr; return m_ptr != other.m_ptr;
} }
ImageIteratorT& operator++() { ImageIteratorT& operator++() {
#ifdef RASTER_DEBUG_ITERATORS ASSERT(m_image->getBounds().contains(gfx::Point(m_x, m_y)));
ASSERT(m_image->getBounds().contains(gfx::Point(m_X, m_Y)));
#endif
++m_x; ++m_x;
++m_subPixel; ++m_subPixel;
if (m_subPixel == 8) { if (m_x == m_xend) {
m_x = m_xbegin;
m_subPixel = m_x % 8;
++m_y;
if (m_y < m_image->getHeight())
m_ptr = (pointer)m_image->getPixelAddress(m_x, m_y);
else
++m_ptr;
}
else if (m_subPixel == 8) {
m_subPixel = 0; m_subPixel = 0;
++m_ptr; ++m_ptr;
} }
#ifdef RASTER_DEBUG_ITERATORS
++m_X;
#endif
if (m_x == m_width) {
m_ptr += m_nextRow;
m_x = 0;
m_subPixel = m_subPixel0;
#ifdef RASTER_DEBUG_ITERATORS
m_X = m_X0;
++m_Y;
if (m_Y < m_image->getHeight()) {
pointer expected_ptr = (pointer)m_image->getPixelAddress(m_X, m_Y);
ASSERT(expected_ptr == m_ptr);
ASSERT(m_subPixel == m_X % 8);
}
#endif
}
#ifdef RASTER_DEBUG_ITERATORS
else {
pointer expected_ptr = (pointer)m_image->getPixelAddress(m_X, m_Y);
ASSERT(expected_ptr == m_ptr);
ASSERT(m_subPixel == m_X % 8);
}
#endif
return *this; return *this;
} }
@ -471,15 +387,13 @@ namespace raster {
} }
private: private:
pointer m_ptr;
int m_x, m_subPixel, m_subPixel0;
int m_width;
int m_nextRow;
mutable BitPixelAccess m_access;
#ifdef RASTER_DEBUG_ITERATORS // Data used for debugging purposes.
Image* m_image; Image* m_image;
int m_X0, m_X, m_Y; pointer m_ptr;
#endif int m_x, m_y;
int m_subPixel;
int m_xbegin;
int m_xend;
mutable BitPixelAccess m_access;
}; };
template<> template<>