/* KLayout Layout Viewer Copyright (C) 2006-2017 Matthias Koefferlein 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 2 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 "layRedrawThreadCanvas.h" #include "layCanvasPlane.h" #include "layBitmapsToImage.h" #include "layDrawing.h" #include "layBitmap.h" #include namespace lay { // ------------------------------------------------------------------------ BitmapCanvasData::BitmapCanvasData () : m_width (0), m_height (0) { // .. nothing yet .. } BitmapCanvasData::~BitmapCanvasData () { clear_planes (); } BitmapCanvasData::BitmapCanvasData (const std::vector &plane_buffers, const std::vector > &drawing_plane_buffers, unsigned int width, unsigned int height) : m_width (0), m_height (0) { assign (mp_plane_buffers, plane_buffers); assign (mp_drawing_plane_buffers, drawing_plane_buffers); m_width = width; m_height = height; } BitmapCanvasData &BitmapCanvasData::operator= (const BitmapCanvasData &data) { if (this != &data) { assign (mp_plane_buffers, data.mp_plane_buffers); assign (mp_drawing_plane_buffers, data.mp_drawing_plane_buffers); m_width = data.m_width; m_height = data.m_height; } return *this; } void BitmapCanvasData::fetch (std::vector &plane_buffers, std::vector > &drawing_plane_buffers, unsigned int &width, unsigned int &height) const { assign (plane_buffers, mp_plane_buffers); assign (drawing_plane_buffers, mp_drawing_plane_buffers); width = m_width; height = m_height; } bool BitmapCanvasData::can_fetch (const std::vector &plane_buffers, const std::vector > &drawing_plane_buffers, unsigned int width, unsigned int height) const { if (m_width != width || m_height != height) { return false; } if (plane_buffers.size () != mp_plane_buffers.size ()) { return false; } if (drawing_plane_buffers.size () != mp_drawing_plane_buffers.size ()) { return false; } for (size_t i = 0; i < drawing_plane_buffers.size (); ++i) { if (drawing_plane_buffers[i].size () != mp_drawing_plane_buffers[i].size ()) { return false; } } return true; } void BitmapCanvasData::assign (std::vector &to, const std::vector &from) { while (! to.empty ()) { delete to.back (); to.pop_back (); } for (std::vector ::const_iterator b = from.begin (); b != from.end (); ++b) { to.push_back (new lay::Bitmap (**b)); } } void BitmapCanvasData::assign (std::vector > &to, const std::vector > &from) { while (! to.empty ()) { while (! to.back ().empty ()) { delete to.back ().back (); to.back ().pop_back (); } to.pop_back (); } for (std::vector >::const_iterator f = from.begin (); f != from.end (); ++f) { to.push_back (std::vector ()); for (std::vector ::const_iterator ff = f->begin (); ff != f->end (); ++ff) { to.back ().push_back (new lay::Bitmap (**ff)); } } } void BitmapCanvasData::clear_planes () { assign (mp_plane_buffers, std::vector ()); assign (mp_drawing_plane_buffers, std::vector > ()); } void BitmapCanvasData::swap (BitmapCanvasData &other) { mp_plane_buffers.swap (other.mp_plane_buffers); mp_drawing_plane_buffers.swap (other.mp_drawing_plane_buffers); std::swap (m_width, other.m_width); std::swap (m_height, other.m_height); } // ------------------------------------------------------------------------ BitmapRedrawThreadCanvas::BitmapRedrawThreadCanvas () : m_width (1), m_height (1) { // .. nothing yet .. } BitmapRedrawThreadCanvas::~BitmapRedrawThreadCanvas () { lock (); clear_planes (); unlock (); } bool BitmapRedrawThreadCanvas::shift_supported () const { return true; } bool BitmapRedrawThreadCanvas::is_plane_empty (unsigned int n) { bool ret = true; lock (); if (n < mp_plane_buffers.size () && mp_plane_buffers [n] != 0) { ret = mp_plane_buffers [n]->empty (); } unlock (); return ret; } static void shift_bitmap (const lay::Bitmap *from, lay::Bitmap *to, int dx, int dy) { tl_assert (from->width () == to->width ()); tl_assert (from->height () == to->height ()); to->clear (); if (dy <= -int (from->height()) || dy >= int (from->height ()) || dx <= -int (from->width()) || dx >= int (from->width ())) { return; } int nn = int (to->height ()) - std::max (0, dy); for (int n = std::max (-dy, 0); n < nn; ++n) { if (from->is_scanline_empty (n)) { continue; } const uint32_t *sl_from = from->scanline (n); uint32_t *sl_to = to->scanline (n + dy); if (dx < 0) { unsigned int mo = ((unsigned int) -dx) / 32; unsigned int m = (to->width () + 31) / 32 - mo; sl_from += mo; unsigned int s1 = ((unsigned int) -dx) % 32; if (! s1) { for (unsigned int i = 0; i < m; ++i) { *sl_to++ = *sl_from++; } } else { unsigned int s2 = 32 - s1; for (unsigned int i = 1; i < m; ++i) { *sl_to++ = (sl_from[0] >> s1) | (sl_from[1] << s2); ++sl_from; } if (m) { *sl_to++ = (sl_from[0] >> s1); } } } else { unsigned int mo = ((unsigned int) dx) / 32; unsigned int m = (to->width () + 31) / 32 - mo; sl_to += mo; unsigned int s1 = ((unsigned int) dx) % 32; if (! s1) { for (unsigned int i = 0; i < m; ++i) { *sl_to++ = *sl_from++; } } else { unsigned int s2 = 32 - s1; if (m) { *sl_to++ = (sl_from[0] << s1); } for (unsigned int i = 1; i < m; ++i) { *sl_to++ = (sl_from[0] >> s2) | (sl_from[1] << s1); ++sl_from; } } } } } void BitmapRedrawThreadCanvas::prepare (unsigned int nlayers, unsigned int width, unsigned int height, double resolution, const db::Vector *shift_vector, const std::vector *planes, const lay::Drawings *drawings) { RedrawThreadCanvas::prepare (nlayers, width, height, resolution, shift_vector, planes, drawings); lock (); if (shift_vector) { tl_assert (width == m_width); tl_assert (height == m_height); tl_assert (nlayers == mp_plane_buffers.size ()); for (size_t i = 0; i < mp_plane_buffers.size (); ++i) { lay::Bitmap *from = mp_plane_buffers [i]; lay::Bitmap *to = mp_plane_buffers [i] = new lay::Bitmap (width, height, resolution); shift_bitmap (from, to, shift_vector->x (), shift_vector->y ()); delete from; } size_t di = 0; for (lay::Drawings::const_iterator d = drawings->begin (); d != drawings->end (); ++d, ++di) { for (unsigned int i = 0; i < d->num_planes (); ++i) { lay::Bitmap *from = mp_drawing_plane_buffers[di][i]; lay::Bitmap *to = mp_drawing_plane_buffers[di][i] = new lay::Bitmap (width, height, resolution); shift_bitmap (from, to, shift_vector->x (), shift_vector->y ()); delete from; } } } else if (planes) { tl_assert (width == m_width); tl_assert (height == m_height); for (std::vector::const_iterator l = planes->begin (); l != planes->end (); ++l) { if (*l < 0) { // clear the custom drawing planes unsigned int di = 0; for (lay::Drawings::const_iterator d = drawings->begin (); d != drawings->end (); ++d, ++di) { for (unsigned int i = 0; i < d->num_planes (); ++i) { if (mp_drawing_plane_buffers.size () > di && mp_drawing_plane_buffers[di].size () > i) { mp_drawing_plane_buffers[di][i]->clear (); } } } } else if (size_t (*l) < mp_plane_buffers.size ()) { mp_plane_buffers[*l]->clear (); } } } else { m_width = width; m_height = height; // delete the buffers and create new ones clear_planes (); for (unsigned int i = 0; i < nlayers; ++i) { mp_plane_buffers.push_back (new lay::Bitmap (width, height, resolution)); } for (lay::Drawings::const_iterator d = drawings->begin (); d != drawings->end (); ++d) { mp_drawing_plane_buffers.push_back (std::vector ()); for (unsigned int i = 0; i < d->num_planes (); ++i) { mp_drawing_plane_buffers.back ().push_back (new lay::Bitmap (width, height, resolution)); } } } unlock (); } void BitmapRedrawThreadCanvas::set_plane (unsigned int n, const lay::CanvasPlane *plane) { lock (); if (n < mp_plane_buffers.size ()) { const lay::Bitmap *bitmap = dynamic_cast (plane); tl_assert (bitmap != 0); *(mp_plane_buffers [n]) = *bitmap; } unlock (); } void BitmapRedrawThreadCanvas::set_drawing_plane (unsigned int d, unsigned int n, const lay::CanvasPlane *plane) { lock (); if (d < mp_drawing_plane_buffers.size () && n < mp_drawing_plane_buffers [d].size ()) { const lay::Bitmap *bitmap = dynamic_cast (plane); tl_assert (bitmap != 0); *(mp_drawing_plane_buffers [d][n]) = *bitmap; } unlock (); } void BitmapRedrawThreadCanvas::clear_planes () { while (! mp_plane_buffers.empty ()) { delete mp_plane_buffers.back (); mp_plane_buffers.pop_back (); } while (! mp_drawing_plane_buffers.empty ()) { while (! mp_drawing_plane_buffers.back ().empty ()) { delete mp_drawing_plane_buffers.back ().back (); mp_drawing_plane_buffers.back ().pop_back (); } mp_drawing_plane_buffers.pop_back (); } } lay::CanvasPlane * BitmapRedrawThreadCanvas::create_drawing_plane () { return new lay::Bitmap(m_width, m_height, resolution ()); } void BitmapRedrawThreadCanvas::initialize_plane (lay::CanvasPlane *plane, unsigned int n) { lock (); if (n < mp_plane_buffers.size ()) { lay::Bitmap *bitmap = dynamic_cast (plane); tl_assert (bitmap != 0); *bitmap = *(mp_plane_buffers [n]); } unlock (); } void BitmapRedrawThreadCanvas::initialize_plane (lay::CanvasPlane *plane, unsigned int d, unsigned int n) { lock (); if (d < mp_drawing_plane_buffers.size () && n < mp_drawing_plane_buffers [d].size ()) { lay::Bitmap *bitmap = dynamic_cast (plane); tl_assert (bitmap != 0); *bitmap = *(mp_drawing_plane_buffers [d][n]); } unlock (); } void BitmapRedrawThreadCanvas::to_image (const std::vector &view_ops, const lay::DitherPattern &dp, const lay::LineStyles &ls, QColor background, QColor foreground, QColor active, const lay::Drawings *drawings, QImage &img, unsigned int width, unsigned int height) { // convert the plane data to image data bitmaps_to_image (view_ops, mp_plane_buffers, dp, ls, &img, width, height, true, &mutex ()); // convert the planes of the "drawing" objects too: std::vector >::const_iterator bt = mp_drawing_plane_buffers.begin (); for (lay::Drawings::const_iterator d = drawings->begin (); d != drawings->end () && bt != mp_drawing_plane_buffers.end (); ++d, ++bt) { bitmaps_to_image (d->get_view_ops (*this, background, foreground, active), *bt, dp, ls, &img, width, height, true, &mutex ()); } } }