[YAROTOWS] Reintegrate the branch. For a brighter future.
[reactos.git] / reactos / subsystems / win32 / win32k / objects / pen.c
index 3b03631..5884945 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.
  *
  * $Id$
  */
 
-#include <w32k.h>
+#include <win32k.h>
 
 #define NDEBUG
 #include <debug.h>
 
 /* PRIVATE FUNCTIONS **********************************************************/
 
-HPEN STDCALL
+PBRUSH
+FASTCALL
+PEN_LockPen(HGDIOBJ hBMObj)
+{
+   if (GDI_HANDLE_GET_TYPE(hBMObj) == GDI_OBJECT_TYPE_EXTPEN)
+      return GDIOBJ_LockObj( hBMObj, GDI_OBJECT_TYPE_EXTPEN);
+   else
+      return GDIOBJ_LockObj( hBMObj, GDI_OBJECT_TYPE_PEN);
+}
+
+PBRUSH
+FASTCALL
+PEN_ShareLockPen(HGDIOBJ hBMObj)
+{
+   if (GDI_HANDLE_GET_TYPE(hBMObj) == GDI_OBJECT_TYPE_EXTPEN)
+      return GDIOBJ_ShareLockObj( hBMObj, GDI_OBJECT_TYPE_EXTPEN);
+   else
+      return GDIOBJ_ShareLockObj( hBMObj, GDI_OBJECT_TYPE_PEN);
+}
+
+HPEN APIENTRY
 IntGdiExtCreatePen(
    DWORD dwPenStyle,
    DWORD dwWidth,
@@ -42,158 +62,212 @@ IntGdiExtCreatePen(
    IN OPTIONAL HBRUSH hbrush)
 {
    HPEN hPen;
-   PGDIBRUSHOBJ PenObject;
-   static const BYTE PatternAlternate[] = {0x55, 0x55, 0x55};
-   static const BYTE PatternDash[] = {0xFF, 0xFF, 0xC0};
-   static const BYTE PatternDot[] = {0xE3, 0x8E, 0x38};
-   static const BYTE PatternDashDot[] = {0xFF, 0x81, 0xC0};
-   static const BYTE PatternDashDotDot[] = {0xFF, 0x8E, 0x38};
+   PBRUSH pbrushPen;
+   static const BYTE PatternAlternate[] = {0x55, 0x55, 0x55, 0};
+   static const BYTE PatternDash[] = {0xFF, 0xFF, 0xC0, 0};
+   static const BYTE PatternDot[] = {0xE3, 0x8E, 0x38, 0};
+   static const BYTE PatternDashDot[] = {0xFF, 0x81, 0xC0, 0};
+   static const BYTE PatternDashDotDot[] = {0xFF, 0x8E, 0x38, 0};
+
+   dwWidth = abs(dwWidth);
+
+   if ( (dwPenStyle & PS_STYLE_MASK) == PS_NULL)
+   {
+      return StockObjects[NULL_PEN];
+   }
 
    if (bOldStylePen)
    {
-      hPen = PENOBJ_AllocPen();
+      pbrushPen = PEN_AllocPenWithHandle();
    }
    else
    {
-      hPen = PENOBJ_AllocExtPen();
+      pbrushPen = PEN_AllocExtPenWithHandle();
    }
 
-   if (!hPen)
+   if (!pbrushPen)
    {
       SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
       DPRINT("Can't allocate pen\n");
       return 0;
    }
+   hPen = pbrushPen->BaseObject.hHmgr;
 
-   if (bOldStylePen)
-   {
-      PenObject = PENOBJ_LockPen(hPen);
-   }
-   else
-   {
-      PenObject = PENOBJ_LockExtPen(hPen);
-   }
-   /* FIXME - Handle PenObject == NULL!!! */
+   // If nWidth is zero, the pen is a single pixel wide, regardless of the current transformation.
+   if ((bOldStylePen) && (!dwWidth) && (dwPenStyle & PS_STYLE_MASK) != PS_SOLID)
+      dwWidth = 1;
 
-   PenObject->ptPenWidth.x = dwWidth;
-   PenObject->ptPenWidth.y = 0;
-   PenObject->ulPenStyle = dwPenStyle;
-   PenObject->BrushAttr.lbColor = ulColor;
-   PenObject->ulStyle = ulBrushStyle;
+   pbrushPen->ptPenWidth.x = dwWidth;
+   pbrushPen->ptPenWidth.y = 0;
+   pbrushPen->ulPenStyle = dwPenStyle;
+   pbrushPen->BrushAttr.lbColor = ulColor;
+   pbrushPen->ulStyle = ulBrushStyle;
    // FIXME: copy the bitmap first ?
-   PenObject->hbmClient = (HANDLE)ulClientHatch;
-   PenObject->dwStyleCount = dwStyleCount;
-   PenObject->pStyle = pStyle;
+   pbrushPen->hbmClient = (HANDLE)ulClientHatch;
+   pbrushPen->dwStyleCount = dwStyleCount;
+   pbrushPen->pStyle = pStyle;
 
-   PenObject->flAttrs = bOldStylePen? GDIBRUSH_IS_OLDSTYLEPEN : GDIBRUSH_IS_PEN;
+   pbrushPen->flAttrs = bOldStylePen? GDIBRUSH_IS_OLDSTYLEPEN : GDIBRUSH_IS_PEN;
+
+   // If dwPenStyle is PS_COSMETIC, the width must be set to 1.
+   if ( !(bOldStylePen) && ((dwPenStyle & PS_TYPE_MASK) == PS_COSMETIC) && ( dwWidth != 1) )
+      goto ExitCleanup;
 
    switch (dwPenStyle & PS_STYLE_MASK)
    {
       case PS_NULL:
-         PenObject->flAttrs |= GDIBRUSH_IS_NULL;
+         pbrushPen->flAttrs |= GDIBRUSH_IS_NULL;
          break;
 
       case PS_SOLID:
-         PenObject->flAttrs |= GDIBRUSH_IS_SOLID;
+         pbrushPen->flAttrs |= GDIBRUSH_IS_SOLID;
          break;
 
       case PS_ALTERNATE:
-         PenObject->flAttrs |= GDIBRUSH_IS_BITMAP;
-         PenObject->hbmPattern = IntGdiCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternAlternate);
+         pbrushPen->flAttrs |= GDIBRUSH_IS_BITMAP;
+         pbrushPen->hbmPattern = GreCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternAlternate);
          break;
 
       case PS_DOT:
-         PenObject->flAttrs |= GDIBRUSH_IS_BITMAP;
-         PenObject->hbmPattern = IntGdiCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDot);
+         pbrushPen->flAttrs |= GDIBRUSH_IS_BITMAP;
+         pbrushPen->hbmPattern = GreCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDot);
          break;
 
       case PS_DASH:
-         PenObject->flAttrs |= GDIBRUSH_IS_BITMAP;
-         PenObject->hbmPattern = IntGdiCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDash);
+         pbrushPen->flAttrs |= GDIBRUSH_IS_BITMAP;
+         pbrushPen->hbmPattern = GreCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDash);
          break;
 
       case PS_DASHDOT:
-         PenObject->flAttrs |= GDIBRUSH_IS_BITMAP;
-         PenObject->hbmPattern = IntGdiCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDashDot);
+         pbrushPen->flAttrs |= GDIBRUSH_IS_BITMAP;
+         pbrushPen->hbmPattern = GreCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDashDot);
          break;
 
       case PS_DASHDOTDOT:
-         PenObject->flAttrs |= GDIBRUSH_IS_BITMAP;
-         PenObject->hbmPattern = IntGdiCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDashDotDot);
+         pbrushPen->flAttrs |= GDIBRUSH_IS_BITMAP;
+         pbrushPen->hbmPattern = GreCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDashDotDot);
          break;
 
       case PS_INSIDEFRAME:
-         /* FIXME: does it need some additional work? */
-         PenObject->flAttrs |= GDIBRUSH_IS_SOLID;
+         pbrushPen->flAttrs |= (GDIBRUSH_IS_SOLID|GDIBRUSH_IS_INSIDEFRAME);
          break;
 
       case PS_USERSTYLE:
+         if ((dwPenStyle & PS_TYPE_MASK) == PS_COSMETIC)
+         {
+            /* FIXME: PS_USERSTYLE workaround */
+            DPRINT1("PS_COSMETIC | PS_USERSTYLE not handled\n");
+            pbrushPen->flAttrs |= GDIBRUSH_IS_SOLID;
+            break;
+         }
+         else
+         {
+            UINT i;
+            BOOL has_neg = FALSE, all_zero = TRUE;
+
+            for(i = 0; (i < dwStyleCount) && !has_neg; i++)
+            {
+                has_neg = has_neg || (((INT)(pStyle[i])) < 0);
+                all_zero = all_zero && (pStyle[i] == 0);
+            }
+
+            if(all_zero || has_neg)
+            {
+                goto ExitCleanup;
+            }
+         }
          /* FIXME: what style here? */
-         PenObject->flAttrs |= 0;
+         pbrushPen->flAttrs |= 0;
          break;
 
       default:
          DPRINT1("IntGdiExtCreatePen unknown penstyle %x\n", dwPenStyle);
    }
-   PENOBJ_UnlockPen(PenObject);
-
+   PEN_UnlockPen(pbrushPen);
    return hPen;
+
+ExitCleanup:
+   SetLastWin32Error(ERROR_INVALID_PARAMETER);
+   pbrushPen->pStyle = NULL;
+   PEN_UnlockPen(pbrushPen);
+   if (bOldStylePen)
+      PEN_FreePenByHandle(hPen);
+   else
+      PEN_FreeExtPenByHandle(hPen);
+   return NULL;
 }
 
 VOID FASTCALL
 IntGdiSetSolidPenColor(HPEN hPen, COLORREF Color)
 {
-  PGDIBRUSHOBJ PenObject;
+  PBRUSH pbrushPen;
 
-  PenObject = PENOBJ_LockPen(hPen);
-  if (PenObject)
+  pbrushPen = PEN_LockPen(hPen);
+  if (pbrushPen)
   {
-    if (PenObject->flAttrs & GDIBRUSH_IS_SOLID)
+    if (pbrushPen->flAttrs & GDIBRUSH_IS_SOLID)
     {
-      PenObject->BrushAttr.lbColor = Color & 0xFFFFFF;
+      pbrushPen->BrushAttr.lbColor = Color & 0xFFFFFF;
     }
-    PENOBJ_UnlockPen(PenObject);
+    PEN_UnlockPen(pbrushPen);
   }
 }
 
-INT STDCALL
-PEN_GetObject(PGDIBRUSHOBJ pPenObject, INT cbCount, PLOGPEN pBuffer)
+INT APIENTRY
+PEN_GetObject(PBRUSH pbrushPen, INT cbCount, PLOGPEN pBuffer)
 {
    PLOGPEN pLogPen;
    PEXTLOGPEN pExtLogPen;
    INT cbRetCount;
 
-   if (pPenObject->flAttrs & GDIBRUSH_IS_OLDSTYLEPEN)
+   if (pbrushPen->flAttrs & GDIBRUSH_IS_OLDSTYLEPEN)
    {
       cbRetCount = sizeof(LOGPEN);
       if (pBuffer)
       {
+
          if (cbCount < cbRetCount) return 0;
-         pLogPen = (PLOGPEN)pBuffer;
-         pLogPen->lopnWidth = pPenObject->ptPenWidth;
-         pLogPen->lopnStyle = pPenObject->ulPenStyle;
-         pLogPen->lopnColor = pPenObject->BrushAttr.lbColor;
+
+         if ( (pbrushPen->ulPenStyle & PS_STYLE_MASK) == PS_NULL && 
+               cbCount == sizeof(EXTLOGPEN))
+         {
+            pExtLogPen = (PEXTLOGPEN)pBuffer; 
+            pExtLogPen->elpPenStyle = pbrushPen->ulPenStyle;
+            pExtLogPen->elpWidth = 0;
+            pExtLogPen->elpBrushStyle = pbrushPen->ulStyle;
+            pExtLogPen->elpColor = pbrushPen->BrushAttr.lbColor;
+            pExtLogPen->elpHatch = 0;
+            pExtLogPen->elpNumEntries = 0;
+            cbRetCount = sizeof(EXTLOGPEN);
+         }
+         else
+         {
+            pLogPen = (PLOGPEN)pBuffer;
+            pLogPen->lopnWidth = pbrushPen->ptPenWidth;
+            pLogPen->lopnStyle = pbrushPen->ulPenStyle;
+            pLogPen->lopnColor = pbrushPen->BrushAttr.lbColor;
+         }
       }
    }
    else
    {
       // FIXME: Can we trust in dwStyleCount being <= 16?
-      cbRetCount = sizeof(EXTLOGPEN) - sizeof(DWORD) + pPenObject->dwStyleCount * sizeof(DWORD);
+      cbRetCount = sizeof(EXTLOGPEN) - sizeof(DWORD) + pbrushPen->dwStyleCount * sizeof(DWORD);
       if (pBuffer)
       {
          INT i;
 
          if (cbCount < cbRetCount) return 0;
          pExtLogPen = (PEXTLOGPEN)pBuffer;
-         pExtLogPen->elpPenStyle = pPenObject->ulPenStyle;
-         pExtLogPen->elpWidth = pPenObject->ptPenWidth.x;
-         pExtLogPen->elpBrushStyle = pPenObject->ulStyle;
-         pExtLogPen->elpColor = pPenObject->BrushAttr.lbColor;
-         pExtLogPen->elpHatch = (ULONG_PTR)pPenObject->hbmClient;
-         pExtLogPen->elpNumEntries = pPenObject->dwStyleCount;
+         pExtLogPen->elpPenStyle = pbrushPen->ulPenStyle;
+         pExtLogPen->elpWidth = pbrushPen->ptPenWidth.x;
+         pExtLogPen->elpBrushStyle = pbrushPen->ulStyle;
+         pExtLogPen->elpColor = pbrushPen->BrushAttr.lbColor;
+         pExtLogPen->elpHatch = (ULONG_PTR)pbrushPen->hbmClient;
+         pExtLogPen->elpNumEntries = pbrushPen->dwStyleCount;
          for (i = 0; i < pExtLogPen->elpNumEntries; i++)
          {
-            pExtLogPen->elpStyleEntry[i] = pPenObject->pStyle[i];
+            pExtLogPen->elpStyleEntry[i] = pbrushPen->pStyle[i];
          }
       }
    }
@@ -201,18 +275,20 @@ PEN_GetObject(PGDIBRUSHOBJ pPenObject, INT cbCount, PLOGPEN pBuffer)
    return cbRetCount;
 }
 
+
 /* PUBLIC FUNCTIONS ***********************************************************/
 
-HPEN STDCALL
+HPEN APIENTRY
 NtGdiCreatePen(
    INT PenStyle,
    INT Width,
    COLORREF Color,
    IN HBRUSH hbr)
 {
-   if (PenStyle > PS_INSIDEFRAME)
+   if ( PenStyle < PS_SOLID || PenStyle > PS_INSIDEFRAME )
    {
-      PenStyle = PS_SOLID;
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      return NULL;
    }
 
    return IntGdiExtCreatePen(PenStyle,
@@ -225,10 +301,10 @@ NtGdiCreatePen(
                              NULL,
                              0,
                              TRUE,
-                             0);
+                             hbr);
 }
 
-HPEN STDCALL
+HPEN APIENTRY
 NtGdiExtCreatePen(
    DWORD dwPenStyle,
    DWORD ulWidth,
@@ -246,58 +322,79 @@ NtGdiExtCreatePen(
    DWORD* pSafeStyle = NULL;
    HPEN hPen;
 
+   if ((int)dwStyleCount < 0) return 0;
    if (dwStyleCount > 16)
    {
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
       return 0;
    }
 
    if (dwStyleCount > 0)
    {
-      pSafeStyle = ExAllocatePoolWithTag(NonPagedPool, dwStyleCount * sizeof(DWORD), TAG_EXTPEN);
+      pSafeStyle = ExAllocatePoolWithTag(NonPagedPool, dwStyleCount * sizeof(DWORD), TAG_PENSTYLES);
       if (!pSafeStyle)
       {
          SetLastNtError(ERROR_NOT_ENOUGH_MEMORY);
          return 0;
       }
-      _SEH_TRY
+      _SEH2_TRY
       {
          ProbeForRead(pUnsafeStyle, dwStyleCount * sizeof(DWORD), 1);
          RtlCopyMemory(pSafeStyle,
                        pUnsafeStyle,
                        dwStyleCount * sizeof(DWORD));
       }
-      _SEH_HANDLE
+      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+      {
+         Status = _SEH2_GetExceptionCode();
+      }
+      _SEH2_END
+      if(!NT_SUCCESS(Status))
+      {
+         SetLastNtError(Status);
+         ExFreePoolWithTag(pSafeStyle, TAG_PENSTYLES);
+         return 0;
+      }
+   }
+
+   if (ulBrushStyle == BS_PATTERN)
+   {
+      _SEH2_TRY
+      {
+         ProbeForRead((PVOID)ulHatch, cjDIB, 1);
+      }
+      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
       {
-         Status = _SEH_GetExceptionCode();
+         Status = _SEH2_GetExceptionCode();
       }
-      _SEH_END
+      _SEH2_END
       if(!NT_SUCCESS(Status))
       {
          SetLastNtError(Status);
-         ExFreePool(pSafeStyle);
+         if (pSafeStyle) ExFreePoolWithTag(pSafeStyle, TAG_PENSTYLES);
          return 0;
       }
    }
 
    hPen = IntGdiExtCreatePen(dwPenStyle,
-                             ulWidth,
-                             ulBrushStyle,
-                             ulColor,
-                             ulClientHatch,
-                             ulHatch,
-                             dwStyleCount,
+                                ulWidth,
+                           ulBrushStyle,
+                                ulColor,
+                          ulClientHatch,
+                                ulHatch,
+                           dwStyleCount,
                              pSafeStyle,
-                             cjDIB,
-                             bOldStylePen,
-                             hBrush);
+                                  cjDIB,
+                           bOldStylePen,
+                                 hBrush);
 
-   if ((!hPen) && (pSafeStyle))
+   if (!hPen && pSafeStyle)
    {
-      ExFreePool(pSafeStyle);
+      ExFreePoolWithTag(pSafeStyle, TAG_PENSTYLES);
    }
-
    return hPen;
 }
 
 
+
 /* EOF */