diff options
Diffstat (limited to 'src/drivers/Android/Fl_Android_Graphics_Clipping.cxx')
| -rw-r--r-- | src/drivers/Android/Fl_Android_Graphics_Clipping.cxx | 808 |
1 files changed, 0 insertions, 808 deletions
diff --git a/src/drivers/Android/Fl_Android_Graphics_Clipping.cxx b/src/drivers/Android/Fl_Android_Graphics_Clipping.cxx deleted file mode 100644 index 3f14319df..000000000 --- a/src/drivers/Android/Fl_Android_Graphics_Clipping.cxx +++ /dev/null @@ -1,808 +0,0 @@ -// -// Clipping region routines for the Fast Light Tool Kit (FLTK). -// -// Copyright 2018 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - - -#include <config.h> -#include "Fl_Android_Graphics_Driver.H" -#include "Fl_Android_Application.H" -#include <FL/platform.H> - - -/** - Create an empty clipping region. - */ -Fl_Rect_Region::Fl_Rect_Region() : - pLeft(0), pTop(0), pRight(0), pBottom(0) -{ -} - -/** - Create a clipping region based on position and size. - \param x, y position - \param w, h size - */ -Fl_Rect_Region::Fl_Rect_Region(int x, int y, int w, int h) : - pLeft(x), pTop(y), pRight(x+w), pBottom(y+h) -{ -} - -/** - Clone a clipping rectangle. - */ -Fl_Rect_Region::Fl_Rect_Region(const Fl_Rect_Region &r) : - pLeft(r.pLeft), pTop(r.pTop), - pRight(r.pRight), pBottom(r.pBottom) -{ -} - -/** - Clone a clipping rectangle. - The pointer can be NULL if an empty rectangle is needed. - */ -Fl_Rect_Region::Fl_Rect_Region(enum Type what) -{ - if (what==INFINITE) { - pLeft = pTop = INT_MIN; - pRight = pBottom = INT_MAX; - } else { - pLeft = pTop = pRight = pBottom = 0; - } -} - -/** - If the rectangle has no width or height, it's considered empty. - \return true, if everything will be clipped and there is nothing to draw - */ -bool Fl_Rect_Region::is_empty() const -{ - return (pRight<=pLeft || pBottom<=pTop); -} - -/** - Return true, if the rectangle is of unlimited size and nothing should be clipped. - \return treu, if there is no clipping - */ -bool Fl_Rect_Region::is_infinite() const -{ - return (pLeft==INT_MIN); -} - -/** - Set an empty clipping rect. - */ -void Fl_Rect_Region::set_empty() -{ - pLeft = pTop = pRight = pBottom = 0; -} - -/** - Set a clipping rect using position and size - \param x, y position - \param w, h size - */ -void Fl_Rect_Region::set(int x, int y, int w, int h) -{ - pLeft = x; - pTop = y; - pRight = x+w; - pBottom = y+h; -} - -/** - Set a rectangle using the coordinates of two points, top left and bottom right. - \param l, t left and top coordinate - \param r, b right and bottom coordinate - */ -void Fl_Rect_Region::set_ltrb(int l, int t, int r, int b) -{ - pLeft = l; - pTop = t; - pRight = r; - pBottom = b; -} - -/** - Copy the corrdinates from another rect. - \param r source rectangle - */ -void Fl_Rect_Region::set(const Fl_Rect_Region &r) -{ - pLeft = r.pLeft; - pTop = r.pTop; - pRight = r.pRight; - pBottom = r.pBottom; -} - -/** - Set this rect to be the intersecting area between the original rect and another rect. - \param r another rectangular region - \return EMPTY, if rectangles are not intersecting, SAME if this and rect are - equal, LESS if the new rect is smaller than the original rect - */ -int Fl_Rect_Region::intersect_with(const Fl_Rect_Region &r) -{ - if (is_empty()) { - return EMPTY; - } - if (r.is_empty()) { - set_empty(); - return EMPTY; - } - bool same = true; - if ( pLeft != r.pLeft ) { - same = false; - if ( r.pLeft > pLeft ) pLeft = r.pLeft; - } - if ( pTop != r.pTop ) { - same = false; - if ( r.pTop > pTop ) pTop = r.pTop; - } - if ( pRight != r.pRight ) { - same = false; - if ( r.pRight < pRight ) pRight = r.pRight; - } - if ( pBottom != r.pBottom ) { - same = false; - if ( r.pBottom < pBottom ) pBottom = r.pBottom; - } - if (same) - return SAME; - if (is_empty()) - return EMPTY; - return LESS; -} - -/** - Use rectangle as a bounding box and add the outline of another rect. - */ -void Fl_Rect_Region::add_to_bbox(const Fl_Rect_Region &r) -{ - if (is_empty()) return; - if (r.pLeft<pLeft) pLeft = r.pLeft; - if (r.pTop<pTop) pTop = r.pTop; - if (r.pRight>pRight) pRight = r.pRight; - if (r.pBottom>pBottom) pBottom = r.pBottom; -} - -/** - Print the coordinates of the rect to the log. - \param label some text that is logged with this message. - */ -void Fl_Rect_Region::print(const char *label) const -{ - Fl_Android_Application::log_i("---> Fl_Rect_Region: %s", label); - Fl_Android_Application::log_i("Rect l:%d t:%d r:%d b:%d", left(), top(), right(), bottom()); -} - -// ============================================================================= - -/** - Create an empty complex region. - */ -Fl_Complex_Region::Fl_Complex_Region() : - Fl_Rect_Region() -{ -} - -/** - Create a complex region with the same bounds as the give rect. - \param r region size - */ -Fl_Complex_Region::Fl_Complex_Region(const Fl_Rect_Region &r) : - Fl_Rect_Region(r) -{ -} - -/** - Delete this region, all subregions recursively, and all following regions. - */ -Fl_Complex_Region::~Fl_Complex_Region() -{ - delete_all_subregions(); -} - -/** - Delete all subregions of this region. - The pSubregion pointer should always be seen as a list of subregions, rather - than a single region and some pNext pointer. So everything we do, we should - probably do for every object in that list. - - Also note, that the top level region never has pNext pointing to anything. - */ -void Fl_Complex_Region::delete_all_subregions() -{ - // Do NOT delete the chain in pNext! The caller has to that job. - // A top-level coplex region has pNext always set to NULL, and it does - // delete all subregions chained via the subregion pNext. - while (pSubregion) { - Fl_Complex_Region *rgn = pSubregion; - pSubregion = rgn->pNext; - delete rgn; rgn = 0; - } -} - -/** - Print the entire content of this region recursively. - */ -void Fl_Complex_Region::print(const char *label) const -{ - Fl_Android_Application::log_i("---> Fl_Complex_Region: %s", label); - print_data(0); -} - -/* - Print the rectangular data only. - */ -void Fl_Complex_Region::print_data(int indent) const -{ - static const char *space = " "; - if (pSubregion) { - Fl_Android_Application::log_i("%sBBox l:%d t:%d r:%d b:%d", space+16-indent, left(), top(), right(), bottom()); - pSubregion->print_data(indent+1); - } else { - Fl_Android_Application::log_i("%sRect l:%d t:%d r:%d b:%d", space+16-indent, left(), top(), right(), bottom()); - } - if (pNext) { - pNext->print_data(indent); - } -} - -/** - Replace this region with a rectangle. - \param r the source rectangle - */ -void Fl_Complex_Region::set(const Fl_Rect_Region &r) -{ - Fl_Rect_Region::set(r); - delete_all_subregions(); -} - -/** - Replace this region with a copy of another region. - This operation can be expensive for very complex regions. - \param r the source region - */ -void Fl_Complex_Region::set(const Fl_Complex_Region &r) -{ - Fl_Rect_Region::set((const Fl_Rect_Region&)r); - delete_all_subregions(); - - Fl_Complex_Region *srcRgn = r.pSubregion; - if (srcRgn) { - // copy first subregion - Fl_Complex_Region *dstRgn = pSubregion = new Fl_Complex_Region(); - pSubregion->set(*srcRgn); - // copy rest of list - while (srcRgn) { - dstRgn->pNext = new Fl_Complex_Region(); - dstRgn = dstRgn->next(); - dstRgn->set(*srcRgn); - srcRgn = srcRgn->next(); - } - } -} - -/** - Set this region to the intersection of the original region and some rect. - \param r intersect with this rectangle - \return EMPTY, SAME, LESS - */ -int Fl_Complex_Region::intersect_with(const Fl_Rect_Region &r) -{ - if (pSubregion) { - Fl_Complex_Region *rgn = pSubregion; - while (rgn) { - rgn->intersect_with(r); - rgn = rgn->next(); - } - compress(); - } else { - Fl_Rect_Region::intersect_with(r); - } - return 0; -} - -/** - Subtract a rectangular region from this region. - \param r the rect that we want removed - \return currently 0, but could return something meaningful - */ -int Fl_Complex_Region::subtract(const Fl_Rect_Region &r) -{ - if (pSubregion) { - Fl_Complex_Region *rgn = pSubregion; - while (rgn) { - rgn->subtract(r); - rgn = rgn->next(); - } - compress(); - } else { - // Check if we overlap at all - Fl_Rect_Region s(r); - int intersects = s.intersect_with(*this); - switch (intersects) { - case EMPTY: - // nothing to do - break; - case SAME: - set_empty(); // Will be deleted by compress() - break; - case LESS: - // split this rect into 1, 2, 3, or 4 new ones - subtract_smaller_region(s); - break; - default: - Fl_Android_Application::log_e("Invalid case in %s:%d", __FUNCTION__, __LINE__); - break; - } - if (pSubregion) compress(); // because intersecting this may have created subregions - } - return 0; -} - -/** - Compress the subregion of this region if possible and update the bounding - box of this region. - - Does not recurse down the tree! - */ -void Fl_Complex_Region::compress() -{ - // Can't compress anything that does not have a subregion - if (!pSubregion) return; - - // remove all empty regions, because the really don't add anything (literally) - // print("Compress"); - Fl_Complex_Region *rgn = pSubregion; - while (rgn && rgn->is_empty()) { - pSubregion = rgn->next(); - delete rgn; rgn = pSubregion; - } - if (!pSubregion) return; - - rgn = pSubregion; - while (rgn) { - while (rgn->pNext && rgn->pNext->is_empty()) { - Fl_Complex_Region *nextNext = rgn->pNext->pNext; - delete rgn->pNext; rgn->pNext = nextNext; - } - rgn = rgn->next(); - } - - // find rectangles that can be merged into a single new rectangle - // (Too much work for much too little benefit) - - // if there is only a single subregion left, merge it into this region - if (pSubregion->pNext==nullptr) { - set((Fl_Rect_Region&)*pSubregion); // deletes subregion for us - } - if (!pSubregion) return; - - // finally, update the boudning box - Fl_Rect_Region::set((Fl_Rect_Region&)*pSubregion); - for (rgn=pSubregion->pNext; rgn; rgn=rgn->pNext) { - add_to_bbox(*rgn); - } -} - -/** - Subtract a smaller rect from a larger rect, potentially creating four new rectangles. - This assumes that the calling region is NOT complex. - \param r subtract the area of this rectangle; r must fit within ``this``. - \return currently 0, but this may change - */ -int Fl_Complex_Region::subtract_smaller_region(const Fl_Rect_Region &r) -{ - // subtract a smaller rect from a larger rect and create subrects as needed - // if there is only one single coordinate different, we can reuse this container - if (left()==r.left() && top()==r.top() && right()==r.right() && bottom()==r.bottom()) { - // this should not happen - set_empty(); - } else if (left()!=r.left() && top()==r.top() && right()==r.right() && bottom()==r.bottom()) { - pRight = r.left(); - } else if (left()==r.left() && top()!=r.top() && right()==r.right() && bottom()==r.bottom()) { - pBottom = r.top(); - } else if (left()==r.left() && top()==r.top() && right()!=r.right() && bottom()==r.bottom()) { - pLeft = r.right(); - } else if (left()==r.left() && top()==r.top() && right()==r.right() && bottom()!=r.bottom()) { - pTop = r.bottom(); - } else { - // create multiple regions - if (pTop!=r.top()) { - Fl_Complex_Region *s = add_subregion(); - s->set_ltrb(pLeft, pTop, pRight, r.top()); - } - if (pBottom!=r.bottom()) { - Fl_Complex_Region *s = add_subregion(); - s->set_ltrb(pLeft, r.bottom(), pRight, pBottom); - } - if (pLeft!=r.left()) { - Fl_Complex_Region *s = add_subregion(); - s->set_ltrb(pLeft, r.top(), r.left(), r.bottom()); - } - if (pRight!=r.right()) { - Fl_Complex_Region *s = add_subregion(); - s->set_ltrb(r.right(), r.top(), pRight, r.bottom()); - } - } - return 0; -} - -/** - Add an empty subregion to the current region. - \return a pointer to the newly created region. - */ -Fl_Complex_Region *Fl_Complex_Region::add_subregion() -{ - Fl_Complex_Region *r = new Fl_Complex_Region(); - r->pParent = this; - r->pNext = pSubregion; - pSubregion = r; - return r; -} - - -// ----------------------------------------------------------------------------- - -/** - Returns an iterator object for loops that traverse the entire region tree. - C++11 interface to range-based loops. - \return Iterator pointing to the first element. - */ -Fl_Complex_Region::Iterator Fl_Complex_Region::begin() -{ - return Iterator(this); -} - -/** - Returns an interator object to mark the end of travesing the tree. - C++11 interface to range-based loops. - \return - */ -Fl_Complex_Region::Iterator Fl_Complex_Region::end() -{ - return Iterator(nullptr); -} - -/** - Create an iterator to walk the entire tree. - \param r Iterate through this region, r must not have a parent(). - */ -Fl_Complex_Region::Iterator::Iterator(Fl_Complex_Region *r) : - pRegion(r) -{ -} - -/** - Compare two iterators. - C++11 needs this to find the end of a for loop. - \param other - \return - */ -bool Fl_Complex_Region::Iterator::operator!=(const Iterator &other) const -{ - return pRegion != other.pRegion; -} - -/** - Set the iterator to the next object in the tree, down first. - C++11 needs this to iterate in a for loop. - \return - */ -const Fl_Complex_Region::Iterator &Fl_Complex_Region::Iterator::operator++() -{ - if (pRegion->subregion()) { - pRegion = pRegion->subregion(); - } else if (pRegion->next()) { - pRegion = pRegion->next(); - } else { - pRegion = pRegion->parent(); - } - return *this; -} - -/** - Return the current object while iterating through the tree. - \return - */ -Fl_Complex_Region *Fl_Complex_Region::Iterator::operator*() const -{ - return pRegion; -} - -// ----------------------------------------------------------------------------- - -/** - Use this to iterate through a region, hitting only nodes that intersect with this rect. - \param r find all parts of the region that intersect with this rect. - \return an object that can be used in range-based for loops in C++11. - */ -Fl_Complex_Region::Overlapping Fl_Complex_Region::overlapping(const Fl_Rect_Region &r) -{ - return Overlapping(this, r); -} - -/** - A helper object for iterating through a region, finding only overlapping rects. - \param rgn - \param rect - */ -Fl_Complex_Region::Overlapping::Overlapping(Fl_Complex_Region *rgn, - const Fl_Rect_Region &rect) : - pRegion(rgn), - pOriginalRect(rect), - pClippedRect(rect) -{ -} - -/** - Return an itertor for the first clipping rectangle inside the region. - \return - */ -Fl_Complex_Region::Overlapping::OverlappingIterator Fl_Complex_Region::Overlapping::begin() -{ - find_intersecting(); - return OverlappingIterator(this); -} - -/** - Return an iterator for the end of forward iteration. - \return - */ -Fl_Complex_Region::Overlapping::OverlappingIterator Fl_Complex_Region::Overlapping::end() -{ - return OverlappingIterator(nullptr); -} - -/** - Return the result of intersecting the original rect with this iterator. - \return - */ -Fl_Rect_Region &Fl_Complex_Region::Overlapping::clipped_rect() -{ - return pClippedRect; -} - -/** - Store the intersection in pClippedRect and return true if there was an intersection. - \return - */ -bool Fl_Complex_Region::Overlapping::intersects() -{ - return (pClippedRect.intersect_with(*pRegion) != EMPTY); -} - -/** - Find the next element in the tree that actually intersects with the initial rect. - Starting the search at the current object, NOT the next object. - \return - */ -bool Fl_Complex_Region::Overlapping::find_intersecting() -{ - for (;;) { - if (!pRegion) return false; - pClippedRect.set(pOriginalRect); - if (intersects()) { - if (!pRegion->subregion()) { - return true; - } else { - pRegion = pRegion->subregion(); - } - } else { - find_next(); - } - } -} - -/** - Find the next object in the tree, complex, simple, intersecting or not. - \return - */ -bool Fl_Complex_Region::Overlapping::find_next() -{ - if (pRegion->subregion()) { - pRegion = pRegion->subregion(); - } else if (pRegion->next()) { - pRegion = pRegion->next(); - } else { - pRegion = pRegion->parent(); // can be NULL - } - return (pRegion != nullptr); -} - -// ----------------------------------------------------------------------------- - -/** - Create the actual iterator for finding true clipping rects. - \see Fl_Complex_Region::Overlapping - \param ov - */ -Fl_Complex_Region::Overlapping::OverlappingIterator::OverlappingIterator( - Overlapping *ov) : - pOv(ov) -{ -} - -/** - Compare two iterator. - This is used by C++11 range-based for loops to find the end of the range. - \param other - \return - */ -bool Fl_Complex_Region::Overlapping::OverlappingIterator::operator!=( - const OverlappingIterator &other) const -{ - auto thisRegion = pOv ? pOv->pRegion : nullptr; - auto otherRegion = other.pOv ? other.pOv->pRegion : nullptr; - return thisRegion != otherRegion; -} - -/** - Wrapper to find and set the next intersecting rectangle. - \see Fl_Complex_Region::Overlapping::find_intersecting - \see Fl_Complex_Region::Overlapping::find_next - \return - */ -const Fl_Complex_Region::Overlapping::OverlappingIterator & -Fl_Complex_Region::Overlapping::OverlappingIterator::operator++() -{ - pOv->find_next(); - if (pOv->pRegion) - pOv->find_intersecting(); - return *this; -} - -/** - Return the Fl_Complex_Region::Overlapping state for this iterator. - This gives the user access to the current rectangular fragment of - the clipping region. - \return - */ -Fl_Complex_Region::Overlapping * -Fl_Complex_Region::Overlapping::OverlappingIterator::operator*() const -{ - return pOv; -} - -// ============================================================================= - - -void Fl_Android_Graphics_Driver::restore_clip() -{ - fl_clip_state_number++; - - // find the current user clipping rectangle - Fl_Region b = rstack[rstackptr]; // Fl_Region is a pointer to Fl_Rect_Region - if (b) { - if (b->is_empty()) { - // if this is an empty region, the intersection is always empty as well - pClippingRegion.set_empty(); - } else { - // if there is a region, copy the full window region - pClippingRegion.set(pDesktopWindowRegion); - if (!b->is_infinite()) { - // if the rect has dimensions, calculate the intersection - pClippingRegion.intersect_with(*b); - } - } - } else { - // no rect? Just copy the window region - pClippingRegion.set(pDesktopWindowRegion); - } -} - - -void Fl_Android_Graphics_Driver::clip_region(Fl_Region r) -{ - Fl_Region oldr = rstack[rstackptr]; - if (oldr) - ::free(oldr); - rstack[rstackptr] = r; - restore_clip(); -} - - -Fl_Region Fl_Android_Graphics_Driver::clip_region() -{ - return rstack[rstackptr]; -} - - -void Fl_Android_Graphics_Driver::push_clip(int x, int y, int w, int h) -{ - Fl_Region r; - if (w > 0 && h > 0) { - r = new Fl_Rect_Region(x, y, w, h); - Fl_Region current = rstack[rstackptr]; - if (current) { - r->intersect_with(*current); - } - } else { // make empty clip region: - r = new Fl_Rect_Region(); - } - if (rstackptr < region_stack_max) rstack[++rstackptr] = r; - else Fl::warning("Fl_Android_Graphics_Driver::push_clip: clip stack overflow!\n"); - restore_clip(); -} - - -void Fl_Android_Graphics_Driver::push_no_clip() -{ - if (rstackptr < region_stack_max) rstack[++rstackptr] = 0; - else Fl::warning("Fl_Android_Graphics_Driver::push_no_clip: clip stack overflow!\n"); - restore_clip(); -} - - -void Fl_Android_Graphics_Driver::pop_clip() -{ - if (rstackptr > 0) { - Fl_Region oldr = rstack[rstackptr--]; - if (oldr) - ::free(oldr); - } else Fl::warning("Fl_Android_Graphics_Driver::pop_clip: clip stack underflow!\n"); - restore_clip(); -} - -/* - Intersects the rectangle with the current clip region and returns the - bounding box of the result. - - Returns non-zero if the resulting rectangle is different to the original. - This can be used to limit the necessary drawing to a rectangle. - \p W and \p H are set to zero if the rectangle is completely outside the region. - \param[in] x,y,w,h position and size of rectangle - \param[out] X,Y,W,H position and size of resulting bounding box. - \returns Non-zero if the resulting rectangle is different to the original. - */ -int Fl_Android_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H) -{ - Fl_Region r = rstack[rstackptr]; - if (r) { - Fl_Rect_Region a(x, y, w, h); - int ret = a.intersect_with(*r); - X = a.x(); - Y = a.y(); - W = a.w(); - H = a.h(); - return (ret!=Fl_Rect_Region::SAME); - } else { - X = x; Y = y; W = w; H = h; - return 0; - } -} - -/* - Does the rectangle intersect the current clip region? - \param[in] x,y,w,h position and size of rectangle - \returns non-zero if any of the rectangle intersects the current clip - region. If this returns 0 you don't have to draw the object. - - \note - Under X this returns 2 if the rectangle is partially clipped, - and 1 if it is entirely inside the clip region. - */ -int Fl_Android_Graphics_Driver::not_clipped(int x, int y, int w, int h) -{ - if (w <= 0 || h <= 0) return 0; - Fl_Region r = rstack[rstackptr]; - if (r) { - Fl_Rect_Region a(x, y, w, h); // return 0 for empty, 1 for same, 2 if intersecting - return a.intersect_with(*r); - } else { - return 1; - } -} |
