[YAROTOWS] Reintegrate the branch. For a brighter future.
[reactos.git] / reactos / subsystems / win32 / win32k / objects / fillshap.c
index a77eba5..7779de4 100644 (file)
  *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include <w32k.h>
+#include <win32k.h>
 
 #define NDEBUG
 #include <debug.h>
@@ -44,7 +44,7 @@ IntGdiPolygon(PDC    dc,
     POINTL BrushOrigin;
 //    int Left;
 //    int Top;
-    
+
     ASSERT(dc); // caller's responsibility to pass a valid dc
 
     if (!Points || Count < 2 )
@@ -110,7 +110,7 @@ IntGdiPolygon(PDC    dc,
                                   psurf,
                                   &dc->eboFill.BrushObject,
                                   Points,
-                                  Count, 
+                                  Count,
                                   DestRect,
                                   &BrushOrigin);
         }
@@ -271,15 +271,15 @@ NtGdiEllipse(
     }
 
     if (!PenWidth) PenWidth = 1;
-    pbrush->ptPenWidth.x = PenWidth;  
+    pbrush->ptPenWidth.x = PenWidth;
 
     RectBounds.left   = Left;
     RectBounds.right  = Right;
     RectBounds.top    = Top;
     RectBounds.bottom = Bottom;
-                
+
     IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
+
     RectBounds.left += dc->ptlDCOrig.x;
     RectBounds.right += dc->ptlDCOrig.x;
     RectBounds.top += dc->ptlDCOrig.y;
@@ -298,7 +298,7 @@ NtGdiEllipse(
                CenterX - RadiusX, CenterY + RadiusY, RadiusX*2, RadiusY*2);
 
     pFillBrushObj = BRUSH_LockBrush(pdcattr->hbrush);
-    if (NULL == pFillBrushObj)   
+    if (NULL == pFillBrushObj)
     {
         DPRINT1("FillEllipse Fail\n");
         SetLastWin32Error(ERROR_INTERNAL_ERROR);
@@ -478,6 +478,15 @@ NtGdiPolyPolyDraw( IN HDC hDC,
         return TRUE;
     }
 
+    DC_vPrepareDCsForBlit(dc, dc->rosdc.CombinedClip->rclBounds,
+                            NULL, dc->rosdc.CombinedClip->rclBounds);
+
+    if (dc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
+        DC_vUpdateFillBrush(dc);
+
+    if (dc->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
+        DC_vUpdateLineBrush(dc);
+
     /* Perform the actual work */
     switch (iFunc)
     {
@@ -502,6 +511,7 @@ NtGdiPolyPolyDraw( IN HDC hDC,
     }
 
     /* Cleanup and return */
+    DC_vFinishBlit(dc, NULL);
     DC_UnlockDc(dc);
     ExFreePool(pTemp);
 
@@ -529,19 +539,6 @@ IntRectangle(PDC dc,
 
     pdcattr = dc->pdcattr;
 
-    /* Do we rotate or shear? */
-    if (!(dc->dclevel.mxWorldToDevice.flAccel & MX_SCALE))
-    {
-
-        POINTL DestCoords[4];
-        ULONG  PolyCounts = 4;
-        DestCoords[0].x = DestCoords[3].x = LeftRect;
-        DestCoords[0].y = DestCoords[1].y = TopRect;
-        DestCoords[1].x = DestCoords[2].x = RightRect;
-        DestCoords[2].y = DestCoords[3].y = BottomRect;
-        // Use IntGdiPolyPolygon so to support PATH.
-        return IntGdiPolyPolygon(dc, DestCoords, &PolyCounts, 1);
-    }
     // Rectangle Path only.
     if ( PATH_IsPathOpen(dc->dclevel) )
     {
@@ -567,6 +564,8 @@ IntRectangle(PDC dc,
         DestRect.bottom--;
     }
 
+    DC_vPrepareDCsForBlit(dc, DestRect, NULL, DestRect);
+
     if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
         DC_vUpdateFillBrush(dc);
 
@@ -580,6 +579,7 @@ IntRectangle(PDC dc,
         ret = FALSE;
         goto cleanup;
     }
+
     psurf = dc->dclevel.pSurface;
     if (!psurf)
     {
@@ -645,6 +645,8 @@ IntRectangle(PDC dc,
     }
 
 cleanup:
+    DC_vFinishBlit(dc, NULL);
+
     /* Move current position in DC?
        MSDN: The current position is neither used nor updated by Rectangle. */
 
@@ -675,8 +677,25 @@ NtGdiRectangle(HDC  hDC,
         return TRUE;
     }
 
-    ret = IntRectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
-    DC_UnlockDc ( dc );
+    /* Do we rotate or shear? */
+    if (!(dc->dclevel.mxWorldToDevice.flAccel & MX_SCALE))
+    {
+        POINTL DestCoords[4];
+        ULONG PolyCounts = 4;
+
+        DestCoords[0].x = DestCoords[3].x = LeftRect;
+        DestCoords[0].y = DestCoords[1].y = TopRect;
+        DestCoords[1].x = DestCoords[2].x = RightRect;
+        DestCoords[2].y = DestCoords[3].y = BottomRect;
+        // Use IntGdiPolyPolygon so to support PATH.
+        ret = IntGdiPolyPolygon(dc, DestCoords, &PolyCounts, 1);
+    }
+    else
+    {
+        ret = IntRectangle(dc, LeftRect, TopRect, RightRect, BottomRect );
+    }
+
+    DC_UnlockDc(dc);
 
     return ret;
 }
@@ -750,7 +769,7 @@ IntRoundRect(
     }
 
     if (!PenWidth) PenWidth = 1;
-    pbrushLine->ptPenWidth.x = PenWidth;  
+    pbrushLine->ptPenWidth.x = PenWidth;
 
     RectBounds.left = Left;
     RectBounds.top = Top;
@@ -765,12 +784,12 @@ IntRoundRect(
     RectBounds.bottom += dc->ptlDCOrig.y;
 
     pbrushFill = BRUSH_LockBrush(pdcattr->hbrush);
-    if (NULL == pbrushFill)   
+    if (NULL == pbrushFill)
     {
         DPRINT1("FillRound Fail\n");
         SetLastWin32Error(ERROR_INTERNAL_ERROR);
         ret = FALSE;
-    } 
+    }
     else
     {
         RtlCopyMemory(&brushTemp, pbrushFill, sizeof(brushTemp));
@@ -837,40 +856,34 @@ NtGdiRoundRect(
     return ret;
 }
 
-BOOL FASTCALL
-IntGdiGradientFill(
-    DC *dc,
+BOOL
+NTAPI
+GreGradientFill(
+    HDC hdc,
     PTRIVERTEX pVertex,
-    ULONG uVertex,
+    ULONG nVertex,
     PVOID pMesh,
-    ULONG uMesh,
+    ULONG nMesh,
     ULONG ulMode)
 {
+    PDC pdc;
     SURFACE *psurf;
-    PPALETTE PalDestGDI;
-    XLATEOBJ *XlateObj;
-    RECTL Extent;
-    POINTL DitherOrg;
-    ULONG Mode, i;
-    BOOL Ret;
-    HPALETTE hDestPalette;
-
-    ASSERT(dc);
-    ASSERT(pVertex);
-    ASSERT(uVertex);
-    ASSERT(pMesh);
-    ASSERT(uMesh);
+    EXLATEOBJ exlo;
+    RECTL rclExtent;
+    POINTL ptlDitherOrg;
+    ULONG i;
+    BOOL bRet;
 
     /* check parameters */
     if (ulMode & GRADIENT_FILL_TRIANGLE)
     {
-        PGRADIENT_TRIANGLE tr = (PGRADIENT_TRIANGLE)pMesh;
+        PGRADIENT_TRIANGLE pTriangle = (PGRADIENT_TRIANGLE)pMesh;
 
-        for (i = 0; i < uMesh; i++, tr++)
+        for (i = 0; i < nMesh; i++, pTriangle++)
         {
-            if (tr->Vertex1 >= uVertex ||
-                    tr->Vertex2 >= uVertex ||
-                    tr->Vertex3 >= uVertex)
+            if (pTriangle->Vertex1 >= nVertex ||
+                pTriangle->Vertex2 >= nVertex ||
+                pTriangle->Vertex3 >= nVertex)
             {
                 SetLastWin32Error(ERROR_INVALID_PARAMETER);
                 return FALSE;
@@ -879,10 +892,10 @@ IntGdiGradientFill(
     }
     else
     {
-        PGRADIENT_RECT rc = (PGRADIENT_RECT)pMesh;
-        for (i = 0; i < uMesh; i++, rc++)
+        PGRADIENT_RECT pRect = (PGRADIENT_RECT)pMesh;
+        for (i = 0; i < nMesh; i++, pRect++)
         {
-            if (rc->UpperLeft >= uVertex || rc->LowerRight >= uVertex)
+            if (pRect->UpperLeft >= nVertex || pRect->LowerRight >= nVertex)
             {
                 SetLastWin32Error(ERROR_INVALID_PARAMETER);
                 return FALSE;
@@ -890,62 +903,74 @@ IntGdiGradientFill(
         }
     }
 
-    /* calculate extent */
-    Extent.left = Extent.right = pVertex->x;
-    Extent.top = Extent.bottom = pVertex->y;
-    for (i = 0; i < uVertex; i++)
+    /* Lock the output DC */
+    pdc = DC_LockDc(hdc);
+    if(!pdc)
     {
-        Extent.left = min(Extent.left, (pVertex + i)->x);
-        Extent.right = max(Extent.right, (pVertex + i)->x);
-        Extent.top = min(Extent.top, (pVertex + i)->y);
-        Extent.bottom = max(Extent.bottom, (pVertex + i)->y);
+        SetLastWin32Error(ERROR_INVALID_HANDLE);
+        return FALSE;
     }
-    IntLPtoDP(dc, (LPPOINT)&Extent, 2);
 
-    Extent.left   += dc->ptlDCOrig.x;
-    Extent.right  += dc->ptlDCOrig.x;
-    Extent.top    += dc->ptlDCOrig.y;
-    Extent.bottom += dc->ptlDCOrig.y;
+    if(pdc->dctype == DC_TYPE_INFO)
+    {
+        DC_UnlockDc(pdc);
+        /* Yes, Windows really returns TRUE in this case */
+        return TRUE;
+    }
 
-    DitherOrg.x = DitherOrg.y = 0;
-    IntLPtoDP(dc, (LPPOINT)&DitherOrg, 1);
+    psurf = pdc->dclevel.pSurface;
+    if(!psurf)
+    {
+        /* Memory DC with no surface selected */
+        DC_UnlockDc(pdc);
+        return TRUE; //CHECKME
+    }
 
-    DitherOrg.x += dc->ptlDCOrig.x;
-    DitherOrg.y += dc->ptlDCOrig.y;
+    /* calculate extent */
+    rclExtent.left = rclExtent.right = pVertex->x;
+    rclExtent.top = rclExtent.bottom = pVertex->y;
+    for (i = 0; i < nVertex; i++)
+    {
+        rclExtent.left = min(rclExtent.left, (pVertex + i)->x);
+        rclExtent.right = max(rclExtent.right, (pVertex + i)->x);
+        rclExtent.top = min(rclExtent.top, (pVertex + i)->y);
+        rclExtent.bottom = max(rclExtent.bottom, (pVertex + i)->y);
+    }
+    IntLPtoDP(pdc, (LPPOINT)&rclExtent, 2);
 
-    psurf = dc->dclevel.pSurface;
-    /* FIXME - psurf can be NULL!!! Don't assert but handle this case gracefully! */
-    ASSERT(psurf);
+    rclExtent.left   += pdc->ptlDCOrig.x;
+    rclExtent.right  += pdc->ptlDCOrig.x;
+    rclExtent.top    += pdc->ptlDCOrig.y;
+    rclExtent.bottom += pdc->ptlDCOrig.y;
 
-    hDestPalette = psurf->hDIBPalette;
-    if (!hDestPalette) hDestPalette = pPrimarySurface->DevInfo.hpalDefault;
+    ptlDitherOrg.x = ptlDitherOrg.y = 0;
+    IntLPtoDP(pdc, (LPPOINT)&ptlDitherOrg, 1);
 
-    PalDestGDI = PALETTE_LockPalette(hDestPalette);
-    if (PalDestGDI)
-    {
-        Mode = PalDestGDI->Mode;
-        PALETTE_UnlockPalette(PalDestGDI);
-    }
-    else
-        Mode = PAL_RGB;
+    ptlDitherOrg.x += pdc->ptlDCOrig.x;
+    ptlDitherOrg.y += pdc->ptlDCOrig.y;
+
+    EXLATEOBJ_vInitialize(&exlo, &gpalRGB, psurf->ppal, 0, 0, 0);
 
-    XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, hDestPalette, NULL);
-    ASSERT(XlateObj);
+    ASSERT(pdc->rosdc.CombinedClip);
 
-    Ret = IntEngGradientFill(&psurf->SurfObj,
-                             dc->rosdc.CombinedClip,
-                             XlateObj,
+    DC_vPrepareDCsForBlit(pdc, rclExtent, NULL, rclExtent);
+
+    bRet = IntEngGradientFill(&psurf->SurfObj,
+                             pdc->rosdc.CombinedClip,
+                             &exlo.xlo,
                              pVertex,
-                             uVertex,
+                             nVertex,
                              pMesh,
-                             uMesh,
-                             &Extent,
-                             &DitherOrg,
+                             nMesh,
+                             &rclExtent,
+                             &ptlDitherOrg,
                              ulMode);
 
-    EngDeleteXlate(XlateObj);
+    EXLATEOBJ_vCleanup(&exlo);
+    DC_vFinishBlit(pdc, NULL);
+    DC_UnlockDc(pdc);
 
-    return Ret;
+    return bRet;
 }
 
 BOOL
@@ -953,33 +978,19 @@ APIENTRY
 NtGdiGradientFill(
     HDC hdc,
     PTRIVERTEX pVertex,
-    ULONG uVertex,
+    ULONG nVertex,
     PVOID pMesh,
-    ULONG uMesh,
+    ULONG nMesh,
     ULONG ulMode)
 {
-    DC *dc;
-    BOOL Ret;
+    BOOL bRet;
     PTRIVERTEX SafeVertex;
     PVOID SafeMesh;
-    ULONG SizeMesh;
-    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG cbVertex, cbMesh;
 
-    dc = DC_LockDc(hdc);
-    if (!dc)
-    {
-        SetLastWin32Error(ERROR_INVALID_HANDLE);
-        return FALSE;
-    }
-    if (dc->dctype == DC_TYPE_INFO)
+    /* Validate parameters */
+    if (!pVertex || !nVertex || !pMesh || !nMesh)
     {
-        DC_UnlockDc(dc);
-        /* Yes, Windows really returns TRUE in this case */
-        return TRUE;
-    }
-    if (!pVertex || !uVertex || !pMesh || !uMesh)
-    {
-        DC_UnlockDc(dc);
         SetLastWin32Error(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
@@ -988,77 +999,55 @@ NtGdiGradientFill(
     {
         case GRADIENT_FILL_RECT_H:
         case GRADIENT_FILL_RECT_V:
-            SizeMesh = uMesh * sizeof(GRADIENT_RECT);
+            cbMesh = nMesh * sizeof(GRADIENT_RECT);
             break;
         case GRADIENT_FILL_TRIANGLE:
-            SizeMesh = uMesh * sizeof(TRIVERTEX);
+            cbMesh = nMesh * sizeof(GRADIENT_TRIANGLE);
             break;
         default:
-            DC_UnlockDc(dc);
             SetLastWin32Error(ERROR_INVALID_PARAMETER);
             return FALSE;
     }
 
-    _SEH2_TRY
+    cbVertex = nVertex * sizeof(TRIVERTEX) ;
+    if(cbVertex + cbMesh <= cbVertex)
     {
-        ProbeForRead(pVertex,
-                     uVertex * sizeof(TRIVERTEX),
-                     1);
-        ProbeForRead(pMesh,
-                     SizeMesh,
-                     1);
+        /* Overflow */
+        return FALSE ;
     }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-    {
-        Status = _SEH2_GetExceptionCode();
-    }
-    _SEH2_END;
 
-    if (!NT_SUCCESS(Status))
+    /* Allocate a kernel mode buffer */
+    SafeVertex = ExAllocatePoolWithTag(PagedPool, cbVertex + cbMesh, TAG_SHAPE);
+    if(!SafeVertex)
     {
-        DC_UnlockDc(dc);
-        SetLastWin32Error(Status);
-        return FALSE;
-    }
-
-    if (!(SafeVertex = ExAllocatePoolWithTag(PagedPool, (uVertex * sizeof(TRIVERTEX)) + SizeMesh, TAG_SHAPE)))
-    {
-        DC_UnlockDc(dc);
         SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
         return FALSE;
     }
 
-    SafeMesh = (PTRIVERTEX)(SafeVertex + uVertex);
+    SafeMesh = (PVOID)((ULONG_PTR)SafeVertex + cbVertex);
 
+    /* Copy the parameters to kernel mode */
     _SEH2_TRY
     {
-        /* pointers were already probed! */
-        RtlCopyMemory(SafeVertex,
-                      pVertex,
-                      uVertex * sizeof(TRIVERTEX));
-        RtlCopyMemory(SafeMesh,
-                      pMesh,
-                      SizeMesh);
+        ProbeForRead(pVertex, cbVertex, 1);
+        ProbeForRead(pMesh, cbMesh, 1);
+        RtlCopyMemory(SafeVertex, pVertex, cbVertex);
+        RtlCopyMemory(SafeMesh, pMesh, cbMesh);
     }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
-        Status = _SEH2_GetExceptionCode();
-    }
-    _SEH2_END;
-
-    if (!NT_SUCCESS(Status))
-    {
-        DC_UnlockDc(dc);
         ExFreePoolWithTag(SafeVertex, TAG_SHAPE);
-        SetLastNtError(Status);
-        return FALSE;
+        SetLastNtError(_SEH2_GetExceptionCode());
+        _SEH2_YIELD(return FALSE;)
     }
+    _SEH2_END;
 
-    Ret = IntGdiGradientFill(dc, SafeVertex, uVertex, SafeMesh, uMesh, ulMode);
+    /* Call the internal function */
+    bRet = GreGradientFill(hdc, SafeVertex, nVertex, SafeMesh, nMesh, ulMode);
 
-    DC_UnlockDc(dc);
-    ExFreePool(SafeVertex);
-    return Ret;
+    /* Cleanup and return result */
+    ExFreePoolWithTag(SafeVertex, TAG_SHAPE);
+    return bRet;
 }
 
 BOOL APIENTRY
@@ -1070,14 +1059,13 @@ NtGdiExtFloodFill(
     UINT  FillType)
 {
     PDC dc;
-    PDC_ATTR pdcattr;
-    SURFACE *psurf = NULL;
-    PBRUSH pbrFill = NULL;
+    PDC_ATTR   pdcattr;
+    SURFACE    *psurf = NULL;
+    EXLATEOBJ  exlo;
     BOOL       Ret = FALSE;
     RECTL      DestRect;
     POINTL     Pt;
-
-    DPRINT1("FIXME: NtGdiExtFloodFill is UNIMPLEMENTED\n");
+    ULONG      ConvColor;
 
     dc = DC_LockDc(hDC);
     if (!dc)
@@ -1110,12 +1098,6 @@ NtGdiExtFloodFill(
     else
         goto cleanup;
 
-    pbrFill = dc->dclevel.pbrFill;
-    if (!pbrFill)
-    {
-        Ret = FALSE;
-        goto cleanup;
-    }
     psurf = dc->dclevel.pSurface;
     if (!psurf)
     {
@@ -1123,6 +1105,17 @@ NtGdiExtFloodFill(
         goto cleanup;
     }
 
+    EXLATEOBJ_vInitialize(&exlo, &gpalRGB, psurf->ppal, 0, 0xffffff, 0);
+
+    /* Only solid fills supported for now
+     * How to support pattern brushes and non standard surfaces (not offering dib functions):
+     * Version a (most likely slow): call DrvPatBlt for every pixel
+     * Version b: create a flood mask and let MaskBlt blit a masked brush */
+    ConvColor = XLATEOBJ_iXlate(&exlo.xlo, Color);
+    Ret = DIB_XXBPP_FloodFillSolid(&psurf->SurfObj, &dc->eboFill.BrushObject, &DestRect, &Pt, ConvColor, FillType);
+
+    EXLATEOBJ_vCleanup(&exlo);
+
 cleanup:
     DC_UnlockDc(dc);
     return Ret;