/**************************************************************************** * graphics/nxbe/nxbe_move.c * * Copyright (C) 2008-2009, 2011-2012, 2016, 2019 Gregory Nutt. All rights * reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name NuttX nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include "nxbe.h" #include "nxmu.h" /**************************************************************************** * Private Types ****************************************************************************/ struct nxbe_move_s { struct nxbe_clipops_s cops; struct nxgl_point_s offset; FAR struct nxbe_window_s *wnd; struct nxgl_rect_s srcrect; uint8_t order; }; /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: nxbe_clipmovesrc * * Description: * Called from nxbe_clipper() to performed the move operation on visible * regions of the rectangle. * ****************************************************************************/ static void nxbe_clipmovesrc(FAR struct nxbe_clipops_s *cops, FAR struct nxbe_plane_s *plane, FAR const struct nxgl_rect_s *rect) { struct nxbe_move_s *info = (struct nxbe_move_s *)cops; struct nxgl_point_s offset; #ifdef CONFIG_NX_UPDATE FAR struct nxbe_window_s *wnd; struct nxgl_rect_s update; #endif if (info->offset.x != 0 || info->offset.y != 0) { /* Offset is the destination position of the moved rectangle */ offset.x = rect->pt1.x + info->offset.x; offset.y = rect->pt1.y + info->offset.y; /* Move the source rectangle to the destination position in the * device */ plane->dev.moverectangle(&plane->pinfo, rect, &offset); #ifdef CONFIG_NX_UPDATE /* Move the source rectangle back to window relative coordinates and * apply the offset. */ wnd = info->wnd; nxgl_rectoffset(&update, rect, offset.x - wnd->bounds.pt1.x, offset.y - wnd->bounds.pt1.y); /* Notify any listeners that the graphic content in the update * rectangle has changed. */ nxbe_notify_rectangle(plane->driver, &update); #endif } } /**************************************************************************** * Name: nxbe_clipmoveobscured * * Description: * Called from nxbe_clipper() to performed the move operation on obsrured * regions of the rectangle. * ****************************************************************************/ static void nxbe_clipmoveobscured(FAR struct nxbe_clipops_s *cops, FAR struct nxbe_plane_s *plane, FAR const struct nxgl_rect_s *rect) { struct nxbe_move_s *info = (struct nxbe_move_s *)cops; struct nxgl_rect_s dst; nxgl_rectoffset(&dst, rect, info->offset.x, info->offset.y); nxmu_redraw(info->wnd, &dst); } /**************************************************************************** * Name: nxbe_clipmovedest * * Description: * Called from nxbe_clipper() to performed the move operation on visible * regions of the source rectangle. * ****************************************************************************/ static void nxbe_clipmovedest(FAR struct nxbe_clipops_s *cops, FAR struct nxbe_plane_s *plane, FAR const struct nxgl_rect_s *rect) { struct nxbe_move_s *dstdata = (struct nxbe_move_s *)cops; struct nxbe_window_s *wnd = dstdata->wnd; struct nxgl_point_s offset = dstdata->offset; struct nxgl_rect_s src; struct nxgl_rect_s tmprect1; struct nxgl_rect_s tmprect2; struct nxgl_rect_s nonintersecting[4]; int i; /* Redraw dest regions where the source is outside of the bounds of the * background window */ nxgl_rectoffset(&tmprect1, &dstdata->srcrect, offset.x, offset.y); nxgl_rectintersect(&tmprect2, &tmprect1, &wnd->be->bkgd.bounds); nxgl_nonintersecting(nonintersecting, rect, &tmprect2); for (i = 0; i < 4; i++) { if (!nxgl_nullrect(&nonintersecting[i])) { nxmu_redraw(dstdata->wnd, &nonintersecting[i]); } } /* Clip to determine what is inside the bounds */ nxgl_rectintersect(&src, rect, &dstdata->srcrect); if (!nxgl_nullrect(&src)) { struct nxbe_move_s srcinfo; /* Move the visible part of window */ srcinfo.cops.visible = nxbe_clipmovesrc; srcinfo.cops.obscured = nxbe_clipmoveobscured; srcinfo.offset = offset; srcinfo.wnd = wnd; nxbe_clipper(dstdata->wnd->above, &src, dstdata->order, &srcinfo.cops, plane); } } /**************************************************************************** * Name: nxbe_move_dev * * Description: * Move a rectangular region within the window * * Input Parameters: * wnd - The window within which the move is to be done * rect - Describes the rectangular region to move (absolute device * positions) * offset - The offset to move the region * * Returned Value: * None * ****************************************************************************/ static inline void nxbe_move_dev(FAR struct nxbe_window_s *wnd, FAR const struct nxgl_rect_s *rect, FAR const struct nxgl_point_s *offset) { struct nxbe_move_s info; #ifdef CONFIG_NX_SWCURSOR struct nxgl_rect_s dest; #endif int i; info.cops.visible = nxbe_clipmovedest; info.cops.obscured = nxbe_clipnull; info.offset.x = offset->x; info.offset.y = offset->y; info.wnd = wnd; nxgl_rectcopy(&info.srcrect, rect); /* The clip order depends up the direction that the rectangle is being * moved. */ if (offset->y < 0) { /* Moving rectangle up */ if (offset->x < 0) { /* Moving to upper-left */ info.order = NX_CLIPORDER_TLRB; /* Top-left-right-bottom */ } else { /* Moving to upper-right (or just up) */ info.order = NX_CLIPORDER_TRLB; /* Top-right-left-bottom */ } } else { /* Moving rectangle down (or just left/right) */ if (offset->x < 0) { /* Moving to lower-left */ info.order = NX_CLIPORDER_BLRT; /* Bottom-left-right-top */ } else { /* Moving to lower-right */ info.order = NX_CLIPORDER_BRLT; /* Bottom-right-left-top */ } } #ifdef CONFIG_NX_SWCURSOR /* Apply the offsets to the source window to get the destination window */ nxgl_rectoffset(&dest, rect, offset->x, offset->y); #endif /* Then perform the move */ #if CONFIG_NX_NPLANES > 1 for (i = 0; i < wnd->be->vinfo.nplanes; i++) #else i = 0; #endif { #ifdef CONFIG_NX_SWCURSOR /* Is the cursor visible? */ if (wnd->be->cursor.visible) { /* Remove the cursor from the source region */ wnd->be->plane[i].cursor.erase(wnd->be, rect, i); } #endif nxbe_clipper(wnd->above, &info.srcrect, info.order, &info.cops, &wnd->be->plane[i]); #ifdef CONFIG_NX_SWCURSOR /* Backup and redraw the cursor in the modified region. * * REVISIT: This and the following logic belongs in the function * nxbe_clipfill(). It is here only because the struct nxbe_state_s * (wnd->be) is not available at that point. This may result in an * excessive number of cursor updates. */ nxbe_cursor_backupdraw_dev(wnd->be, &dest, i); #endif } } /**************************************************************************** * Name: nxbe_move_pwfb * * Description: * Move a rectangular region within the window * * Input Parameters: * wnd - The window within which the move is to be done * rect - Describes the rectangular region to move (absolute positions) * offset - The offset to move the region * * Returned Value: * None * ****************************************************************************/ #ifdef CONFIG_NX_RAMBACKED static inline void nxbe_move_pwfb(FAR struct nxbe_window_s *wnd, FAR const struct nxgl_rect_s *rect, FAR const struct nxgl_point_s *offset) { FAR const void *src[CONFIG_NX_NPLANES]; struct nxgl_point_s destpos; struct nxgl_point_s origin; struct nxgl_rect_s srcrect; struct nxgl_rect_s destrect; unsigned int bpp; /* The rectangle that we receive here is in absolute device coordinates. * We need to restore this to windows relative coordinates. */ nxgl_rectoffset(&srcrect, rect, -wnd->bounds.pt1.x, -wnd->bounds.pt1.y); /* Offset is the destination position of the moved rectangle */ destpos.x = srcrect.pt1.x + offset->x; destpos.y = srcrect.pt1.y + offset->y; /* Move the source rectangle to the destination position in the * frambebuffer. * REVISIT: Assumes a single color plane. */ DEBUGASSERT(wnd->be->plane[0].pwfb.moverectangle != NULL); wnd->be->plane[0].pwfb.moverectangle(wnd, &srcrect, &destpos); /* Construct the destination bounding box in relative window * coordinates. This derives from the source bounding box with * an offset distination. */ nxgl_rectoffset(&destrect, &srcrect, offset->x, offset->y); /* Get the source of address of the moved rectangle in the framebuffer. */ bpp = wnd->be->plane[0].pinfo.bpp; src[0] = (FAR const void *) ((FAR uint8_t *)wnd->fbmem + destrect.pt1.y * wnd->stride + ((bpp * destrect.pt1.x) >> 3)); /* For resolutions less than 8-bits, the starting pixel will be contained * in the byte pointed to by src[0]but may not be properly aligned for * the transfer. We fix this by modifying the origin. */ origin.x = destrect.pt1.x; origin.y = destrect.pt1.y; switch (bpp) { #ifndef CONFIG_NX_DISABLE_1BPP case 1: /* 1 bit per pixel */ { origin.x &= ~7; } break; #endif #ifndef CONFIG_NX_DISABLE_2BPP case 2: /* 2 bits per pixel */ { origin.x &= ~3; } break; #endif #ifndef CONFIG_NX_DISABLE_4BPP case 4: /* 4 bits per pixel */ { origin.x &= ~1; } break; #endif default: break; } /* Update the physical device by just copying the rectangle from the * framebuffer to the destination rectangle device graphics memory. */ nxbe_flush(wnd, &destrect, src, &origin, wnd->stride); } #endif /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: nxbe_move * * Description: * Move a rectangular region within the window * * Input Parameters: * wnd - The window within which the move is to be done * rect - Describes the rectangular region to move (window relative) * offset - The offset to move the region * * Returned Value: * None * ****************************************************************************/ void nxbe_move(FAR struct nxbe_window_s *wnd, FAR const struct nxgl_rect_s *rect, FAR const struct nxgl_point_s *offset) { struct nxgl_rect_s srcrect; DEBUGASSERT(wnd != NULL && rect != NULL && offset != 0); if (offset->x != 0 || offset->y != 0) { /* Offset the rectangle by the window origin to create a bounding box */ nxgl_rectoffset(&srcrect, rect, wnd->bounds.pt1.x, wnd->bounds.pt1.y); /* Clip to the limits of the window and of the background screen */ nxgl_rectintersect(&srcrect, &srcrect, &wnd->bounds); nxgl_rectintersect(&srcrect, &srcrect, &wnd->be->bkgd.bounds); if (!nxgl_nullrect(&srcrect)) { #ifdef CONFIG_NX_RAMBACKED /* Update the pre-window framebuffer first, then the device * memory. */ if (NXBE_ISRAMBACKED(wnd)) { nxbe_move_pwfb(wnd, &srcrect, offset); } else #endif /* Don't update hidden windows */ if (!NXBE_ISHIDDEN(wnd)) { /* Update only the graphics device memory. */ nxbe_move_dev(wnd, &srcrect, offset); } } } }