--- /dev/null
- if (R4_MASK == rop4)
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * PURPOSE: GDI BitBlt Functions
+ * FILE: subsys/win32k/eng/bitblt.c
+ * PROGRAMER: Jason Filby
+ * Timo Kreuzer
+ * REVISION HISTORY:
+ * 2/10/1999: Created
+ */
+
+#include <win32k.h>
+
+#define NDEBUG
+#include <debug.h>
+
+typedef BOOLEAN (APIENTRY *PBLTRECTFUNC)(SURFOBJ* OutputObj,
+ SURFOBJ* InputObj,
+ SURFOBJ* Mask,
+ XLATEOBJ* ColorTranslation,
+ RECTL* OutputRect,
+ POINTL* InputPoint,
+ POINTL* MaskOrigin,
+ BRUSHOBJ* pbo,
+ POINTL* BrushOrigin,
+ ROP4 Rop4);
+
+static BOOLEAN APIENTRY
+BltMask(SURFOBJ* psoDest,
+ SURFOBJ* psoSource, // unused
+ SURFOBJ* psoMask,
+ XLATEOBJ* ColorTranslation, // unused
+ RECTL* prclDest,
+ POINTL* pptlSource, // unused
+ POINTL* pptlMask,
+ BRUSHOBJ* pbo,
+ POINTL* pptlBrush,
+ ROP4 Rop4)
+{
+ LONG x, y;
+ BYTE *pjMskLine, *pjMskCurrent;
+ BYTE fjMaskBit0, fjMaskBit;
+ /* Pattern brushes */
+ PEBRUSHOBJ pebo = NULL;
+ SURFOBJ *psoPattern = NULL;
+ PSURFACE psurfPattern;
+ ULONG PatternWidth = 0, PatternHeight = 0;
+ LONG PatternX0 = 0, PatternX = 0, PatternY = 0;
+ PFN_DIB_PutPixel fnDest_PutPixel = NULL;
+ PFN_DIB_GetPixel fnPattern_GetPixel = NULL;
+ ULONG Pattern = 0;
+ HBITMAP hbmPattern;
+
+ ASSERT(psoSource == NULL);
+ ASSERT(pptlSource == NULL);
+
+ if (psoMask == NULL)
+ {
+ return FALSE;
+ }
+
+ if (pbo && pbo->iSolidColor == 0xFFFFFFFF)
+ {
+ pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
+
+ hbmPattern = EBRUSHOBJ_pvGetEngBrush(pebo);
+ psurfPattern = SURFACE_LockSurface(hbmPattern);
+ if (psurfPattern != NULL)
+ {
+ psoPattern = &psurfPattern->SurfObj;
+ PatternWidth = psoPattern->sizlBitmap.cx;
+ PatternHeight = psoPattern->sizlBitmap.cy;
+ fnPattern_GetPixel = DibFunctionsForBitmapFormat[psoPattern->iBitmapFormat].DIB_GetPixel;
+ }
+ }
+ else
+ psurfPattern = NULL;
+
+ pjMskLine = (PBYTE)psoMask->pvScan0 + pptlMask->y * psoMask->lDelta + (pptlMask->x >> 3);
+ fjMaskBit0 = 0x80 >> (pptlMask->x & 0x07);
+
+ fnDest_PutPixel = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel;
+ if (psurfPattern)
+ {
+ PatternY = (prclDest->top - pptlBrush->y) % PatternHeight;
+ if (PatternY < 0)
+ {
+ PatternY += PatternHeight;
+ }
+ PatternX0 = (prclDest->left - pptlBrush->x) % PatternWidth;
+ if (PatternX0 < 0)
+ {
+ PatternX0 += PatternWidth;
+ }
+
+ for (y = prclDest->top; y < prclDest->bottom; y++)
+ {
+ pjMskCurrent = pjMskLine;
+ fjMaskBit = fjMaskBit0;
+ PatternX = PatternX0;
+
+ for (x = prclDest->left; x < prclDest->right; x++)
+ {
+ if (*pjMskCurrent & fjMaskBit)
+ {
+ fnDest_PutPixel(psoDest, x, y,
+ fnPattern_GetPixel(psoPattern, PatternX, PatternY));
+ }
+ fjMaskBit = _rotr8(fjMaskBit, 1);
+ pjMskCurrent += (fjMaskBit >> 7);
+ PatternX++;
+ PatternX %= PatternWidth;
+ }
+ pjMskLine += psoMask->lDelta;
+ PatternY++;
+ PatternY %= PatternHeight;
+ }
+ }
+ else
+ {
+ Pattern = pbo ? pbo->iSolidColor : 0;
+ for (y = prclDest->top; y < prclDest->bottom; y++)
+ {
+ pjMskCurrent = pjMskLine;
+ fjMaskBit = fjMaskBit0;
+
+ for (x = prclDest->left; x < prclDest->right; x++)
+ {
+ if (*pjMskCurrent & fjMaskBit)
+ {
+ fnDest_PutPixel(psoDest, x, y, Pattern);
+ }
+ fjMaskBit = _rotr8(fjMaskBit, 1);
+ pjMskCurrent += (fjMaskBit >> 7);
+ }
+ pjMskLine += psoMask->lDelta;
+ }
+ }
+
+ if (psurfPattern)
+ SURFACE_UnlockSurface(psurfPattern);
+
+ return TRUE;
+}
+
+static BOOLEAN APIENTRY
+BltPatCopy(SURFOBJ* Dest,
+ SURFOBJ* Source,
+ SURFOBJ* Mask,
+ XLATEOBJ* ColorTranslation,
+ RECTL* DestRect,
+ POINTL* SourcePoint,
+ POINTL* MaskPoint,
+ BRUSHOBJ* pbo,
+ POINTL* BrushPoint,
+ ROP4 Rop4)
+{
+ // These functions are assigned if we're working with a DIB
+ // The assigned functions depend on the bitsPerPixel of the DIB
+
+ DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_ColorFill(Dest, DestRect, pbo ? pbo->iSolidColor : 0);
+
+ return TRUE;
+}
+
+static BOOLEAN APIENTRY
+CallDibBitBlt(SURFOBJ* OutputObj,
+ SURFOBJ* InputObj,
+ SURFOBJ* Mask,
+ XLATEOBJ* ColorTranslation,
+ RECTL* OutputRect,
+ POINTL* InputPoint,
+ POINTL* MaskOrigin,
+ BRUSHOBJ* pbo,
+ POINTL* BrushOrigin,
+ ROP4 Rop4)
+{
+ BLTINFO BltInfo;
+ PEBRUSHOBJ GdiBrush = NULL;
+ SURFACE *psurfPattern;
+ BOOLEAN Result;
+ HBITMAP hbmPattern;
+
+ BltInfo.DestSurface = OutputObj;
+ BltInfo.SourceSurface = InputObj;
+ BltInfo.PatternSurface = NULL;
+ BltInfo.XlateSourceToDest = ColorTranslation;
+ BltInfo.DestRect = *OutputRect;
+ BltInfo.SourcePoint = *InputPoint;
+
+ if (ROP3_TO_ROP4(SRCCOPY) == Rop4)
+ return DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_BitBltSrcCopy(&BltInfo);
+
+ BltInfo.Brush = pbo;
+ BltInfo.BrushOrigin = *BrushOrigin;
+ BltInfo.Rop4 = Rop4;
+
+ /* Pattern brush */
+ if (ROP4_USES_PATTERN(Rop4) && pbo && pbo->iSolidColor == 0xFFFFFFFF)
+ {
+ GdiBrush = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
+ hbmPattern = EBRUSHOBJ_pvGetEngBrush(GdiBrush);
+ psurfPattern = SURFACE_LockSurface(hbmPattern);
+ if (psurfPattern)
+ {
+ BltInfo.PatternSurface = &psurfPattern->SurfObj;
+ }
+ else
+ {
+ /* FIXME - What to do here? */
+ }
+ }
+ else
+ {
+ psurfPattern = NULL;
+ }
+
+ Result = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_BitBlt(&BltInfo);
+
+ /* Pattern brush */
+ if (psurfPattern)
+ {
+ SURFACE_UnlockSurface(psurfPattern);
+ }
+
+ return Result;
+}
+
+INT __cdecl abs(INT nm);
+
+
+/*
+ * @implemented
+ */
+BOOL APIENTRY
+NtGdiEngBitBlt(
+ IN SURFOBJ *psoTrg,
+ IN SURFOBJ *psoSrc,
+ IN SURFOBJ *psoMask,
+ IN CLIPOBJ *pco,
+ IN XLATEOBJ *pxlo,
+ IN RECTL *prclTrg,
+ IN POINTL *pptlSrc,
+ IN POINTL *pptlMask,
+ IN BRUSHOBJ *pbo,
+ IN POINTL *pptlBrush,
+ IN ROP4 rop4 )
+{
+ RECTL rclTrg;
+ POINTL ptlSrc;
+ POINTL ptlMask;
+ POINTL ptlBrush;
+
+ _SEH2_TRY
+ {
+ ProbeForRead(prclTrg, sizeof(RECTL), 1);
+ RtlCopyMemory(&rclTrg,prclTrg, sizeof(RECTL));
+
+ ProbeForRead(pptlSrc, sizeof(POINTL), 1);
+ RtlCopyMemory(&ptlSrc, pptlSrc, sizeof(POINTL));
+
+ ProbeForRead(pptlMask, sizeof(POINTL), 1);
+ RtlCopyMemory(&ptlMask, pptlMask, sizeof(POINTL));
+
+ ProbeForRead(pptlBrush, sizeof(POINTL), 1);
+ RtlCopyMemory(&ptlBrush, pptlBrush, sizeof(POINTL));
+
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ _SEH2_YIELD(return FALSE);
+ }
+ _SEH2_END;
+
+ return EngBitBlt(psoTrg, psoSrc, psoMask, pco, pxlo, &rclTrg, &ptlSrc, &ptlMask, pbo, &ptlBrush, rop4);
+}
+
+/*
+ * @implemented
+ */
+BOOL APIENTRY
+EngBitBlt(SURFOBJ *DestObj,
+ SURFOBJ *SourceObj,
+ SURFOBJ *Mask,
+ CLIPOBJ *ClipRegion,
+ XLATEOBJ *ColorTranslation,
+ RECTL *DestRect,
+ POINTL *SourcePoint,
+ POINTL *MaskOrigin,
+ BRUSHOBJ *pbo,
+ POINTL *BrushOrigin,
+ ROP4 rop4)
+{
+ BYTE clippingType;
+ RECTL CombinedRect;
+ RECT_ENUM RectEnum;
+ BOOL EnumMore;
+ POINTL InputPoint;
+ RECTL InputRect;
+ RECTL OutputRect;
+ SURFOBJ* InputObj = 0;
+ SURFOBJ* OutputObj;
+ PBLTRECTFUNC BltRectFunc;
+ BOOLEAN Ret = TRUE;
+ RECTL ClipRect;
+ unsigned i;
+ POINTL Pt;
+ ULONG Direction;
+ BOOL UsesSource;
+ BOOL UsesPattern;
+ POINTL AdjustedBrushOrigin;
+
+ UsesSource = ROP4_USES_SOURCE(rop4);
+ UsesPattern = ROP4_USES_PATTERN(rop4);
+ if (R4_NOOP == rop4)
+ {
+ /* Copy destination onto itself: nop */
+ return TRUE;
+ }
+
+ OutputRect = *DestRect;
+ if (OutputRect.right < OutputRect.left)
+ {
+ OutputRect.left = DestRect->right;
+ OutputRect.right = DestRect->left;
+ }
+ if (OutputRect.bottom < OutputRect.top)
+ {
+ OutputRect.left = DestRect->right;
+ OutputRect.right = DestRect->left;
+ }
+
+ if (UsesSource)
+ {
+ if (NULL == SourcePoint)
+ {
+ return FALSE;
+ }
+
+ /* Make sure we don't try to copy anything outside the valid source
+ region */
+ InputPoint = *SourcePoint;
+ if (InputPoint.x < 0)
+ {
+ OutputRect.left -= InputPoint.x;
+ InputPoint.x = 0;
+ }
+ if (InputPoint.y < 0)
+ {
+ OutputRect.top -= InputPoint.y;
+ InputPoint.y = 0;
+ }
+ if (SourceObj->sizlBitmap.cx < InputPoint.x +
+ OutputRect.right - OutputRect.left)
+ {
+ OutputRect.right = OutputRect.left +
+ SourceObj->sizlBitmap.cx - InputPoint.x;
+ }
+ if (SourceObj->sizlBitmap.cy < InputPoint.y +
+ OutputRect.bottom - OutputRect.top)
+ {
+ OutputRect.bottom = OutputRect.top +
+ SourceObj->sizlBitmap.cy - InputPoint.y;
+ }
+
+ InputRect.left = InputPoint.x;
+ InputRect.right = InputPoint.x + (OutputRect.right - OutputRect.left);
+ InputRect.top = InputPoint.y;
+ InputRect.bottom = InputPoint.y + (OutputRect.bottom - OutputRect.top);
+
+ InputObj = SourceObj;
+ }
+ else
+ {
+ InputRect.left = 0;
+ InputRect.right = DestRect->right - DestRect->left;
+ InputRect.top = 0;
+ InputRect.bottom = DestRect->bottom - DestRect->top;
+ }
+
+ if (NULL != ClipRegion)
+ {
+ if (OutputRect.left < ClipRegion->rclBounds.left)
+ {
+ InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
+ InputPoint.x += ClipRegion->rclBounds.left - OutputRect.left;
+ OutputRect.left = ClipRegion->rclBounds.left;
+ }
+ if (ClipRegion->rclBounds.right < OutputRect.right)
+ {
+ InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
+ OutputRect.right = ClipRegion->rclBounds.right;
+ }
+ if (OutputRect.top < ClipRegion->rclBounds.top)
+ {
+ InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
+ InputPoint.y += ClipRegion->rclBounds.top - OutputRect.top;
+ OutputRect.top = ClipRegion->rclBounds.top;
+ }
+ if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
+ {
+ InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
+ OutputRect.bottom = ClipRegion->rclBounds.bottom;
+ }
+ }
+
+ /* Check for degenerate case: if height or width of OutputRect is 0 pixels
+ there's nothing to do */
+ if (OutputRect.right <= OutputRect.left ||
+ OutputRect.bottom <= OutputRect.top)
+ {
+ return TRUE;
+ }
+
+ OutputObj = DestObj;
+
+ if (BrushOrigin)
+ {
+ AdjustedBrushOrigin.x = BrushOrigin->x;
+ AdjustedBrushOrigin.y = BrushOrigin->y;
+ }
+ else
+ {
+ AdjustedBrushOrigin.x = 0;
+ AdjustedBrushOrigin.y = 0;
+ }
+
+ /* Determine clipping type */
+ if (ClipRegion == (CLIPOBJ *) NULL)
+ {
+ clippingType = DC_TRIVIAL;
+ }
+ else
+ {
+ clippingType = ClipRegion->iDComplexity;
+ }
+
- else if (ROP3_TO_ROP4(PATCOPY) == rop4)
++ /*if (R4_MASK == rop4)
+ {
+ BltRectFunc = BltMask;
+ }
++ else */if (ROP3_TO_ROP4(PATCOPY) == rop4)
+ {
+ if (pbo && pbo->iSolidColor == 0xFFFFFFFF)
+ BltRectFunc = CallDibBitBlt;
+ else
+ BltRectFunc = BltPatCopy;
+ }
+ else
+ {
+ BltRectFunc = CallDibBitBlt;
+ }
+
+
+ switch (clippingType)
+ {
+ case DC_TRIVIAL:
+ Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ColorTranslation,
+ &OutputRect, &InputPoint, MaskOrigin, pbo,
+ &AdjustedBrushOrigin, rop4);
+ break;
+ case DC_RECT:
+ /* Clip the blt to the clip rectangle */
+ ClipRect.left = ClipRegion->rclBounds.left;
+ ClipRect.right = ClipRegion->rclBounds.right;
+ ClipRect.top = ClipRegion->rclBounds.top;
+ ClipRect.bottom = ClipRegion->rclBounds.bottom;
+ if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
+ {
+ Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
+ Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
+ Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ColorTranslation,
+ &CombinedRect, &Pt, MaskOrigin, pbo,
+ &AdjustedBrushOrigin, rop4);
+ }
+ break;
+ case DC_COMPLEX:
+ Ret = TRUE;
+ if (OutputObj == InputObj)
+ {
+ if (OutputRect.top < InputPoint.y)
+ {
+ Direction = OutputRect.left < InputPoint.x ?
+ CD_RIGHTDOWN : CD_LEFTDOWN;
+ }
+ else
+ {
+ Direction = OutputRect.left < InputPoint.x ?
+ CD_RIGHTUP : CD_LEFTUP;
+ }
+ }
+ else
+ {
+ Direction = CD_ANY;
+ }
+ CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
+ do
+ {
+ EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum),
+ (PVOID) &RectEnum);
+
+ for (i = 0; i < RectEnum.c; i++)
+ {
+ ClipRect.left = RectEnum.arcl[i].left;
+ ClipRect.right = RectEnum.arcl[i].right;
+ ClipRect.top = RectEnum.arcl[i].top;
+ ClipRect.bottom = RectEnum.arcl[i].bottom;
+ if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
+ {
+ Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
+ Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
+ Ret = (*BltRectFunc)(OutputObj, InputObj, Mask,
+ ColorTranslation, &CombinedRect, &Pt,
+ MaskOrigin, pbo, &AdjustedBrushOrigin,
+ rop4) && Ret;
+ }
+ }
+ }
+ while (EnumMore);
+ break;
+ }
+
+ return Ret;
+}
+
+BOOL APIENTRY
+IntEngBitBlt(
+ SURFOBJ *psoTrg,
+ SURFOBJ *psoSrc,
+ SURFOBJ *psoMask,
+ CLIPOBJ *pco,
+ XLATEOBJ *pxlo,
+ RECTL *prclTrg,
+ POINTL *pptlSrc,
+ POINTL *pptlMask,
+ BRUSHOBJ *pbo,
+ POINTL *pptlBrush,
+ ROP4 rop4)
+{
+ SURFACE *psurfTrg;
+ SURFACE *psurfSrc = NULL;
+ BOOL bResult;
+ RECTL rclClipped;
+ RECTL rclSrc;
+// INTENG_ENTER_LEAVE EnterLeaveSource;
+// INTENG_ENTER_LEAVE EnterLeaveDest;
+ PFN_DrvBitBlt pfnBitBlt;
+
+ ASSERT(psoTrg);
+ psurfTrg = CONTAINING_RECORD(psoTrg, SURFACE, SurfObj);
+
+ /* FIXME: Should we really allow to pass non-well-ordered rects? */
+ rclClipped = *prclTrg;
+ RECTL_vMakeWellOrdered(&rclClipped);
+
+ /* Clip target rect against the bounds of the clipping region */
+ if (pco)
+ {
+ if (!RECTL_bIntersectRect(&rclClipped, &rclClipped, &pco->rclBounds))
+ {
+ /* Nothing left */
+ return TRUE;
+ }
+
+ /* Don't pass a clipobj with only a single rect */
+ if (pco->iDComplexity == DC_RECT)
+ pco = NULL;
+ }
+
+ if (ROP4_USES_SOURCE(rop4))
+ {
+ ASSERT(psoSrc);
+ psurfSrc = CONTAINING_RECORD(psoSrc, SURFACE, SurfObj);
+
+ /* Calculate source rect */
+ rclSrc.left = pptlSrc->x + rclClipped.left - prclTrg->left;
+ rclSrc.top = pptlSrc->y + rclClipped.top - prclTrg->top;
+ rclSrc.right = rclSrc.left + rclClipped.right - rclClipped.left;
+ rclSrc.bottom = rclSrc.top + rclClipped.bottom - rclClipped.top;
+ }
+ else
+ {
+ psoSrc = NULL;
+ psurfSrc = NULL;
+ }
+
+ /* Is the target surface device managed? */
+ if (psurfTrg->flags & HOOK_BITBLT)
+ {
+ /* Is the source a different device managed surface? */
+ if (psoSrc && psoSrc->hdev != psoTrg->hdev && psurfSrc->flags & HOOK_BITBLT)
+ {
+ DPRINT1("Need to copy to standard bitmap format!\n");
+ ASSERT(FALSE);
+ }
+
+ pfnBitBlt = GDIDEVFUNCS(psoTrg).BitBlt;
+ }
+
+ /* Is the source surface device managed? */
+ else if (psoSrc && psurfSrc->flags & HOOK_BITBLT)
+ {
+ pfnBitBlt = GDIDEVFUNCS(psoSrc).BitBlt;
+ }
+ else
+ {
+ pfnBitBlt = EngBitBlt;
+ }
+
+ bResult = pfnBitBlt(psoTrg,
+ psoSrc,
+ psoMask,
+ pco,
+ pxlo,
+ &rclClipped,
+ (POINTL*)&rclSrc,
+ pptlMask,
+ pbo,
+ pptlBrush,
+ rop4);
+
+ // FIXME: cleanup temp surface!
+
+ return bResult;
+}
+
+
+/**** REACTOS FONT RENDERING CODE *********************************************/
+
+/* renders the alpha mask bitmap */
+static BOOLEAN APIENTRY
+AlphaBltMask(SURFOBJ* psoDest,
+ SURFOBJ* psoSource, // unused
+ SURFOBJ* psoMask,
+ XLATEOBJ* pxloRGB2Dest,
+ XLATEOBJ* pxloBrush,
+ RECTL* prclDest,
+ POINTL* pptlSource, // unused
+ POINTL* pptlMask,
+ BRUSHOBJ* pbo,
+ POINTL* pptlBrush)
+{
+ LONG i, j, dx, dy;
+ int r, g, b;
+ ULONG Background, BrushColor, NewColor;
+ BYTE *tMask, *lMask;
+
+ ASSERT(psoSource == NULL);
+ ASSERT(pptlSource == NULL);
+
+ dx = prclDest->right - prclDest->left;
+ dy = prclDest->bottom - prclDest->top;
+
+ if (psoMask != NULL)
+ {
+ BrushColor = XLATEOBJ_iXlate(pxloBrush, pbo ? pbo->iSolidColor : 0);
+ r = (int)GetRValue(BrushColor);
+ g = (int)GetGValue(BrushColor);
+ b = (int)GetBValue(BrushColor);
+
+ tMask = (PBYTE)psoMask->pvScan0 + (pptlMask->y * psoMask->lDelta) + pptlMask->x;
+ for (j = 0; j < dy; j++)
+ {
+ lMask = tMask;
+ for (i = 0; i < dx; i++)
+ {
+ if (*lMask > 0)
+ {
+ if (*lMask == 0xff)
+ {
+ DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel(
+ psoDest, prclDest->left + i, prclDest->top + j, pbo ? pbo->iSolidColor : 0);
+ }
+ else
+ {
+ Background = DIB_GetSource(psoDest, prclDest->left + i, prclDest->top + j,
+ pxloBrush);
+
+ NewColor =
+ RGB((*lMask * (r - GetRValue(Background)) >> 8) + GetRValue(Background),
+ (*lMask * (g - GetGValue(Background)) >> 8) + GetGValue(Background),
+ (*lMask * (b - GetBValue(Background)) >> 8) + GetBValue(Background));
+
+ Background = XLATEOBJ_iXlate(pxloRGB2Dest, NewColor);
+ DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel(
+ psoDest, prclDest->left + i, prclDest->top + j, Background);
+ }
+ }
+ lMask++;
+ }
+ tMask += psoMask->lDelta;
+ }
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static
+BOOL APIENTRY
+EngMaskBitBlt(SURFOBJ *psoDest,
+ SURFOBJ *psoMask,
+ CLIPOBJ *ClipRegion,
+ XLATEOBJ *DestColorTranslation,
+ XLATEOBJ *SourceColorTranslation,
+ RECTL *DestRect,
+ POINTL *pptlMask,
+ BRUSHOBJ *pbo,
+ POINTL *BrushOrigin)
+{
+ BYTE clippingType;
+ RECTL CombinedRect;
+ RECT_ENUM RectEnum;
+ BOOL EnumMore;
+ POINTL InputPoint;
+ RECTL InputRect;
+ RECTL OutputRect;
+ POINTL Translate;
+ INTENG_ENTER_LEAVE EnterLeaveSource;
+ INTENG_ENTER_LEAVE EnterLeaveDest;
+ SURFOBJ* psoInput;
+ SURFOBJ* psoOutput;
+ BOOLEAN Ret = TRUE;
+ RECTL ClipRect;
+ unsigned i;
+ POINTL Pt;
+ ULONG Direction;
+ POINTL AdjustedBrushOrigin;
+
+ ASSERT(psoMask);
+
+ if (pptlMask)
+ {
+ InputRect.left = pptlMask->x;
+ InputRect.right = pptlMask->x + (DestRect->right - DestRect->left);
+ InputRect.top = pptlMask->y;
+ InputRect.bottom = pptlMask->y + (DestRect->bottom - DestRect->top);
+ }
+ else
+ {
+ InputRect.left = 0;
+ InputRect.right = DestRect->right - DestRect->left;
+ InputRect.top = 0;
+ InputRect.bottom = DestRect->bottom - DestRect->top;
+ }
+
+ OutputRect = *DestRect;
+ if (NULL != ClipRegion)
+ {
+ if (OutputRect.left < ClipRegion->rclBounds.left)
+ {
+ InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
+ OutputRect.left = ClipRegion->rclBounds.left;
+ }
+ if (ClipRegion->rclBounds.right < OutputRect.right)
+ {
+ InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
+ OutputRect.right = ClipRegion->rclBounds.right;
+ }
+ if (OutputRect.top < ClipRegion->rclBounds.top)
+ {
+ InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
+ OutputRect.top = ClipRegion->rclBounds.top;
+ }
+ if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
+ {
+ InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
+ OutputRect.bottom = ClipRegion->rclBounds.bottom;
+ }
+ }
+
+ if (! IntEngEnter(&EnterLeaveSource, psoMask, &InputRect, TRUE, &Translate, &psoInput))
+ {
+ return FALSE;
+ }
+
+ InputPoint.x = InputRect.left + Translate.x;
+ InputPoint.y = InputRect.top + Translate.y;
+
+ /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
+ nothing to do */
+ if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
+ {
+ IntEngLeave(&EnterLeaveSource);
+ return TRUE;
+ }
+
+ if (! IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &psoOutput))
+ {
+ IntEngLeave(&EnterLeaveSource);
+ return FALSE;
+ }
+
+ OutputRect.left = DestRect->left + Translate.x;
+ OutputRect.right = DestRect->right + Translate.x;
+ OutputRect.top = DestRect->top + Translate.y;
+ OutputRect.bottom = DestRect->bottom + Translate.y;
+
+ if (BrushOrigin)
+ {
+ AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
+ AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
+ }
+ else
+ AdjustedBrushOrigin = Translate;
+
+ // Determine clipping type
+ if (ClipRegion == (CLIPOBJ *) NULL)
+ {
+ clippingType = DC_TRIVIAL;
+ } else {
+ clippingType = ClipRegion->iDComplexity;
+ }
+
+ switch (clippingType)
+ {
+ case DC_TRIVIAL:
+ if (psoMask->iBitmapFormat == BMF_8BPP)
+ Ret = AlphaBltMask(psoOutput, NULL , psoInput, DestColorTranslation, SourceColorTranslation,
+ &OutputRect, NULL, &InputPoint, pbo, &AdjustedBrushOrigin);
+ else
+ Ret = BltMask(psoOutput, NULL, psoInput, DestColorTranslation,
+ &OutputRect, NULL, &InputPoint, pbo, &AdjustedBrushOrigin,
+ R4_MASK);
+ break;
+ case DC_RECT:
+ // Clip the blt to the clip rectangle
+ ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
+ ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
+ ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
+ ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
+ if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
+ {
+ Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
+ Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
+ if (psoMask->iBitmapFormat == BMF_8BPP)
+ {
+ Ret = AlphaBltMask(psoOutput, NULL, psoInput, DestColorTranslation, SourceColorTranslation,
+ &CombinedRect, NULL, &Pt, pbo, &AdjustedBrushOrigin);
+ }
+ else
+ {
+ Ret = BltMask(psoOutput, NULL, psoInput, DestColorTranslation,
+ &CombinedRect, NULL, &Pt, pbo, &AdjustedBrushOrigin, R4_MASK);
+ }
+ }
+ break;
+ case DC_COMPLEX:
+ Ret = TRUE;
+ if (psoOutput == psoInput)
+ {
+ if (OutputRect.top < InputPoint.y)
+ {
+ Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
+ }
+ else
+ {
+ Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
+ }
+ }
+ else
+ {
+ Direction = CD_ANY;
+ }
+ CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
+ do
+ {
+ EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
+
+ for (i = 0; i < RectEnum.c; i++)
+ {
+ ClipRect.left = RectEnum.arcl[i].left + Translate.x;
+ ClipRect.right = RectEnum.arcl[i].right + Translate.x;
+ ClipRect.top = RectEnum.arcl[i].top + Translate.y;
+ ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
+ if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
+ {
+ Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
+ Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
+ if (psoMask->iBitmapFormat == BMF_8BPP)
+ {
+ Ret = AlphaBltMask(psoOutput, NULL, psoInput,
+ DestColorTranslation,
+ SourceColorTranslation,
+ &CombinedRect, NULL, &Pt, pbo,
+ &AdjustedBrushOrigin) && Ret;
+ }
+ else
+ {
+ Ret = BltMask(psoOutput, NULL, psoInput,
+ DestColorTranslation, &CombinedRect, NULL,
+ &Pt, pbo, &AdjustedBrushOrigin,
+ R4_MASK) && Ret;
+ }
+ }
+ }
+ }
+ while (EnumMore);
+ break;
+ }
+
+
+ IntEngLeave(&EnterLeaveDest);
+ IntEngLeave(&EnterLeaveSource);
+
+ return Ret;
+}
+
+BOOL APIENTRY
+IntEngMaskBlt(SURFOBJ *psoDest,
+ SURFOBJ *psoMask,
+ CLIPOBJ *ClipRegion,
+ XLATEOBJ *DestColorTranslation,
+ XLATEOBJ *SourceColorTranslation,
+ RECTL *DestRect,
+ POINTL *pptlMask,
+ BRUSHOBJ *pbo,
+ POINTL *BrushOrigin)
+{
+ BOOLEAN ret;
+ RECTL OutputRect;
+ POINTL InputPoint;
+ SURFACE *psurfDest;
+
+ ASSERT(psoMask);
+
+ if (pptlMask)
+ {
+ InputPoint = *pptlMask;
+ }
+
+ /* Clip against the bounds of the clipping region so we won't try to write
+ * outside the surface */
+ if (NULL != ClipRegion)
+ {
+ if (!RECTL_bIntersectRect(&OutputRect, DestRect, &ClipRegion->rclBounds))
+ {
+ return TRUE;
+ }
+ InputPoint.x += OutputRect.left - DestRect->left;
+ InputPoint.y += OutputRect.top - DestRect->top;
+ }
+ else
+ {
+ OutputRect = *DestRect;
+ }
+
+ /* No success yet */
+ ret = FALSE;
+ ASSERT(psoDest);
+ psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
+
+ /* Dummy BitBlt to let driver know that it should flush its changes.
+ This should really be done using a call to DrvSynchronizeSurface,
+ but the VMware driver doesn't hook that call. */
+ IntEngBitBlt(psoDest, NULL, psoMask, ClipRegion, DestColorTranslation,
+ DestRect, pptlMask, pptlMask, pbo, BrushOrigin,
+ R4_NOOP);
+
+ ret = EngMaskBitBlt(psoDest, psoMask, ClipRegion, DestColorTranslation, SourceColorTranslation,
+ &OutputRect, &InputPoint, pbo, BrushOrigin);
+
+ /* Dummy BitBlt to let driver know that something has changed. */
+ IntEngBitBlt(psoDest, NULL, psoMask, ClipRegion, DestColorTranslation,
+ DestRect, pptlMask, pptlMask, pbo, BrushOrigin,
+ R4_NOOP);
+
+ return ret;
+}
+
+/* EOF */
--- /dev/null
+ /*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * PURPOSE: XLATEOBJ structures and functions
+ * FILE: subsystem/win32/win32k/eng/objects.h
+ * PROGRAMER: Timo Kreuzer
+ *
+ */
+
+#include <include/palette.h>
+
+struct _EXLATEOBJ;
+
+typedef ULONG (FASTCALL *PFN_XLATE)(struct _EXLATEOBJ *pexlo, ULONG iColor);
+
+typedef struct _EXLATEOBJ
+{
+ XLATEOBJ xlo;
+
+ PFN_XLATE pfnXlate;
+
+ PPALETTE ppalSrc;
+ PPALETTE ppalDst;
+ PPALETTE ppalDstDc;
+
+ HANDLE hColorTransform;
+
+ union
+ {
+ ULONG aulXlate[6];
+ struct
+ {
+ ULONG ulRedMask;
+ ULONG ulGreenMask;
+ ULONG ulBlueMask;
+ ULONG ulRedShift;
+ ULONG ulGreenShift;
+ ULONG ulBlueShift;
+ };
+ };
+} EXLATEOBJ, *PEXLATEOBJ;
+
+void
+DbgCmpXlate(XLATEOBJ *pxlo1, XLATEOBJ *pxlo2);
+
+VOID NTAPI EXLATEOBJ_vInitialize(PEXLATEOBJ pexlo, PALETTE *ppalSrc, PALETTE *ppalDst, ULONG, ULONG, ULONG);
+VOID NTAPI EXLATEOBJ_vInitXlateFromDCs(PEXLATEOBJ pexlo, PDC pdcSrc, PDC pdcDst);
+VOID NTAPI EXLATEOBJ_vInitSrcMonoXlate(PEXLATEOBJ pexlo, PPALETTE ppalDst, ULONG Color0, ULONG Color1);
+VOID NTAPI EXLATEOBJ_vCleanup(PEXLATEOBJ pexlo);
+
++extern XLATEOBJ* gpxloTrivial;
++
+//#define XLATEOBJ_iXlate(pxo, Color) ((EXLATEOBJ*)pxo)->pfnXlate(pxo, Color)
--- /dev/null
- #define NDEBUG
+/*
+ * ReactOS W32 Subsystem
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * We handle two types of cursors/icons:
+ * - Private
+ * Loaded without LR_SHARED flag
+ * Private to a process
+ * Can be deleted by calling NtDestroyCursorIcon()
+ * CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc set to NULL
+ * - Shared
+ * Loaded with LR_SHARED flag
+ * Possibly shared by multiple processes
+ * Immune to NtDestroyCursorIcon()
+ * CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc are valid
+ * There's a M:N relationship between processes and (shared) cursor/icons.
+ * A process can have multiple cursor/icons and a cursor/icon can be used
+ * by multiple processes. To keep track of this we keep a list of all
+ * cursor/icons (CurIconList) and per cursor/icon we keep a list of
+ * CURICON_PROCESS structs starting at CurIcon->ProcessList.
+ */
+
+#include <win32k.h>
+
- BOOL Ret = FALSE;
- HBITMAP hbmMask, hbmColor;
- BITMAP bmpColor, bm;
++//#define NDEBUG
+#include <debug.h>
+
+static PAGED_LOOKASIDE_LIST gProcessLookasideList;
+static LIST_ENTRY gCurIconList;
+
+SYSTEM_CURSORINFO gSysCursorInfo;
+
+BOOL
+InitCursorImpl()
+{
+ ExInitializePagedLookasideList(&gProcessLookasideList,
+ NULL,
+ NULL,
+ 0,
+ sizeof(CURICON_PROCESS),
+ TAG_DIB,
+ 128);
+ InitializeListHead(&gCurIconList);
+
+ gSysCursorInfo.Enabled = FALSE;
+ gSysCursorInfo.ButtonsDown = 0;
+ gSysCursorInfo.CursorClipInfo.IsClipped = FALSE;
+ gSysCursorInfo.LastBtnDown = 0;
+ gSysCursorInfo.CurrentCursorObject = NULL;
+ gSysCursorInfo.ShowingCursor = 0;
+ gSysCursorInfo.ClickLockActive = FALSE;
+ gSysCursorInfo.ClickLockTime = 0;
+
+ return TRUE;
+}
+
+PSYSTEM_CURSORINFO
+IntGetSysCursorInfo()
+{
+ return &gSysCursorInfo;
+}
+
+/* This function creates a reference for the object! */
+PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
+{
+ PCURICON_OBJECT CurIcon;
+
+ if (!hCurIcon)
+ {
+ SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
+ return NULL;
+ }
+
+ CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, otCursorIcon);
+ if (!CurIcon)
+ {
+ /* we never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
+ SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
+ return NULL;
+ }
+
+ ASSERT(CurIcon->head.cLockObj >= 1);
+ return CurIcon;
+}
+
+HCURSOR
+FASTCALL
+UserSetCursor(
+ PCURICON_OBJECT NewCursor,
+ BOOL ForceChange)
+{
+ PSYSTEM_CURSORINFO CurInfo;
+ PCURICON_OBJECT OldCursor;
+ HCURSOR hOldCursor = (HCURSOR)0;
+ HDC hdcScreen;
+ BOOL bResult;
+
+ CurInfo = IntGetSysCursorInfo();
+
+ OldCursor = CurInfo->CurrentCursorObject;
+ if (OldCursor)
+ {
+ hOldCursor = (HCURSOR)OldCursor->Self;
+ }
+
+ /* Is the new cursor the same as the old cursor? */
+ if (OldCursor == NewCursor)
+ {
+ /* Nothing to to do in this case */
+ return hOldCursor;
+ }
+
+ /* Get the screen DC */
+ if(!(hdcScreen = IntGetScreenDC()))
+ {
+ return (HCURSOR)0;
+ }
+
+ /* Do we have a new cursor? */
+ if (NewCursor)
+ {
+ UserReferenceObject(NewCursor);
+
+ CurInfo->ShowingCursor = 1;
+ CurInfo->CurrentCursorObject = NewCursor;
+
+ /* Call GDI to set the new screen cursor */
+ bResult = GreSetPointerShape(hdcScreen,
+ NewCursor->IconInfo.hbmMask,
+ NewCursor->IconInfo.hbmColor,
+ NewCursor->IconInfo.xHotspot,
+ NewCursor->IconInfo.yHotspot,
+ gpsi->ptCursor.x,
+ gpsi->ptCursor.y);
+
+
+ }
+ else
+ {
+ /* Check if were diplaying a cursor */
+ if (OldCursor && CurInfo->ShowingCursor)
+ {
+ /* Remove the cursor */
+ GreMovePointer(hdcScreen, -1, -1);
+ DPRINT("Removing pointer!\n");
+ }
+
+ CurInfo->CurrentCursorObject = NULL;
+ CurInfo->ShowingCursor = 0;
+ }
+
+ /* OldCursor is not in use anymore */
+ if (OldCursor)
+ {
+ UserDereferenceObject(OldCursor);
+ }
+
+ /* Return handle of the old cursor */
+ return hOldCursor;
+}
+
+BOOL UserSetCursorPos( INT x, INT y, BOOL SendMouseMoveMsg)
+{
+ PWINDOW_OBJECT DesktopWindow;
+ PSYSTEM_CURSORINFO CurInfo;
+ HDC hDC;
+ MSG Msg;
+
+ if(!(hDC = IntGetScreenDC()))
+ {
+ return FALSE;
+ }
+
+ CurInfo = IntGetSysCursorInfo();
+
+ DesktopWindow = UserGetDesktopWindow();
+
+ if (DesktopWindow)
+ {
+ if(x >= DesktopWindow->Wnd->rcClient.right)
+ x = DesktopWindow->Wnd->rcClient.right - 1;
+ if(y >= DesktopWindow->Wnd->rcClient.bottom)
+ y = DesktopWindow->Wnd->rcClient.bottom - 1;
+ }
+
+ if(x < 0)
+ x = 0;
+ if(y < 0)
+ y = 0;
+
+ //Clip cursor position
+ if(CurInfo->CursorClipInfo.IsClipped)
+ {
+ if(x >= (LONG)CurInfo->CursorClipInfo.Right)
+ x = (LONG)CurInfo->CursorClipInfo.Right - 1;
+ if(x < (LONG)CurInfo->CursorClipInfo.Left)
+ x = (LONG)CurInfo->CursorClipInfo.Left;
+ if(y >= (LONG)CurInfo->CursorClipInfo.Bottom)
+ y = (LONG)CurInfo->CursorClipInfo.Bottom - 1;
+ if(y < (LONG)CurInfo->CursorClipInfo.Top)
+ y = (LONG)CurInfo->CursorClipInfo.Top;
+ }
+
+ //Store the new cursor position
+ gpsi->ptCursor.x = x;
+ gpsi->ptCursor.y = y;
+
+ //Move the mouse pointer
+ GreMovePointer(hDC, x, y);
+
+ if (!SendMouseMoveMsg)
+ return TRUE;
+
+ //Generate a mouse move message
+ Msg.message = WM_MOUSEMOVE;
+ Msg.wParam = CurInfo->ButtonsDown;
+ Msg.lParam = MAKELPARAM(x, y);
+ Msg.pt = gpsi->ptCursor;
+ MsqInsertSystemMessage(&Msg);
+
+ return TRUE;
+}
+
+/* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
+ * User32 macro NtUserShowCursor */
+int UserShowCursor(BOOL bShow)
+{
+ PSYSTEM_CURSORINFO CurInfo = IntGetSysCursorInfo();
+ HDC hdcScreen;
+
+ if (!(hdcScreen = IntGetScreenDC()))
+ {
+ return 0; /* No mouse */
+ }
+
+ if (bShow == FALSE)
+ {
+ /* Check if were diplaying a cursor */
+ if (CurInfo->ShowingCursor == 1)
+ {
+ /* Remove the pointer */
+ GreMovePointer(hdcScreen, -1, -1);
+ DPRINT("Removing pointer!\n");
+ }
+ CurInfo->ShowingCursor--;
+ }
+ else
+ {
+ if (CurInfo->ShowingCursor == 0)
+ {
+ /*Show the pointer*/
+ GreMovePointer(hdcScreen, gpsi->ptCursor.x, gpsi->ptCursor.y);
+ }
+ CurInfo->ShowingCursor++;
+ }
+
+ return CurInfo->ShowingCursor;
+}
+
+/*
+ * We have to register that this object is in use by the current
+ * process. The only way to do that seems to be to walk the list
+ * of cursor/icon objects starting at W32Process->CursorIconListHead.
+ * If the object is already present in the list, we don't have to do
+ * anything, if it's not present we add it and inc the ProcessCount
+ * in the object. Having to walk the list kind of sucks, but that's
+ * life...
+ */
+static BOOLEAN FASTCALL
+ReferenceCurIconByProcess(PCURICON_OBJECT CurIcon)
+{
+ PPROCESSINFO Win32Process;
+ PCURICON_PROCESS Current;
+
+ Win32Process = PsGetCurrentProcessWin32Process();
+
+ LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
+ {
+ if (Current->Process == Win32Process)
+ {
+ /* Already registered for this process */
+ return TRUE;
+ }
+ }
+
+ /* Not registered yet */
+ Current = ExAllocateFromPagedLookasideList(&gProcessLookasideList);
+ if (NULL == Current)
+ {
+ return FALSE;
+ }
+ InsertHeadList(&CurIcon->ProcessList, &Current->ListEntry);
+ Current->Process = Win32Process;
+
+ return TRUE;
+}
+
+PCURICON_OBJECT FASTCALL
+IntFindExistingCurIconObject(HMODULE hModule,
+ HRSRC hRsrc, LONG cx, LONG cy)
+{
+ PCURICON_OBJECT CurIcon;
+
+ LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry)
+ {
+
+ // if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon))) //<- huh????
+// UserReferenceObject( CurIcon);
+// {
+ if ((CurIcon->hModule == hModule) && (CurIcon->hRsrc == hRsrc))
+ {
+ if (cx && ((cx != CurIcon->Size.cx) || (cy != CurIcon->Size.cy)))
+ {
+// UserDereferenceObject(CurIcon);
+ continue;
+ }
+ if (! ReferenceCurIconByProcess(CurIcon))
+ {
+ return NULL;
+ }
+
+ return CurIcon;
+ }
+// }
+// UserDereferenceObject(CurIcon);
+
+ }
+
+ return NULL;
+}
+
+PCURICON_OBJECT
+IntCreateCurIconHandle()
+{
+ PCURICON_OBJECT CurIcon;
+ HANDLE hCurIcon;
+
+ CurIcon = UserCreateObject(gHandleTable, NULL, &hCurIcon, otCursorIcon, sizeof(CURICON_OBJECT));
+
+ if (!CurIcon)
+ {
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+
+ CurIcon->Self = hCurIcon;
+ InitializeListHead(&CurIcon->ProcessList);
+
+ if (! ReferenceCurIconByProcess(CurIcon))
+ {
+ DPRINT1("Failed to add process\n");
+ UserDeleteObject(hCurIcon, otCursorIcon);
+ UserDereferenceObject(CurIcon);
+ return NULL;
+ }
+
+ InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
+
+ return CurIcon;
+}
+
+BOOLEAN FASTCALL
+IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, BOOL ProcessCleanup)
+{
+ PSYSTEM_CURSORINFO CurInfo;
+ HBITMAP bmpMask, bmpColor;
+ BOOLEAN Ret;
+ PCURICON_PROCESS Current = NULL;
+ PPROCESSINFO W32Process = PsGetCurrentProcessWin32Process();
+
+ /* Private objects can only be destroyed by their own process */
+ if (NULL == CurIcon->hModule)
+ {
+ ASSERT(CurIcon->ProcessList.Flink->Flink == &CurIcon->ProcessList);
+ Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS, ListEntry);
+ if (Current->Process != W32Process)
+ {
+ DPRINT1("Trying to destroy private icon/cursor of another process\n");
+ return FALSE;
+ }
+ }
+ else if (! ProcessCleanup)
+ {
+ DPRINT("Trying to destroy shared icon/cursor\n");
+ return FALSE;
+ }
+
+ /* Now find this process in the list of processes referencing this object and
+ remove it from that list */
+ LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
+ {
+ if (Current->Process == W32Process)
+ {
+ RemoveEntryList(&Current->ListEntry);
+ break;
+ }
+ }
+
+ ExFreeToPagedLookasideList(&gProcessLookasideList, Current);
+
+ /* If there are still processes referencing this object we can't destroy it yet */
+ if (! IsListEmpty(&CurIcon->ProcessList))
+ {
+ return TRUE;
+ }
+
+
+ if (! ProcessCleanup)
+ {
+ RemoveEntryList(&CurIcon->ListEntry);
+ }
+
+ CurInfo = IntGetSysCursorInfo();
+
+ if (CurInfo->CurrentCursorObject == CurIcon)
+ {
+ /* Hide the cursor if we're destroying the current cursor */
+ UserSetCursor(NULL, TRUE);
+ }
+
+ bmpMask = CurIcon->IconInfo.hbmMask;
+ bmpColor = CurIcon->IconInfo.hbmColor;
+
+ /* delete bitmaps */
+ if (bmpMask)
+ {
+ GDIOBJ_SetOwnership(bmpMask, PsGetCurrentProcess());
+ GreDeleteObject(bmpMask);
+ CurIcon->IconInfo.hbmMask = NULL;
+ }
+ if (bmpColor)
+ {
+ GDIOBJ_SetOwnership(bmpColor, PsGetCurrentProcess());
+ GreDeleteObject(bmpColor);
+ CurIcon->IconInfo.hbmColor = NULL;
+ }
+
+ /* We were given a pointer, no need to keep the reference anylonger! */
+ UserDereferenceObject(CurIcon);
+ Ret = UserDeleteObject(CurIcon->Self, otCursorIcon);
+
+ return Ret;
+}
+
+VOID FASTCALL
+IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process)
+{
+ PCURICON_OBJECT CurIcon, tmp;
+ PCURICON_PROCESS ProcessData;
+
+ LIST_FOR_EACH_SAFE(CurIcon, tmp, &gCurIconList, CURICON_OBJECT, ListEntry)
+ {
+ UserReferenceObject(CurIcon);
+ // if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon)))
+ {
+ LIST_FOR_EACH(ProcessData, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
+ {
+ if (Win32Process == ProcessData->Process)
+ {
+ RemoveEntryList(&CurIcon->ListEntry);
+ IntDestroyCurIconObject(CurIcon, TRUE);
+ CurIcon = NULL;
+ break;
+ }
+ }
+
+// UserDereferenceObject(Object);
+ }
+
+ if (CurIcon)
+ {
+ UserDereferenceObject(CurIcon);
+ }
+ }
+
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+APIENTRY
+NtUserGetIconInfo(
+ HANDLE hCurIcon,
+ PICONINFO IconInfo,
+ PUNICODE_STRING lpInstName, // optional
+ PUNICODE_STRING lpResName, // optional
+ LPDWORD pbpp, // optional
+ BOOL bInternal)
+{
+ ICONINFO ii;
+ PCURICON_OBJECT CurIcon;
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL Ret = FALSE;
+ DWORD colorBpp = 0;
+
+ DPRINT("Enter NtUserGetIconInfo\n");
+ UserEnterExclusive();
+
+ if (!IconInfo)
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ goto leave;
+ }
+
+ if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
+ {
+ goto leave;
+ }
+
+ RtlCopyMemory(&ii, &CurIcon->IconInfo, sizeof(ICONINFO));
+
+ /* Copy bitmaps */
+ ii.hbmMask = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmMask);
+ ii.hbmColor = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmColor);
+
+ if (pbpp)
+ {
+ PSURFACE psurfBmp;
+
+ psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor);
+ if (psurfBmp)
+ {
+ colorBpp = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
+ SURFACE_UnlockSurface(psurfBmp);
+ }
+ }
+
+ /* Copy fields */
+ _SEH2_TRY
+ {
+ ProbeForWrite(IconInfo, sizeof(ICONINFO), 1);
+ RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO));
+
+ if (pbpp)
+ {
+ ProbeForWrite(pbpp, sizeof(DWORD), 1);
+ *pbpp = colorBpp;
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+
+ if (NT_SUCCESS(Status))
+ Ret = TRUE;
+ else
+ SetLastNtError(Status);
+
+ UserDereferenceObject(CurIcon);
+
+leave:
+ DPRINT("Leave NtUserGetIconInfo, ret=%i\n", Ret);
+ UserLeave();
+
+ return Ret;
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+APIENTRY
+NtUserGetIconSize(
+ HANDLE hCurIcon,
+ UINT istepIfAniCur,
+ PLONG plcx, // &size.cx
+ PLONG plcy) // &size.cy
+{
+ PCURICON_OBJECT CurIcon;
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL bRet = FALSE;
+
+ DPRINT("Enter NtUserGetIconSize\n");
+ UserEnterExclusive();
+
+ if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
+ {
+ goto cleanup;
+ }
+
+ _SEH2_TRY
+ {
+ ProbeForWrite(plcx, sizeof(LONG), 1);
+ RtlCopyMemory(plcx, &CurIcon->Size.cx, sizeof(LONG));
+ ProbeForWrite(plcy, sizeof(LONG), 1);
+ RtlCopyMemory(plcy, &CurIcon->Size.cy, sizeof(LONG));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+
+ if (NT_SUCCESS(Status))
+ bRet = TRUE;
+ else
+ SetLastNtError(Status); // maybe not, test this
+
+ UserDereferenceObject(CurIcon);
+
+cleanup:
+ DPRINT("Leave NtUserGetIconSize, ret=%i\n", bRet);
+ UserLeave();
+ return bRet;
+}
+
+
+/*
+ * @unimplemented
+ */
+DWORD
+APIENTRY
+NtUserGetCursorFrameInfo(
+ DWORD Unknown0,
+ DWORD Unknown1,
+ DWORD Unknown2,
+ DWORD Unknown3)
+{
+ UNIMPLEMENTED
+
+ return 0;
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+APIENTRY
+NtUserGetCursorInfo(
+ PCURSORINFO pci)
+{
+ CURSORINFO SafeCi;
+ PSYSTEM_CURSORINFO CurInfo;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PCURICON_OBJECT CurIcon;
+ BOOL Ret = FALSE;
+ DECLARE_RETURN(BOOL);
+
+ DPRINT("Enter NtUserGetCursorInfo\n");
+ UserEnterExclusive();
+
+ CurInfo = IntGetSysCursorInfo();
+ CurIcon = (PCURICON_OBJECT)CurInfo->CurrentCursorObject;
+
+ SafeCi.cbSize = sizeof(CURSORINFO);
+ SafeCi.flags = ((CurInfo->ShowingCursor && CurIcon) ? CURSOR_SHOWING : 0);
+ SafeCi.hCursor = (CurIcon ? (HCURSOR)CurIcon->Self : (HCURSOR)0);
+
+ SafeCi.ptScreenPos = gpsi->ptCursor;
+
+ _SEH2_TRY
+ {
+ if (pci->cbSize == sizeof(CURSORINFO))
+ {
+ ProbeForWrite(pci, sizeof(CURSORINFO), 1);
+ RtlCopyMemory(pci, &SafeCi, sizeof(CURSORINFO));
+ Ret = TRUE;
+ }
+ else
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ }
+
+ RETURN(Ret);
+
+CLEANUP:
+ DPRINT("Leave NtUserGetCursorInfo, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+BOOL
+APIENTRY
+UserClipCursor(
+ RECTL *prcl)
+{
+ /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
+ PSYSTEM_CURSORINFO CurInfo;
+ PWINDOW_OBJECT DesktopWindow = NULL;
+
+ CurInfo = IntGetSysCursorInfo();
+
+ DesktopWindow = UserGetDesktopWindow();
+
+ if (prcl != NULL &&
+ (prcl->right > prcl->left) &&
+ (prcl->bottom > prcl->top) &&
+ DesktopWindow != NULL)
+ {
+ CurInfo->CursorClipInfo.IsClipped = TRUE;
+ CurInfo->CursorClipInfo.Left = max(prcl->left, DesktopWindow->Wnd->rcWindow.left);
+ CurInfo->CursorClipInfo.Top = max(prcl->top, DesktopWindow->Wnd->rcWindow.top);
+ CurInfo->CursorClipInfo.Right = min(prcl->right, DesktopWindow->Wnd->rcWindow.right);
+ CurInfo->CursorClipInfo.Bottom = min(prcl->bottom, DesktopWindow->Wnd->rcWindow.bottom);
+
+ UserSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y, FALSE);
+ }
+ else
+ {
+ CurInfo->CursorClipInfo.IsClipped = FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+APIENTRY
+NtUserClipCursor(
+ RECTL *prcl)
+{
+ /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
+ RECTL rclLocal;
+ BOOL bResult;
+
+ if (prcl)
+ {
+ _SEH2_TRY
+ {
+ /* Probe and copy rect */
+ ProbeForRead(prcl, sizeof(RECTL), 1);
+ rclLocal = *prcl;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ _SEH2_YIELD(return FALSE;)
+ }
+ _SEH2_END
+
+ prcl = &rclLocal;
+ }
+
+ UserEnterExclusive();
+
+ /* Call the internal function */
+ bResult = UserClipCursor(prcl);
+
+ UserLeave();
+
+ return bResult;
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+APIENTRY
+NtUserDestroyCursor(
+ HANDLE hCurIcon,
+ DWORD Unknown)
+{
+ PCURICON_OBJECT CurIcon;
+ BOOL ret;
+ DECLARE_RETURN(BOOL);
+
+ DPRINT("Enter NtUserDestroyCursorIcon\n");
+ UserEnterExclusive();
+
+ if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
+ {
+ RETURN(FALSE);
+ }
+
+ ret = IntDestroyCurIconObject(CurIcon, FALSE);
+ /* Note: IntDestroyCurIconObject will remove our reference for us! */
+
+ RETURN(ret);
+
+CLEANUP:
+ DPRINT("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+
+/*
+ * @implemented
+ */
+HICON
+APIENTRY
+NtUserFindExistingCursorIcon(
+ HMODULE hModule,
+ HRSRC hRsrc,
+ LONG cx,
+ LONG cy)
+{
+ PCURICON_OBJECT CurIcon;
+ HANDLE Ret = (HANDLE)0;
+ DECLARE_RETURN(HICON);
+
+ DPRINT("Enter NtUserFindExistingCursorIcon\n");
+ UserEnterExclusive();
+
+ CurIcon = IntFindExistingCurIconObject(hModule, hRsrc, cx, cy);
+ if (CurIcon)
+ {
+ Ret = CurIcon->Self;
+
+// IntReleaseCurIconObject(CurIcon);//faxme: is this correct? does IntFindExistingCurIconObject add a ref?
+ RETURN(Ret);
+ }
+
+ SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
+ RETURN((HANDLE)0);
+
+CLEANUP:
+ DPRINT("Leave NtUserFindExistingCursorIcon, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+APIENTRY
+NtUserGetClipCursor(
+ RECTL *lpRect)
+{
+ /* FIXME - check if process has WINSTA_READATTRIBUTES */
+ PSYSTEM_CURSORINFO CurInfo;
+ RECTL Rect;
+ NTSTATUS Status;
+ DECLARE_RETURN(BOOL);
+
+ DPRINT("Enter NtUserGetClipCursor\n");
+ UserEnterExclusive();
+
+ if (!lpRect)
+ RETURN(FALSE);
+
+ CurInfo = IntGetSysCursorInfo();
+ if (CurInfo->CursorClipInfo.IsClipped)
+ {
+ Rect.left = CurInfo->CursorClipInfo.Left;
+ Rect.top = CurInfo->CursorClipInfo.Top;
+ Rect.right = CurInfo->CursorClipInfo.Right;
+ Rect.bottom = CurInfo->CursorClipInfo.Bottom;
+ }
+ else
+ {
+ Rect.left = 0;
+ Rect.top = 0;
+ Rect.right = UserGetSystemMetrics(SM_CXSCREEN);
+ Rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
+ }
+
+ Status = MmCopyToCaller(lpRect, &Rect, sizeof(RECT));
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN(FALSE);
+ }
+
+ RETURN(TRUE);
+
+CLEANUP:
+ DPRINT("Leave NtUserGetClipCursor, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+
+/*
+ * @implemented
+ */
+HCURSOR
+APIENTRY
+NtUserSetCursor(
+ HCURSOR hCursor)
+{
+ PCURICON_OBJECT CurIcon;
+ HICON OldCursor;
+ DECLARE_RETURN(HCURSOR);
+
+ DPRINT("Enter NtUserSetCursor\n");
+ UserEnterExclusive();
+
+ if (hCursor)
+ {
+ if (!(CurIcon = UserGetCurIconObject(hCursor)))
+ {
+ RETURN(NULL);
+ }
+ }
+ else
+ {
+ CurIcon = NULL;
+ }
+
+ OldCursor = UserSetCursor(CurIcon, FALSE);
+
+ if (CurIcon)
+ {
+ UserDereferenceObject(CurIcon);
+ }
+
+ RETURN(OldCursor);
+
+CLEANUP:
+ DPRINT("Leave NtUserSetCursor, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+APIENTRY
+NtUserSetCursorContents(
+ HANDLE hCurIcon,
+ PICONINFO UnsafeIconInfo)
+{
+ PCURICON_OBJECT CurIcon;
+ ICONINFO IconInfo;
+ PSURFACE psurfBmp;
+ NTSTATUS Status;
+ BOOL Ret = FALSE;
+ DECLARE_RETURN(BOOL);
+
+ DPRINT("Enter NtUserSetCursorContents\n");
+ UserEnterExclusive();
+
+ if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
+ {
+ RETURN(FALSE);
+ }
+
+ /* Copy fields */
+ Status = MmCopyFromCaller(&IconInfo, UnsafeIconInfo, sizeof(ICONINFO));
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ goto done;
+ }
+
+ /* Delete old bitmaps */
+ if ((CurIcon->IconInfo.hbmColor)
+ && (CurIcon->IconInfo.hbmColor != IconInfo.hbmColor))
+ {
+ GreDeleteObject(CurIcon->IconInfo.hbmColor);
+ }
+ if ((CurIcon->IconInfo.hbmMask)
+ && CurIcon->IconInfo.hbmMask != IconInfo.hbmMask)
+ {
+ GreDeleteObject(CurIcon->IconInfo.hbmMask);
+ }
+
+ /* Copy new IconInfo field */
+ CurIcon->IconInfo = IconInfo;
+
+ psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor);
+ if (psurfBmp)
+ {
+ CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
+ CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
+ SURFACE_UnlockSurface(psurfBmp);
+ GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
+ }
+ else
+ {
+ psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask);
+ if (!psurfBmp)
+ goto done;
+
+ CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
+ CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy / 2;
+
+ SURFACE_UnlockSurface(psurfBmp);
+ GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
+ }
+
+ Ret = TRUE;
+
+done:
+
+ if (CurIcon)
+ {
+ UserDereferenceObject(CurIcon);
+ }
+ RETURN(Ret);
+
+CLEANUP:
+ DPRINT("Leave NtUserSetCursorContents, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+
+/*
+ * @implemented
+ */
+#if 0
+BOOL
+APIENTRY
+NtUserSetCursorIconData(
+ HANDLE Handle,
+ HMODULE hModule,
+ PUNICODE_STRING pstrResName,
+ PICONINFO pIconInfo)
+{
+ PCURICON_OBJECT CurIcon;
+ PSURFACE psurfBmp;
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL Ret = FALSE;
+ DECLARE_RETURN(BOOL);
+
+ DPRINT("Enter NtUserSetCursorIconData\n");
+ UserEnterExclusive();
+
+ if (!(CurIcon = UserGetCurIconObject(Handle)))
+ {
+ RETURN(FALSE);
+ }
+
+ CurIcon->hModule = hModule;
+ CurIcon->hRsrc = NULL; //hRsrc;
+ CurIcon->hGroupRsrc = NULL; //hGroupRsrc;
+
+ _SEH2_TRY
+ {
+ ProbeForRead(pIconInfo, sizeof(ICONINFO), 1);
+ RtlCopyMemory(&CurIcon->IconInfo, pIconInfo, sizeof(ICONINFO));
+
+ CurIcon->IconInfo.hbmMask = BITMAP_CopyBitmap(pIconInfo->hbmMask);
+ CurIcon->IconInfo.hbmColor = BITMAP_CopyBitmap(pIconInfo->hbmColor);
+
+ if (CurIcon->IconInfo.hbmColor)
+ {
+ if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor)))
+ {
+ CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
+ CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
+ SURFACE_UnlockSurface(psurfBmp);
+ GDIOBJ_SetOwnership(GdiHandleTable, CurIcon->IconInfo.hbmMask, NULL);
+ }
+ }
+ if (CurIcon->IconInfo.hbmMask)
+ {
+ if (CurIcon->IconInfo.hbmColor == NULL)
+ {
+ if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask)))
+ {
+ CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
+ CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
+ SURFACE_UnlockSurface(psurfBmp);
+ }
+ }
+ GDIOBJ_SetOwnership(GdiHandleTable, CurIcon->IconInfo.hbmMask, NULL);
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+
+ if (!NT_SUCCESS(Status))
+ SetLastNtError(Status);
+ else
+ Ret = TRUE;
+
+ UserDereferenceObject(CurIcon);
+ RETURN(Ret);
+
+CLEANUP:
+ DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+#else
+BOOL
+APIENTRY
+NtUserSetCursorIconData(
+ HANDLE hCurIcon,
+ PBOOL fIcon,
+ POINT *Hotspot,
+ HMODULE hModule,
+ HRSRC hRsrc,
+ HRSRC hGroupRsrc)
+{
+ PCURICON_OBJECT CurIcon;
+ NTSTATUS Status;
+ POINT SafeHotspot;
+ BOOL Ret = FALSE;
+ DECLARE_RETURN(BOOL);
+
+ DPRINT("Enter NtUserSetCursorIconData\n");
+ UserEnterExclusive();
+
+ if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
+ {
+ RETURN(FALSE);
+ }
+
+ CurIcon->hModule = hModule;
+ CurIcon->hRsrc = hRsrc;
+ CurIcon->hGroupRsrc = hGroupRsrc;
+
+ /* Copy fields */
+ if (fIcon)
+ {
+ Status = MmCopyFromCaller(&CurIcon->IconInfo.fIcon, fIcon, sizeof(BOOL));
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ goto done;
+ }
+ }
+ else
+ {
+ if (!Hotspot)
+ Ret = TRUE;
+ }
+
+ if (Hotspot)
+ {
+ Status = MmCopyFromCaller(&SafeHotspot, Hotspot, sizeof(POINT));
+ if (NT_SUCCESS(Status))
+ {
+ CurIcon->IconInfo.xHotspot = SafeHotspot.x;
+ CurIcon->IconInfo.yHotspot = SafeHotspot.y;
+
+ Ret = TRUE;
+ }
+ else
+ SetLastNtError(Status);
+ }
+
+ if (!fIcon && !Hotspot)
+ {
+ Ret = TRUE;
+ }
+
+done:
+ if(Ret)
+ {
+ /* This icon is shared now */
+ GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
+ if(CurIcon->IconInfo.hbmColor)
+ {
+ GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
+ }
+ }
+ UserDereferenceObject(CurIcon);
+ RETURN(Ret);
+
+
+CLEANUP:
+ DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+#endif
+
+/*
+ * @unimplemented
+ */
+BOOL
+APIENTRY
+NtUserSetSystemCursor(
+ HCURSOR hcur,
+ DWORD id)
+{
+ return FALSE;
+}
+
+/* Mostly inspired from wine code */
+BOOL
+UserDrawIconEx(
+ HDC hDc,
+ INT xLeft,
+ INT yTop,
+ PCURICON_OBJECT pIcon,
+ INT cxWidth,
+ INT cyHeight,
+ UINT istepIfAniCur,
+ HBRUSH hbrFlickerFreeDraw,
+ UINT diFlags)
+{
- INT iOldBkColor = 0, iOldTxtColor = 0;
-
- HDC hMemDC, hDestDC = hDc;
- HGDIOBJ hOldOffBrush = 0;
- HGDIOBJ hOldOffBmp = 0;
- HBITMAP hTmpBmp = 0, hOffBmp = 0;
- BOOL bAlpha = FALSE;
- INT x=xLeft, y=yTop;
-
- hbmMask = pIcon->IconInfo.hbmMask;
- hbmColor = pIcon->IconInfo.hbmColor;
++ PSURFACE psurfColor = NULL, psurfMask, psurfDst = NULL;
++ HGDIOBJ hObjs[3];
++ PGDIOBJ pObjs[3];
+ BOOL DoFlickerFree;
- if (!hbmMask || !IntGdiGetObject(hbmMask, sizeof(BITMAP), (PVOID)&bm))
++ PDC pdc;
++ HSURF hsurfDst = NULL;
++ RECTL rcSrc, rcDst;
++ CLIPOBJ clo, *pclo;
++ EXLATEOBJ exlo;
++ BOOL bAlpha = FALSE, Ret = FALSE, bStretch;
+
+ if (istepIfAniCur)
+ DPRINT1("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
+
- if (hbmColor && !IntGdiGetObject(hbmColor, sizeof(BITMAP), (PVOID)&bmpColor))
++ DPRINT("Flags : 0x%08x\n", diFlags);
++
++ hObjs[0] = pIcon->IconInfo.hbmMask;
++ hObjs[1] = pIcon->IconInfo.hbmColor;
++ hObjs[2] = hDc;
++ GDIOBJ_LockMultipleObjs(3, hObjs, pObjs);
++ psurfMask = pObjs[0];
++ psurfColor = pObjs[1];
++ pdc = pObjs[2];
++
++ if (!pIcon->IconInfo.hbmMask
++ || !psurfMask)
+ {
++ DPRINT1("No hbmMask?!\n");
++ if(pdc) DC_UnlockDc(pdc);
++ if(psurfColor) SURFACE_UnlockSurface(psurfColor);
+ return FALSE;
+ }
+
- if(!(hMemDC = NtGdiCreateCompatibleDC(hDc)))
++ if (pIcon->IconInfo.hbmColor
++ && !psurfColor)
+ {
++ DPRINT1("Unable to lock the color Bitmap?!\n");
++ SURFACE_UnlockSurface(psurfMask);
++ if(pdc) DC_UnlockDc(pdc);
+ return FALSE;
+ }
+
- DPRINT1("NtGdiCreateCompatibleDC failed!\n");
++ if(!psurfColor)
++ {
++ DPRINT("Monochrome Icon\n");
++ psurfColor = psurfMask;
++ RECTL_vSetRect(&rcSrc, 0, pIcon->Size.cy, pIcon->Size.cx, 2*pIcon->Size.cy);
++ }
++ else
+ {
- if (hbmColor
- && (bmpColor.bmBitsPixel == 32)
++ DPRINT("Color Icon\n");
++ RECTL_vSetRect(&rcSrc, 0, 0, pIcon->Size.cx, pIcon->Size.cy);
++ }
++
++ if(!pdc)
++ {
++ SetLastWin32Error(ERROR_INVALID_PARAMETER);
++ SURFACE_UnlockSurface(psurfMask);
++ if(psurfColor != psurfMask) SURFACE_UnlockSurface(psurfColor);
++ DPRINT1("Invalid DC!\n");
+ return FALSE;
+ }
+
+ /* Check for alpha */
- SURFACE *psurfOff = NULL;
++ if ((BitsPerFormat(psurfColor->SurfObj.iBitmapFormat) == 32)
+ && (diFlags & DI_IMAGE))
+ {
- psurfOff = SURFACE_LockSurface(hbmColor);
- if (psurfOff)
+ PFN_DIB_GetPixel fnSource_GetPixel = NULL;
+ INT i, j;
+
+ /* In order to correctly display 32 bit icons Windows first scans the image,
+ because information about transparency is not stored in any image's headers */
- fnSource_GetPixel = DibFunctionsForBitmapFormat[psurfOff->SurfObj.iBitmapFormat].DIB_GetPixel;
- if (fnSource_GetPixel)
++ fnSource_GetPixel = DibFunctionsForBitmapFormat[psurfColor->SurfObj.iBitmapFormat].DIB_GetPixel;
++ if (fnSource_GetPixel)
+ {
- for (i = 0; i < psurfOff->SurfObj.sizlBitmap.cx; i++)
++ for (i = 0; i < psurfColor->SurfObj.sizlBitmap.cx; i++)
+ {
- for (j = 0; j < psurfOff->SurfObj.sizlBitmap.cy; j++)
- {
- bAlpha = ((BYTE)(fnSource_GetPixel(&psurfOff->SurfObj, i, j) >> 24) & 0xff);
- if (bAlpha)
- break;
- }
++ for (j = 0; j < psurfColor->SurfObj.sizlBitmap.cy; j++)
+ {
- SURFACE_UnlockSurface(psurfOff);
++ bAlpha = ((BYTE)(fnSource_GetPixel(&psurfColor->SurfObj, i, j) >> 24) & 0xff);
+ if (bAlpha)
+ break;
+ }
++ if (bAlpha)
++ break;
+ }
- hDestDC = NtGdiCreateCompatibleDC(hDc);
- if(!hDestDC)
+ }
+ }
+
+ if (!cxWidth)
+ cxWidth = ((diFlags & DI_DEFAULTSIZE) ?
+ UserGetSystemMetrics(SM_CXICON) : pIcon->Size.cx);
+
+ if (!cyHeight)
+ cyHeight = ((diFlags & DI_DEFAULTSIZE) ?
+ UserGetSystemMetrics(SM_CYICON) : pIcon->Size.cy);
+
++ /* Check stretching */
++ bStretch = (pIcon->Size.cx != cxWidth) || (pIcon->Size.cy != cyHeight);
++
+ DoFlickerFree = (hbrFlickerFreeDraw &&
+ (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH));
+
+ if (DoFlickerFree)
+ {
- DPRINT1("NtGdiCreateCompatibleDC failed!\n");
- Ret = FALSE;
- goto Cleanup ;
++ EBRUSHOBJ ebo;
++ PBRUSH pBrush ;
++ POINTL ptBrushOrig;
++
++ pBrush = BRUSH_LockBrush(hbrFlickerFreeDraw);
++ if(!pBrush)
+ {
- hOffBmp = NtGdiCreateCompatibleBitmap(hDc, cxWidth, cyHeight);
- if(!hOffBmp)
++ SetLastWin32Error(ERROR_INVALID_PARAMETER);
++ DPRINT1("Invalid brush!\n");
++ goto cleanup;
+ }
- DPRINT1("NtGdiCreateCompatibleBitmap failed!\n");
- goto Cleanup ;
++
++ hsurfDst = IntCreateCompatibleBitmap(pdc, cxWidth, cyHeight);
++ if(!hsurfDst)
+ {
- hOldOffBmp = NtGdiSelectBitmap(hDestDC, hOffBmp);
- hOldOffBrush = NtGdiSelectBrush(hDestDC, hbrFlickerFreeDraw);
- NtGdiPatBlt(hDestDC, 0, 0, cxWidth, cyHeight, PATCOPY);
- NtGdiSelectBrush(hDestDC, hOldOffBrush);
- x=y=0;
++ DPRINT1("Error : Failed to allocate the offscreen surface\n");
++ goto cleanup;
+ }
- /* Set Background/foreground colors */
- iOldTxtColor = IntGdiSetTextColor(hDc, 0); //black
- iOldBkColor = IntGdiSetBkColor(hDc, 0x00FFFFFF); //white
++ psurfDst = SURFACE_LockSurface(hsurfDst);
++ if(!psurfDst)
++ {
++ DPRINT1("Error : Failed to lock the offScreen bitmap\n");
++ goto cleanup;
++ }
++ RECTL_vSetRect(&rcDst, 0, 0, cxWidth, cyHeight);
++
++ ptBrushOrig.x = pBrush->ptOrigin.x;
++ ptBrushOrig.y = pBrush->ptOrigin.y;
++
++ EBRUSHOBJ_vInit(&ebo, pBrush, pdc);
++
++ clo.iDComplexity = DC_TRIVIAL;
++ pclo = &clo;
++
++ IntEngBitBlt(&psurfDst->SurfObj, NULL, NULL, pclo, NULL, &rcDst, NULL,
++ NULL, &ebo.BrushObject, &ptBrushOrig, ROP3_TO_ROP4(PATCOPY));
++
++ EBRUSHOBJ_vCleanup(&ebo);
++ BRUSH_UnlockBrush(pBrush);
+ }
++ else
++ {
++ RECT rcBmp;
++ RECTL_vSetRect(&rcDst, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
++ IntLPtoDP(pdc, (LPPOINT)&rcDst, 2);
++ RECTL_vOffsetRect(&rcDst, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
++
++ DC_vPrepareDCsForBlit(pdc, rcDst, NULL, rcDst );
+
- PSURFACE psurf;
++ if (pdc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
++ DC_vUpdateFillBrush(pdc);
++
++ psurfDst = pdc->dclevel.pSurface;
++ pclo = pdc->rosdc.CombinedClip;
++ RECTL_vSetRect(&rcBmp, 0, 0, psurfDst->SurfObj.sizlBitmap.cx, psurfDst->SurfObj.sizlBitmap.cy);
++ if(!RECTL_bIntersectRect(&rcDst, &rcDst, &rcBmp))
++ {
++ Ret = FALSE;
++ goto done;
++ }
++ }
++
++ /* Optimization : use directly the palette of the DC,
++ * so we XLATE only once, and then we directly copy bits */
++ EXLATEOBJ_vInitialize(&exlo, psurfColor->ppal, pdc->dclevel.pSurface->ppal, 0, 0, 0xFFFFFFFF);
+
+ if(bAlpha && (diFlags & DI_IMAGE))
+ {
+ BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
+ BYTE Alpha;
+ INT i, j;
- hMemBmp = BITMAP_CopyBitmap(hbmColor);
++ PSURFACE psurf = NULL;
+ PBYTE ptr ;
+ HBITMAP hMemBmp = NULL;
+
- SURFACE_UnlockSurface(psurf);
-
- hTmpBmp = NtGdiSelectBitmap(hMemDC, hMemBmp);
-
- Ret = NtGdiAlphaBlend(hDestDC,
- x,
- y,
- cxWidth,
- cyHeight,
- hMemDC,
- 0,
- 0,
- pIcon->Size.cx,
- pIcon->Size.cy,
- pixelblend,
- NULL);
- NtGdiSelectBitmap(hMemDC, hTmpBmp);
++ hMemBmp = BITMAP_CopyBitmap(pIcon->IconInfo.hbmColor);
+ if(!hMemBmp)
+ {
+ DPRINT1("BITMAP_CopyBitmap failed!");
+ goto CleanupAlpha;
+ }
+
+ psurf = SURFACE_LockSurface(hMemBmp);
+ if(!psurf)
+ {
+ DPRINT1("SURFACE_LockSurface failed!\n");
+ goto CleanupAlpha;
+ }
+
+ /* premultiply with the alpha channel value */
+ for (i = 0; i < psurf->SurfObj.sizlBitmap.cy; i++)
+ {
+ ptr = (PBYTE)psurf->SurfObj.pvScan0 + i*psurf->SurfObj.lDelta;
+ for (j = 0; j < psurf->SurfObj.sizlBitmap.cx; j++)
+ {
+ Alpha = ptr[3];
+ ptr[0] = (ptr[0] * Alpha) / 0xff;
+ ptr[1] = (ptr[1] * Alpha) / 0xff;
+ ptr[2] = (ptr[2] * Alpha) / 0xff;
+
+ ptr += 4;
+ }
+ }
+
- if (diFlags & DI_MASK)
++ DPRINT("Performing alpha blending\n");
++ Ret = IntEngAlphaBlend(&psurfDst->SurfObj,
++ &psurf->SurfObj,
++ pclo,
++ &exlo.xlo,
++ &rcDst,
++ &rcSrc,
++ (BLENDOBJ*)&pixelblend);
++
+ CleanupAlpha:
++ if(psurf) SURFACE_UnlockSurface(psurf);
+ if(hMemBmp) NtGdiDeleteObjectApp(hMemBmp);
+ if(Ret) goto done;
++ else DPRINT1("IntEngAlphaBlend failed!\n");
+ }
+
- hTmpBmp = NtGdiSelectBitmap(hMemDC, hbmMask);
- NtGdiStretchBlt(hDestDC,
- x,
- y,
- cxWidth,
- cyHeight,
- hMemDC,
- 0,
- 0,
- pIcon->Size.cx,
- pIcon->Size.cy,
- SRCAND,
- 0);
- NtGdiSelectBitmap(hMemDC, hTmpBmp);
- }
-
- if(diFlags & DI_IMAGE)
- {
- if (hbmColor)
++ if (diFlags & DI_IMAGE)
+ {
- DWORD rop = (diFlags & DI_MASK) ? SRCINVERT : SRCCOPY ;
- hTmpBmp = NtGdiSelectBitmap(hMemDC, hbmColor);
- NtGdiStretchBlt(hDestDC,
- x,
- y,
- cxWidth,
- cyHeight,
- hMemDC,
- 0,
- 0,
- pIcon->Size.cx,
- pIcon->Size.cy,
- rop,
- 0);
- NtGdiSelectBitmap(hMemDC, hTmpBmp);
++ POINTL ptMaskOrig = {0,0};
++ if(bStretch)
+ {
- /* Mask bitmap holds the information in its second half */
- DWORD rop = (diFlags & DI_MASK) ? SRCINVERT : SRCCOPY ;
- hTmpBmp = NtGdiSelectBitmap(hMemDC, hbmMask);
- NtGdiStretchBlt(hDestDC,
- x,
- y,
- cxWidth,
- cyHeight,
- hMemDC,
- 0,
- pIcon->Size.cy,
- pIcon->Size.cx,
- pIcon->Size.cy,
- rop,
- 0);
- NtGdiSelectBitmap(hMemDC, hTmpBmp);
++ DPRINT("Stretching\n");
++ Ret = IntEngStretchBlt(&psurfDst->SurfObj,
++ &psurfColor->SurfObj,
++ (diFlags & DI_MASK) ? &psurfMask->SurfObj : NULL,
++ pclo,
++ &exlo.xlo,
++ &rcDst,
++ &rcSrc,
++ (diFlags & DI_MASK) ? &ptMaskOrig : NULL,
++ NULL,
++ NULL,
++ (diFlags & DI_MASK) ? R4_MASK : ROP3_TO_ROP4(SRCCOPY));
++ if(!Ret) DPRINT1("IntEngStretchBlt Failed\n");
+ }
+ else
+ {
- if(hDestDC != hDc)
++ DPRINT("Blting\n");
++ Ret = IntEngBitBlt(&psurfDst->SurfObj,
++ &psurfColor->SurfObj,
++ (diFlags & DI_MASK) ? &psurfMask->SurfObj : NULL,
++ pclo,
++ &exlo.xlo,
++ &rcDst,
++ (PPOINTL)&rcSrc,
++ (diFlags & DI_MASK) ? &ptMaskOrig : NULL,
++ NULL,
++ NULL,
++ (diFlags & DI_MASK) ? R4_MASK : ROP3_TO_ROP4(SRCCOPY));
++ if(!Ret) DPRINT1("IntEngBitBlt Failed\n");
+ }
+ }
++ else
++ {
++ DPRINT1("Uh? Calling DrawIcon without anything to draw? diFlags %d\n", diFlags);
++ }
+
+done:
- NtGdiBitBlt(hDc, xLeft, yTop, cxWidth, cyHeight, hDestDC, 0, 0, SRCCOPY, 0, 0);
- }
++ if(DoFlickerFree && Ret)
+ {
- /* Restore foreground and background colors */
- IntGdiSetBkColor(hDc, iOldBkColor);
- IntGdiSetTextColor(hDc, iOldTxtColor);
++ POINTL ptSrc = {0,0};
++ RECTL rcBmp;
++
++ RECTL_vSetRect(&rcDst, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
++
++ IntLPtoDP(pdc, (LPPOINT)&rcDst, 2);
++
++ RECTL_vOffsetRect(&rcDst, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
++ DC_vPrepareDCsForBlit(pdc, rcDst, NULL, rcDst );
++
++ if (pdc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
++ DC_vUpdateFillBrush(pdc);
++
++ RECTL_vSetRect(&rcBmp, 0, 0,
++ pdc->dclevel.pSurface->SurfObj.sizlBitmap.cx,
++ pdc->dclevel.pSurface->SurfObj.sizlBitmap.cy);
+
- Ret = TRUE ;
++ if(RECTL_bIntersectRect(&rcDst, &rcDst, &rcBmp))
++ {
++ /* Copy everything */
++ DPRINT("Copying bits from offscreen buffer\n");
++ Ret = IntEngCopyBits(&pdc->dclevel.pSurface->SurfObj,
++ &psurfDst->SurfObj,
++ pdc->rosdc.CombinedClip,
++ gpxloTrivial,
++ &rcDst,
++ &ptSrc);
++ if(!Ret) DPRINT1("IntEngCopyBits Failed\n");
++ }
++
++ DC_vFinishBlit(pdc, NULL);
++ }
+
- Cleanup:
- NtGdiDeleteObjectApp(hMemDC);
- if(hDestDC != hDc)
++ if(!DoFlickerFree) DC_vFinishBlit(pdc, NULL);
++ EXLATEOBJ_vCleanup(&exlo);
+
- if(hOldOffBmp) NtGdiSelectBitmap(hDestDC, hOldOffBmp);
- NtGdiDeleteObjectApp(hDestDC);
- if(hOffBmp) NtGdiDeleteObjectApp(hOffBmp);
++cleanup:
++ if(psurfColor != psurfMask)
++ SURFACE_UnlockSurface(psurfColor);
++ SURFACE_UnlockSurface(psurfMask);
++ if(hsurfDst)
+ {
- return Ret;
++ if(psurfDst) SURFACE_UnlockSurface(psurfDst);
++ GreDeleteObject(hsurfDst);
+ }
++ DC_UnlockDc(pdc);
+
++ DPRINT("return %s\n", Ret ? "TRUE" : "FALSE") ;
++
++ return Ret ;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+APIENTRY
+NtUserDrawIconEx(
+ HDC hdc,
+ int xLeft,
+ int yTop,
+ HICON hIcon,
+ int cxWidth,
+ int cyHeight,
+ UINT istepIfAniCur,
+ HBRUSH hbrFlickerFreeDraw,
+ UINT diFlags,
+ BOOL bMetaHDC, // When TRUE, GDI functions need to be handled in User32!
+ PVOID pDIXData)
+{
+ PCURICON_OBJECT pIcon;
+ BOOL Ret;
+
+ DPRINT("Enter NtUserDrawIconEx\n");
+ UserEnterExclusive();
+
+ if (!(pIcon = UserGetCurIconObject(hIcon)))
+ {
+ DPRINT1("UserGetCurIconObject() failed!\n");
+ UserLeave();
+ return FALSE;
+ }
+
+ Ret = UserDrawIconEx(hdc,
+ xLeft,
+ yTop,
+ pIcon,
+ cxWidth,
+ cyHeight,
+ istepIfAniCur,
+ hbrFlickerFreeDraw,
+ diFlags);
+
+ UserDereferenceObject(pIcon);
+
+ UserLeave();
+ return Ret;
+}
+
--- /dev/null
- HBITMAP hOldMaskBitmap, hBitmap2, hOldBitmap2, hBitmap3, hOldBitmap3;
- HDC hDCMask, hDC1, hDC2;
- static const DWORD ROP3Table[256] =
- {
- 0x00000042, 0x00010289,
- 0x00020C89, 0x000300AA,
- 0x00040C88, 0x000500A9,
- 0x00060865, 0x000702C5,
- 0x00080F08, 0x00090245,
- 0x000A0329, 0x000B0B2A,
- 0x000C0324, 0x000D0B25,
- 0x000E08A5, 0x000F0001,
- 0x00100C85, 0x001100A6,
- 0x00120868, 0x001302C8,
- 0x00140869, 0x001502C9,
- 0x00165CCA, 0x00171D54,
- 0x00180D59, 0x00191CC8,
- 0x001A06C5, 0x001B0768,
- 0x001C06CA, 0x001D0766,
- 0x001E01A5, 0x001F0385,
- 0x00200F09, 0x00210248,
- 0x00220326, 0x00230B24,
- 0x00240D55, 0x00251CC5,
- 0x002606C8, 0x00271868,
- 0x00280369, 0x002916CA,
- 0x002A0CC9, 0x002B1D58,
- 0x002C0784, 0x002D060A,
- 0x002E064A, 0x002F0E2A,
- 0x0030032A, 0x00310B28,
- 0x00320688, 0x00330008,
- 0x003406C4, 0x00351864,
- 0x003601A8, 0x00370388,
- 0x0038078A, 0x00390604,
- 0x003A0644, 0x003B0E24,
- 0x003C004A, 0x003D18A4,
- 0x003E1B24, 0x003F00EA,
- 0x00400F0A, 0x00410249,
- 0x00420D5D, 0x00431CC4,
- 0x00440328, 0x00450B29,
- 0x004606C6, 0x0047076A,
- 0x00480368, 0x004916C5,
- 0x004A0789, 0x004B0605,
- 0x004C0CC8, 0x004D1954,
- 0x004E0645, 0x004F0E25,
- 0x00500325, 0x00510B26,
- 0x005206C9, 0x00530764,
- 0x005408A9, 0x00550009,
- 0x005601A9, 0x00570389,
- 0x00580785, 0x00590609,
- 0x005A0049, 0x005B18A9,
- 0x005C0649, 0x005D0E29,
- 0x005E1B29, 0x005F00E9,
- 0x00600365, 0x006116C6,
- 0x00620786, 0x00630608,
- 0x00640788, 0x00650606,
- 0x00660046, 0x006718A8,
- 0x006858A6, 0x00690145,
- 0x006A01E9, 0x006B178A,
- 0x006C01E8, 0x006D1785,
- 0x006E1E28, 0x006F0C65,
- 0x00700CC5, 0x00711D5C,
- 0x00720648, 0x00730E28,
- 0x00740646, 0x00750E26,
- 0x00761B28, 0x007700E6,
- 0x007801E5, 0x00791786,
- 0x007A1E29, 0x007B0C68,
- 0x007C1E24, 0x007D0C69,
- 0x007E0955, 0x007F03C9,
- 0x008003E9, 0x00810975,
- 0x00820C49, 0x00831E04,
- 0x00840C48, 0x00851E05,
- 0x008617A6, 0x008701C5,
- 0x008800C6, 0x00891B08,
- 0x008A0E06, 0x008B0666,
- 0x008C0E08, 0x008D0668,
- 0x008E1D7C, 0x008F0CE5,
- 0x00900C45, 0x00911E08,
- 0x009217A9, 0x009301C4,
- 0x009417AA, 0x009501C9,
- 0x00960169, 0x0097588A,
- 0x00981888, 0x00990066,
- 0x009A0709, 0x009B07A8,
- 0x009C0704, 0x009D07A6,
- 0x009E16E6, 0x009F0345,
- 0x00A000C9, 0x00A11B05,
- 0x00A20E09, 0x00A30669,
- 0x00A41885, 0x00A50065,
- 0x00A60706, 0x00A707A5,
- 0x00A803A9, 0x00A90189,
- 0x00AA0029, 0x00AB0889,
- 0x00AC0744, 0x00AD06E9,
- 0x00AE0B06, 0x00AF0229,
- 0x00B00E05, 0x00B10665,
- 0x00B21974, 0x00B30CE8,
- 0x00B4070A, 0x00B507A9,
- 0x00B616E9, 0x00B70348,
- 0x00B8074A, 0x00B906E6,
- 0x00BA0B09, 0x00BB0226,
- 0x00BC1CE4, 0x00BD0D7D,
- 0x00BE0269, 0x00BF08C9,
- 0x00C000CA, 0x00C11B04,
- 0x00C21884, 0x00C3006A,
- 0x00C40E04, 0x00C50664,
- 0x00C60708, 0x00C707AA,
- 0x00C803A8, 0x00C90184,
- 0x00CA0749, 0x00CB06E4,
- 0x00CC0020, 0x00CD0888,
- 0x00CE0B08, 0x00CF0224,
- 0x00D00E0A, 0x00D1066A,
- 0x00D20705, 0x00D307A4,
- 0x00D41D78, 0x00D50CE9,
- 0x00D616EA, 0x00D70349,
- 0x00D80745, 0x00D906E8,
- 0x00DA1CE9, 0x00DB0D75,
- 0x00DC0B04, 0x00DD0228,
- 0x00DE0268, 0x00DF08C8,
- 0x00E003A5, 0x00E10185,
- 0x00E20746, 0x00E306EA,
- 0x00E40748, 0x00E506E5,
- 0x00E61CE8, 0x00E70D79,
- 0x00E81D74, 0x00E95CE6,
- 0x00EA02E9, 0x00EB0849,
- 0x00EC02E8, 0x00ED0848,
- 0x00EE0086, 0x00EF0A08,
- 0x00F00021, 0x00F10885,
- 0x00F20B05, 0x00F3022A,
- 0x00F40B0A, 0x00F50225,
- 0x00F60265, 0x00F708C5,
- 0x00F802E5, 0x00F90845,
- 0x00FA0089, 0x00FB0A09,
- 0x00FC008A, 0x00FD0A0A,
- 0x00FE02A9, 0x00FF0062,
- };
+/*
+* ReactOS W32 Subsystem
+* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
+*
+* 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+/* $Id: bitmaps.c 28300 2007-08-12 15:20:09Z tkreuzer $ */
+
+#include <win32k.h>
+
+#define NDEBUG
+#include <debug.h>
+
+
+
+BOOL APIENTRY
+NtGdiAlphaBlend(
+ HDC hDCDest,
+ LONG XOriginDest,
+ LONG YOriginDest,
+ LONG WidthDest,
+ LONG HeightDest,
+ HDC hDCSrc,
+ LONG XOriginSrc,
+ LONG YOriginSrc,
+ LONG WidthSrc,
+ LONG HeightSrc,
+ BLENDFUNCTION BlendFunc,
+ HANDLE hcmXform)
+{
+ PDC DCDest;
+ PDC DCSrc;
+ HDC ahDC[2];
+ PGDIOBJ apObj[2];
+ SURFACE *BitmapDest, *BitmapSrc;
+ RECTL DestRect, SourceRect;
+ BOOL bResult;
+ EXLATEOBJ exlo;
+ BLENDOBJ BlendObj;
+ BlendObj.BlendFunction = BlendFunc;
+
+ if (WidthDest < 0 || HeightDest < 0 || WidthSrc < 0 || HeightSrc < 0)
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ DPRINT("Locking DCs\n");
+ ahDC[0] = hDCDest;
+ ahDC[1] = hDCSrc ;
+ GDIOBJ_LockMultipleObjs(2, ahDC, apObj);
+ DCDest = apObj[0];
+ DCSrc = apObj[1];
+
+ if ((NULL == DCDest) || (NULL == DCSrc))
+ {
+ DPRINT1("Invalid dc handle (dest=0x%08x, src=0x%08x) passed to NtGdiAlphaBlend\n", hDCDest, hDCSrc);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ if(DCSrc) GDIOBJ_UnlockObjByPtr(&DCSrc->BaseObject);
+ if(DCDest) GDIOBJ_UnlockObjByPtr(&DCDest->BaseObject);
+ return FALSE;
+ }
+
+ if (DCDest->dctype == DC_TYPE_INFO || DCDest->dctype == DCTYPE_INFO)
+ {
+ GDIOBJ_UnlockObjByPtr(&DCSrc->BaseObject);
+ GDIOBJ_UnlockObjByPtr(&DCDest->BaseObject);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+
+ DestRect.left = XOriginDest;
+ DestRect.top = YOriginDest;
+ DestRect.right = XOriginDest + WidthDest;
+ DestRect.bottom = YOriginDest + HeightDest;
+ IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
+
+ DestRect.left += DCDest->ptlDCOrig.x;
+ DestRect.top += DCDest->ptlDCOrig.y;
+ DestRect.right += DCDest->ptlDCOrig.x;
+ DestRect.bottom += DCDest->ptlDCOrig.y;
+
+ SourceRect.left = XOriginSrc;
+ SourceRect.top = YOriginSrc;
+ SourceRect.right = XOriginSrc + WidthSrc;
+ SourceRect.bottom = YOriginSrc + HeightSrc;
+ IntLPtoDP(DCSrc, (LPPOINT)&SourceRect, 2);
+
+ SourceRect.left += DCSrc->ptlDCOrig.x;
+ SourceRect.top += DCSrc->ptlDCOrig.y;
+ SourceRect.right += DCSrc->ptlDCOrig.x;
+ SourceRect.bottom += DCSrc->ptlDCOrig.y;
+
+ if (!DestRect.right ||
+ !DestRect.bottom ||
+ !SourceRect.right ||
+ !SourceRect.bottom)
+ {
+ GDIOBJ_UnlockObjByPtr(&DCSrc->BaseObject);
+ GDIOBJ_UnlockObjByPtr(&DCDest->BaseObject);
+ return TRUE;
+ }
+
+ /* Prepare DCs for blit */
+ DPRINT("Preparing DCs for blit\n");
+ DC_vPrepareDCsForBlit(DCDest, DestRect, DCSrc, SourceRect);
+
+ /* Determine surfaces to be used in the bitblt */
+ BitmapDest = DCDest->dclevel.pSurface;
+ if (!BitmapDest)
+ {
+ bResult = FALSE ;
+ goto leave ;
+ }
+
+ BitmapSrc = DCSrc->dclevel.pSurface;
+ if (!BitmapSrc)
+ {
+ bResult = FALSE;
+ goto leave;
+ }
+
+ /* Create the XLATEOBJ. */
+ EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
+
+ /* Perform the alpha blend operation */
+ DPRINT("Performing the alpha Blend\n");
+ bResult = IntEngAlphaBlend(&BitmapDest->SurfObj,
+ &BitmapSrc->SurfObj,
+ DCDest->rosdc.CombinedClip,
+ &exlo.xlo,
+ &DestRect,
+ &SourceRect,
+ &BlendObj);
+
+ EXLATEOBJ_vCleanup(&exlo);
+leave :
+ DPRINT("Finishing blit\n");
+ DC_vFinishBlit(DCDest, DCSrc);
+ GDIOBJ_UnlockObjByPtr(&DCSrc->BaseObject);
+ GDIOBJ_UnlockObjByPtr(&DCDest->BaseObject);
+
+ return bResult;
+}
+
+BOOL APIENTRY
+NtGdiBitBlt(
+ HDC hDCDest,
+ INT XDest,
+ INT YDest,
+ INT Width,
+ INT Height,
+ HDC hDCSrc,
+ INT XSrc,
+ INT YSrc,
+ DWORD ROP,
+ IN DWORD crBackColor,
+ IN FLONG fl)
+{
+ PDC DCDest;
+ PDC DCSrc = NULL;
+ HDC ahDC[2];
+ PGDIOBJ apObj[2];
+ PDC_ATTR pdcattr = NULL;
+ SURFACE *BitmapDest, *BitmapSrc = NULL;
+ RECTL DestRect, SourceRect;
+ POINTL SourcePoint;
+ BOOL Status = FALSE;
+ EXLATEOBJ exlo;
+ XLATEOBJ *XlateObj = NULL;
+ BOOL UsesSource = ROP3_USES_SOURCE(ROP);
+
+ DPRINT("Locking DCs\n");
+ ahDC[0] = hDCDest;
+ ahDC[1] = hDCSrc ;
+ GDIOBJ_LockMultipleObjs(2, ahDC, apObj);
+ DCDest = apObj[0];
+ DCSrc = apObj[1];
+
+ if (NULL == DCDest)
+ {
+ if(DCSrc) GDIOBJ_UnlockObjByPtr(&DCSrc->BaseObject);
+ DPRINT("Invalid destination dc handle (0x%08x) passed to NtGdiBitBlt\n", hDCDest);
+ return FALSE;
+ }
+
+ if (DCDest->dctype == DC_TYPE_INFO)
+ {
+ if(DCSrc) GDIOBJ_UnlockObjByPtr(&DCSrc->BaseObject);
+ GDIOBJ_UnlockObjByPtr(&DCDest->BaseObject);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+
+ if (UsesSource)
+ {
+ if (NULL == DCSrc)
+ {
+ GDIOBJ_UnlockObjByPtr(&DCDest->BaseObject);
+ DPRINT("Invalid source dc handle (0x%08x) passed to NtGdiBitBlt\n", hDCSrc);
+ return FALSE;
+ }
+ if (DCSrc->dctype == DC_TYPE_INFO)
+ {
+ GDIOBJ_UnlockObjByPtr(&DCDest->BaseObject);
+ GDIOBJ_UnlockObjByPtr(&DCSrc->BaseObject);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+ }
+ else if(DCSrc)
+ {
+ DPRINT1("Getting a valid Source handle without using source!!!\n");
+ GDIOBJ_UnlockObjByPtr(&DCSrc->BaseObject);
+ DCSrc = NULL ;
+ }
+
+ pdcattr = DCDest->pdcattr;
+
+ DestRect.left = XDest;
+ DestRect.top = YDest;
+ DestRect.right = XDest+Width;
+ DestRect.bottom = YDest+Height;
+ IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
+
+ DestRect.left += DCDest->ptlDCOrig.x;
+ DestRect.top += DCDest->ptlDCOrig.y;
+ DestRect.right += DCDest->ptlDCOrig.x;
+ DestRect.bottom += DCDest->ptlDCOrig.y;
+
+ SourcePoint.x = XSrc;
+ SourcePoint.y = YSrc;
+
+ if (UsesSource)
+ {
+ IntLPtoDP(DCSrc, (LPPOINT)&SourcePoint, 1);
+
+ SourcePoint.x += DCSrc->ptlDCOrig.x;
+ SourcePoint.y += DCSrc->ptlDCOrig.y;
+ /* Calculate Source Rect */
+ SourceRect.left = SourcePoint.x;
+ SourceRect.top = SourcePoint.y;
+ SourceRect.right = SourcePoint.x + DestRect.right - DestRect.left;
+ SourceRect.bottom = SourcePoint.y + DestRect.bottom - DestRect.top ;
+ }
+
+ /* Prepare blit */
+ DC_vPrepareDCsForBlit(DCDest, DestRect, DCSrc, SourceRect);
+
+ if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
+ DC_vUpdateFillBrush(DCDest);
+
+ /* Determine surfaces to be used in the bitblt */
+ BitmapDest = DCDest->dclevel.pSurface;
+ if (!BitmapDest)
+ goto cleanup;
+
+ if (UsesSource)
+ {
+ {
+ BitmapSrc = DCSrc->dclevel.pSurface;
+ if (!BitmapSrc)
+ goto cleanup;
+ }
+ }
+
+ /* Create the XLATEOBJ. */
+ if (UsesSource)
+ {
+ EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
+ XlateObj = &exlo.xlo;
+ }
+
+ /* Perform the bitblt operation */
+ Status = IntEngBitBlt(&BitmapDest->SurfObj,
+ BitmapSrc ? &BitmapSrc->SurfObj : NULL,
+ NULL,
+ DCDest->rosdc.CombinedClip,
+ XlateObj,
+ &DestRect,
+ &SourcePoint,
+ NULL,
+ &DCDest->eboFill.BrushObject,
+ &DCDest->dclevel.pbrFill->ptOrigin,
+ ROP3_TO_ROP4(ROP));
+
+ if (UsesSource)
+ EXLATEOBJ_vCleanup(&exlo);
+cleanup:
+ DC_vFinishBlit(DCDest, DCSrc);
+ if (UsesSource)
+ {
+ GDIOBJ_UnlockObjByPtr(&DCSrc->BaseObject);
+ }
+ GDIOBJ_UnlockObjByPtr(&DCDest->BaseObject);
+
+ return Status;
+}
+
+BOOL APIENTRY
+NtGdiTransparentBlt(
+ HDC hdcDst,
+ INT xDst,
+ INT yDst,
+ INT cxDst,
+ INT cyDst,
+ HDC hdcSrc,
+ INT xSrc,
+ INT ySrc,
+ INT cxSrc,
+ INT cySrc,
+ COLORREF TransColor)
+{
+ PDC DCDest, DCSrc;
+ HDC ahDC[2];
+ PGDIOBJ apObj[2];
+ RECTL rcDest, rcSrc;
+ SURFACE *BitmapDest, *BitmapSrc = NULL;
+ PPALETTE PalSourceGDI;
+ ULONG TransparentColor = 0;
+ BOOL Ret = FALSE;
+ EXLATEOBJ exlo;
+
+ DPRINT("Locking DCs\n");
+ ahDC[0] = hdcDst;
+ ahDC[1] = hdcSrc ;
+ GDIOBJ_LockMultipleObjs(2, ahDC, apObj);
+ DCDest = apObj[0];
+ DCSrc = apObj[1];
+
+ if ((NULL == DCDest) || (NULL == DCSrc))
+ {
+ DPRINT1("Invalid dc handle (dest=0x%08x, src=0x%08x) passed to NtGdiAlphaBlend\n", hdcDst, hdcSrc);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ if(DCSrc) GDIOBJ_UnlockObjByPtr(&DCSrc->BaseObject);
+ if(DCDest) GDIOBJ_UnlockObjByPtr(&DCDest->BaseObject);
+ return FALSE;
+ }
+
+ if (DCDest->dctype == DC_TYPE_INFO || DCDest->dctype == DCTYPE_INFO)
+ {
+ GDIOBJ_UnlockObjByPtr(&DCSrc->BaseObject);
+ GDIOBJ_UnlockObjByPtr(&DCDest->BaseObject);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+
+ rcDest.left = xDst;
+ rcDest.top = yDst;
+ rcDest.right = rcDest.left + cxDst;
+ rcDest.bottom = rcDest.top + cyDst;
+ IntLPtoDP(DCDest, (LPPOINT)&rcDest, 2);
+
+ rcDest.left += DCDest->ptlDCOrig.x;
+ rcDest.top += DCDest->ptlDCOrig.y;
+ rcDest.right += DCDest->ptlDCOrig.x;
+ rcDest.bottom += DCDest->ptlDCOrig.y;
+
+ rcSrc.left = xSrc;
+ rcSrc.top = ySrc;
+ rcSrc.right = rcSrc.left + cxSrc;
+ rcSrc.bottom = rcSrc.top + cySrc;
+ IntLPtoDP(DCSrc, (LPPOINT)&rcSrc, 2);
+
+ rcSrc.left += DCSrc->ptlDCOrig.x;
+ rcSrc.top += DCSrc->ptlDCOrig.y;
+ rcSrc.right += DCSrc->ptlDCOrig.x;
+ rcSrc.bottom += DCSrc->ptlDCOrig.y;
+
+ /* Prepare for blit */
+ DC_vPrepareDCsForBlit(DCDest, rcDest, DCSrc, rcSrc);
+
+ BitmapDest = DCDest->dclevel.pSurface;
+ if (!BitmapDest)
+ {
+ goto done;
+ }
+
+ BitmapSrc = DCSrc->dclevel.pSurface;
+ if (!BitmapSrc)
+ {
+ goto done;
+ }
+
+ if (BitmapSrc->ppal)
+ {
+ GDIOBJ_IncrementShareCount(&BitmapSrc->ppal->BaseObject);
+ PalSourceGDI = BitmapSrc->ppal ;
+ }
+ else
+ PalSourceGDI = PALETTE_ShareLockPalette(pPrimarySurface->devinfo.hpalDefault) ;
+
+ if(!PalSourceGDI)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ goto done;
+ }
+
+ /* Translate Transparent (RGB) Color to the source palette */
+ EXLATEOBJ_vInitialize(&exlo, &gpalRGB, PalSourceGDI, 0, 0, 0);
+ TransparentColor = XLATEOBJ_iXlate(&exlo.xlo, (ULONG)TransColor);
+ EXLATEOBJ_vCleanup(&exlo);
+ PALETTE_ShareUnlockPalette(PalSourceGDI);
+
+ EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
+
+ Ret = IntEngTransparentBlt(&BitmapDest->SurfObj, &BitmapSrc->SurfObj,
+ DCDest->rosdc.CombinedClip, &exlo.xlo, &rcDest, &rcSrc,
+ TransparentColor, 0);
+
+ EXLATEOBJ_vCleanup(&exlo);
+
+done:
+ DC_vFinishBlit(DCDest, DCSrc);
+ GDIOBJ_UnlockObjByPtr(&DCDest->BaseObject);
+ GDIOBJ_UnlockObjByPtr(&DCSrc->BaseObject);
+
+ return Ret;
+}
+
+/***********************************************************************
+* MaskBlt
+* Ported from WINE by sedwards 11-4-03
+*
+* Someone thought it would be faster to do it here and then switch back
+* to GDI32. I dunno. Write a test and let me know.
+* A. It should be in here!
+*/
+
++static const DWORD ROP3Table[256] =
++{
++ 0x000042, 0x010289, 0x020C89, 0x0300AA, 0x040C88, 0x0500A9, 0x060865, 0x0702C5,
++ 0x080F08, 0x090245, 0x0A0329, 0x0B0B2A, 0x0C0324, 0x0D0B25, 0x0E08A5, 0x0F0001,
++ 0x100C85, 0x1100A6, 0x120868, 0x1302C8, 0x140869, 0x1502C9, 0x165CCA, 0x171D54,
++ 0x180D59, 0x191CC8, 0x1A06C5, 0x1B0768, 0x1C06CA, 0x1D0766, 0x1E01A5, 0x1F0385,
++ 0x200F09, 0x210248, 0x220326, 0x230B24, 0x240D55, 0x251CC5, 0x2606C8, 0x271868,
++ 0x280369, 0x2916CA, 0x2A0CC9, 0x2B1D58, 0x2C0784, 0x2D060A, 0x2E064A, 0x2F0E2A,
++ 0x30032A, 0x310B28, 0x320688, 0x330008, 0x3406C4, 0x351864, 0x3601A8, 0x370388,
++ 0x38078A, 0x390604, 0x3A0644, 0x3B0E24, 0x3C004A, 0x3D18A4, 0x3E1B24, 0x3F00EA,
++ 0x400F0A, 0x410249, 0x420D5D, 0x431CC4, 0x440328, 0x450B29, 0x4606C6, 0x47076A,
++ 0x480368, 0x4916C5, 0x4A0789, 0x4B0605, 0x4C0CC8, 0x4D1954, 0x4E0645, 0x4F0E25,
++ 0x500325, 0x510B26, 0x5206C9, 0x530764, 0x5408A9, 0x550009, 0x5601A9, 0x570389,
++ 0x580785, 0x590609, 0x5A0049, 0x5B18A9, 0x5C0649, 0x5D0E29, 0x5E1B29, 0x5F00E9,
++ 0x600365, 0x6116C6, 0x620786, 0x630608, 0x640788, 0x650606, 0x660046, 0x6718A8,
++ 0x6858A6, 0x690145, 0x6A01E9, 0x6B178A, 0x6C01E8, 0x6D1785, 0x6E1E28, 0x6F0C65,
++ 0x700CC5, 0x711D5C, 0x720648, 0x730E28, 0x740646, 0x750E26, 0x761B28, 0x7700E6,
++ 0x7801E5, 0x791786, 0x7A1E29, 0x7B0C68, 0x7C1E24, 0x7D0C69, 0x7E0955, 0x7F03C9,
++ 0x8003E9, 0x810975, 0x820C49, 0x831E04, 0x840C48, 0x851E05, 0x8617A6, 0x8701C5,
++ 0x8800C6, 0x891B08, 0x8A0E06, 0x8B0666, 0x8C0E08, 0x8D0668, 0x8E1D7C, 0x8F0CE5,
++ 0x900C45, 0x911E08, 0x9217A9, 0x9301C4, 0x9417AA, 0x9501C9, 0x960169, 0x97588A,
++ 0x981888, 0x990066, 0x9A0709, 0x9B07A8, 0x9C0704, 0x9D07A6, 0x9E16E6, 0x9F0345,
++ 0xA000C9, 0xA11B05, 0xA20E09, 0xA30669, 0xA41885, 0xA50065, 0xA60706, 0xA707A5,
++ 0xA803A9, 0xA90189, 0xAA0029, 0xAB0889, 0xAC0744, 0xAD06E9, 0xAE0B06, 0xAF0229,
++ 0xB00E05, 0xB10665, 0xB21974, 0xB30CE8, 0xB4070A, 0xB507A9, 0xB616E9, 0xB70348,
++ 0xB8074A, 0xB906E6, 0xBA0B09, 0xBB0226, 0xBC1CE4, 0xBD0D7D, 0xBE0269, 0xBF08C9,
++ 0xC000CA, 0xC11B04, 0xC21884, 0xC3006A, 0xC40E04, 0xC50664, 0xC60708, 0xC707AA,
++ 0xC803A8, 0xC90184, 0xCA0749, 0xCB06E4, 0xCC0020, 0xCD0888, 0xCE0B08, 0xCF0224,
++ 0xD00E0A, 0xD1066A, 0xD20705, 0xD307A4, 0xD41D78, 0xD50CE9, 0xD616EA, 0xD70349,
++ 0xD80745, 0xD906E8, 0xDA1CE9, 0xDB0D75, 0xDC0B04, 0xDD0228, 0xDE0268, 0xDF08C8,
++ 0xE003A5, 0xE10185, 0xE20746, 0xE306EA, 0xE40748, 0xE506E5, 0xE61CE8, 0xE70D79,
++ 0xE81D74, 0xE95CE6, 0xEA02E9, 0xEB0849, 0xEC02E8, 0xED0848, 0xEE0086, 0xEF0A08,
++ 0xF00021, 0xF10885, 0xF20B05, 0xF3022A, 0xF40B0A, 0xF50225, 0xF60265, 0xF708C5,
++ 0xF802E5, 0xF90845, 0xFA0089, 0xFB0A09, 0xFC008A, 0xFD0A0A, 0xFE02A9, 0xFF0062,
++};
++
+static __inline BYTE
+SwapROP3_SrcDst(BYTE bRop3)
+{
+ return (bRop3 & 0x99) | ((bRop3 & 0x22) << 1) | ((bRop3 & 0x44) >> 1);
+}
+
+#define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
+#define BKGND_ROP3(ROP4) (ROP3Table[(SwapROP3_SrcDst((ROP4)>>24)) & 0xFF])
+#define DSTCOPY 0x00AA0029
+#define DSTERASE 0x00220326 /* dest = dest & (~src) : DSna */
+
++/* NOTE: An alternative algorithm could use a pattern brush, created from
++ * the mask bitmap and then use raster operation 0xCA to combine the fore
++ * and background bitmaps. In this case erasing the bits beforehand would be
++ * unneccessary. On the other hand the Operation does not provide an optimized
++ * version in the DIB code, while SRCAND and SRCPAINT do.
++ * A fully correct implementation would call Eng/DrvBitBlt, but our
++ * EngBitBlt completely ignores the mask surface.
++ *
++ * Msk Fg Bk => x
++ * P S D DPSDxax
++ * ------------------------------------------
++ * 0 0 0 0 0000xax = 000ax = 00x = 0
++ * 0 0 1 1 1001xax = 101ax = 10x = 1
++ * 0 1 0 0 0010xax = 001ax = 00x = 0
++ * 0 1 1 1 1011xax = 100ax = 10x = 1
++ * 1 0 0 0 0100xax = 010ax = 00x = 0
++ * 1 0 1 0 1101xax = 111ax = 11x = 0
++ * 1 1 0 1 0110xax = 011ax = 01x = 1
++ * 1 1 1 1 1111xax = 110ax = 10x = 1
++ *
++ * Operation index = 11001010 = 0xCA = PSaDPnao = DPSDxax
++ * ^ no, this is not random letters, its reverse Polish notation
++ */
++
+BOOL APIENTRY
+NtGdiMaskBlt(
+ HDC hdcDest,
+ INT nXDest,
+ INT nYDest,
+ INT nWidth,
+ INT nHeight,
+ HDC hdcSrc,
+ INT nXSrc,
+ INT nYSrc,
+ HBITMAP hbmMask,
+ INT xMask,
+ INT yMask,
+ DWORD dwRop,
+ IN DWORD crBackColor)
+{
- return NtGdiBitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop), 0, 0);
-
- /* 1. make mask bitmap's dc */
- hDCMask = NtGdiCreateCompatibleDC(hdcDest);
- hOldMaskBitmap = (HBITMAP)NtGdiSelectBitmap(hDCMask, hbmMask);
-
- /* 2. make masked Background bitmap */
-
- /* 2.1 make bitmap */
- hDC1 = NtGdiCreateCompatibleDC(hdcDest);
- hBitmap2 = NtGdiCreateCompatibleBitmap(hdcDest, nWidth, nHeight);
- hOldBitmap2 = (HBITMAP)NtGdiSelectBitmap(hDC1, hBitmap2);
-
- /* 2.2 draw dest bitmap and mask */
- NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, SRCCOPY, 0, 0);
- NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, BKGND_ROP3(dwRop), 0, 0);
- NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hDCMask, xMask, yMask, DSTERASE, 0, 0);
-
- /* 3. make masked Foreground bitmap */
-
- /* 3.1 make bitmap */
- hDC2 = NtGdiCreateCompatibleDC(hdcDest);
- hBitmap3 = NtGdiCreateCompatibleBitmap(hdcDest, nWidth, nHeight);
- hOldBitmap3 = (HBITMAP)NtGdiSelectBitmap(hDC2, hBitmap3);
-
- /* 3.2 draw src bitmap and mask */
- NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY, 0, 0);
- NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop), 0,0);
- NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hDCMask, xMask, yMask, SRCAND, 0, 0);
-
- /* 4. combine both and copy the result to hdcDest */
- NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hDC2, 0, 0, SRCPAINT, 0, 0);
- NtGdiBitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC1, 0, 0, SRCCOPY, 0, 0);
-
- /* 5. restore all objects */
- NtGdiSelectBitmap(hDCMask, hOldMaskBitmap);
- NtGdiSelectBitmap(hDC1, hOldBitmap2);
- NtGdiSelectBitmap(hDC2, hOldBitmap3);
-
- /* 6. delete all temp objects */
- GreDeleteObject(hBitmap2);
- GreDeleteObject(hBitmap3);
-
- NtGdiDeleteObjectApp(hDC1);
- NtGdiDeleteObjectApp(hDC2);
- NtGdiDeleteObjectApp(hDCMask);
++ HBITMAP hbmFore, hbmBack;
++ HDC hdcMask, hdcFore, hdcBack;
++ PDC pdc;
++ HBRUSH hbr;
++ COLORREF crFore, crBack;
+
+ if (!hbmMask)
++ return NtGdiBitBlt(hdcDest,
++ nXDest,
++ nYDest,
++ nWidth,
++ nHeight,
++ hdcSrc,
++ nXSrc,
++ nYSrc,
++ FRGND_ROP3(dwRop),
++ crBackColor,
++ 0);
++
++ /* Lock the dest DC */
++ pdc = DC_LockDc(hdcDest);
++ if (!pdc) return FALSE;
++
++ /* Get brush and colors from dest dc */
++ hbr = pdc->pdcattr->hbrush;
++ crFore = pdc->pdcattr->crForegroundClr;
++ crBack = pdc->pdcattr->crBackgroundClr;
++
++ /* Unlock the DC */
++ DC_UnlockDc(pdc);
++
++ /* 1. Create mask bitmap's dc */
++ hdcMask = NtGdiCreateCompatibleDC(hdcDest);
++ NtGdiSelectBitmap(hdcMask, hbmMask);
++
++ /* 2. Create masked Background bitmap */
++
++ /* 2.1 Create bitmap */
++ hdcBack = NtGdiCreateCompatibleDC(hdcDest);
++ hbmBack = NtGdiCreateCompatibleBitmap(hdcDest, nWidth, nHeight);
++ NtGdiSelectBitmap(hdcBack, hbmBack);
++
++ /* 2.2 Copy source bitmap */
++ NtGdiSelectBrush(hdcBack, hbr);
++ IntGdiSetBkColor(hdcBack, crBack);
++ IntGdiSetTextColor(hdcBack, crFore);
++ NtGdiBitBlt(hdcBack, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, SRCCOPY, 0, 0);
++
++ /* 2.3 Do the background rop */
++ NtGdiBitBlt(hdcBack, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, BKGND_ROP3(dwRop), 0, 0);
++
++ /* 2.4 Erase the foreground pixels */
++ IntGdiSetBkColor(hdcBack, 0xffffffff);
++ IntGdiSetTextColor(hdcBack, 0);
++ NtGdiBitBlt(hdcBack, 0, 0, nWidth, nHeight, hdcMask, xMask, yMask, SRCAND, 0, 0);
++
++ /* 3. Create masked Foreground bitmap */
++
++ /* 3.1 Create bitmap */
++ hdcFore = NtGdiCreateCompatibleDC(hdcDest);
++ hbmFore = NtGdiCreateCompatibleBitmap(hdcDest, nWidth, nHeight);
++ NtGdiSelectBitmap(hdcFore, hbmFore);
++
++ /* 3.2 Copy the dest bitmap */
++ NtGdiSelectBrush(hdcFore, hbr);
++ IntGdiSetBkColor(hdcFore, crBack);
++ IntGdiSetTextColor(hdcFore, crFore);
++ NtGdiBitBlt(hdcFore, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY, 0, 0);
++
++ /* 2.3 Do the foreground rop */
++ NtGdiBitBlt(hdcFore, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop), 0,0);
++
++ /* 2.4 Erase the background pixels */
++ IntGdiSetBkColor(hdcFore, 0);
++ IntGdiSetTextColor(hdcFore, 0xffffffff);
++ NtGdiBitBlt(hdcFore, 0, 0, nWidth, nHeight, hdcMask, xMask, yMask, SRCAND, 0, 0);
++
++ /* 3. Combine the fore and background into the background bitmap */
++ NtGdiBitBlt(hdcBack, 0, 0, nWidth, nHeight, hdcFore, 0, 0, SRCPAINT, 0, 0);
++
++ /* 4. Copy the result to hdcDest */
++ NtGdiBitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcBack, 0, 0, SRCCOPY, 0, 0);
++
++ /* 5. delete all temp objects */
++ NtGdiDeleteObjectApp(hdcBack);
++ NtGdiDeleteObjectApp(hdcFore);
++ NtGdiDeleteObjectApp(hdcMask);
++ GreDeleteObject(hbmFore);
++ GreDeleteObject(hbmBack);
+
+ return TRUE;
+}
+
+BOOL
+APIENTRY
+NtGdiPlgBlt(
+ IN HDC hdcTrg,
+ IN LPPOINT pptlTrg,
+ IN HDC hdcSrc,
+ IN INT xSrc,
+ IN INT ySrc,
+ IN INT cxSrc,
+ IN INT cySrc,
+ IN HBITMAP hbmMask,
+ IN INT xMask,
+ IN INT yMask,
+ IN DWORD crBackColor)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL APIENTRY
+GreStretchBltMask(
+ HDC hDCDest,
+ INT XOriginDest,
+ INT YOriginDest,
+ INT WidthDest,
+ INT HeightDest,
+ HDC hDCSrc,
+ INT XOriginSrc,
+ INT YOriginSrc,
+ INT WidthSrc,
+ INT HeightSrc,
+ DWORD ROP,
+ IN DWORD dwBackColor,
+ HDC hDCMask,
+ INT XOriginMask,
+ INT YOriginMask)
+{
+ PDC DCDest;
+ PDC DCSrc = NULL;
+ PDC DCMask = NULL;
+ HDC ahDC[3];
+ PGDIOBJ apObj[3];
+ PDC_ATTR pdcattr;
+ SURFACE *BitmapDest, *BitmapSrc = NULL;
+ SURFACE *BitmapMask = NULL;
+ RECTL DestRect;
+ RECTL SourceRect;
+ POINTL MaskPoint;
+ BOOL Status = FALSE;
+ EXLATEOBJ exlo;
+ XLATEOBJ *XlateObj = NULL;
+ POINTL BrushOrigin;
+ BOOL UsesSource = ROP3_USES_SOURCE(ROP);
+
+ if (0 == WidthDest || 0 == HeightDest || 0 == WidthSrc || 0 == HeightSrc)
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ DPRINT("Locking DCs\n");
+ ahDC[0] = hDCDest;
+ ahDC[1] = hDCSrc ;
+ ahDC[2] = hDCMask ;
+ GDIOBJ_LockMultipleObjs(3, ahDC, apObj);
+ DCDest = apObj[0];
+ DCSrc = apObj[1];
+ DCMask = apObj[2];
+
+ if (NULL == DCDest)
+ {
+ if(DCSrc) GDIOBJ_UnlockObjByPtr(&DCSrc->BaseObject);
+ if(DCMask) GDIOBJ_UnlockObjByPtr(&DCMask->BaseObject);
+ DPRINT("Invalid destination dc handle (0x%08x) passed to NtGdiBitBlt\n", hDCDest);
+ return FALSE;
+ }
+
+ if (DCDest->dctype == DC_TYPE_INFO)
+ {
+ if(DCSrc) GDIOBJ_UnlockObjByPtr(&DCSrc->BaseObject);
+ if(DCMask) GDIOBJ_UnlockObjByPtr(&DCMask->BaseObject);
+ GDIOBJ_UnlockObjByPtr(&DCDest->BaseObject);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+
+ if (UsesSource)
+ {
+ if (NULL == DCSrc)
+ {
+ GDIOBJ_UnlockObjByPtr(&DCDest->BaseObject);
+ if(DCMask) GDIOBJ_UnlockObjByPtr(&DCMask->BaseObject);
+ DPRINT("Invalid source dc handle (0x%08x) passed to NtGdiBitBlt\n", hDCSrc);
+ return FALSE;
+ }
+ if (DCSrc->dctype == DC_TYPE_INFO)
+ {
+ GDIOBJ_UnlockObjByPtr(&DCDest->BaseObject);
+ GDIOBJ_UnlockObjByPtr(&DCSrc->BaseObject);
+ if(DCMask) GDIOBJ_UnlockObjByPtr(&DCMask->BaseObject);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+ }
+ else if(DCSrc)
+ {
+ DPRINT1("Getting a valid Source handle without using source!!!\n");
+ GDIOBJ_UnlockObjByPtr(&DCSrc->BaseObject);
+ DCSrc = NULL ;
+ }
+
+ pdcattr = DCDest->pdcattr;
+
+ DestRect.left = XOriginDest;
+ DestRect.top = YOriginDest;
+ DestRect.right = XOriginDest+WidthDest;
+ DestRect.bottom = YOriginDest+HeightDest;
+ IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
+
+ DestRect.left += DCDest->ptlDCOrig.x;
+ DestRect.top += DCDest->ptlDCOrig.y;
+ DestRect.right += DCDest->ptlDCOrig.x;
+ DestRect.bottom += DCDest->ptlDCOrig.y;
+
+ SourceRect.left = XOriginSrc;
+ SourceRect.top = YOriginSrc;
+ SourceRect.right = XOriginSrc+WidthSrc;
+ SourceRect.bottom = YOriginSrc+HeightSrc;
+
+ if (UsesSource)
+ {
+ IntLPtoDP(DCSrc, (LPPOINT)&SourceRect, 2);
+
+ SourceRect.left += DCSrc->ptlDCOrig.x;
+ SourceRect.top += DCSrc->ptlDCOrig.y;
+ SourceRect.right += DCSrc->ptlDCOrig.x;
+ SourceRect.bottom += DCSrc->ptlDCOrig.y;
+ }
+
+ BrushOrigin.x = 0;
+ BrushOrigin.y = 0;
+
+ /* Only prepare Source and Dest, hdcMask represents a DIB */
+ DC_vPrepareDCsForBlit(DCDest, DestRect, DCSrc, SourceRect);
+
+ if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
+ DC_vUpdateFillBrush(DCDest);
+
+ /* Determine surfaces to be used in the bitblt */
+ BitmapDest = DCDest->dclevel.pSurface;
+ if (BitmapDest == NULL)
+ goto failed;
+ if (UsesSource)
+ {
+ BitmapSrc = DCSrc->dclevel.pSurface;
+ if (BitmapSrc == NULL)
+ goto failed;
+
+ /* Create the XLATEOBJ. */
+ EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
+ XlateObj = &exlo.xlo;
+ }
+
+ /* Offset the brush */
+ BrushOrigin.x += DCDest->ptlDCOrig.x;
+ BrushOrigin.y += DCDest->ptlDCOrig.y;
+
+ /* Make mask surface for source surface */
+ if (BitmapSrc && DCMask)
+ {
+ BitmapMask = DCMask->dclevel.pSurface;
+ if (BitmapMask &&
+ (BitmapMask->SurfObj.sizlBitmap.cx < WidthSrc ||
+ BitmapMask->SurfObj.sizlBitmap.cy < HeightSrc))
+ {
+ DPRINT1("%dx%d mask is smaller than %dx%d bitmap\n",
+ BitmapMask->SurfObj.sizlBitmap.cx, BitmapMask->SurfObj.sizlBitmap.cy,
+ WidthSrc, HeightSrc);
+ EXLATEOBJ_vCleanup(&exlo);
+ goto failed;
+ }
+ /* Create mask offset point */
+ MaskPoint.x = XOriginMask;
+ MaskPoint.y = YOriginMask;
+ IntLPtoDP(DCMask, &MaskPoint, 1);
+ MaskPoint.x += DCMask->ptlDCOrig.x;
+ MaskPoint.y += DCMask->ptlDCOrig.x;
+ }
+
+ /* Perform the bitblt operation */
+ Status = IntEngStretchBlt(&BitmapDest->SurfObj,
+ &BitmapSrc->SurfObj,
+ BitmapMask ? &BitmapMask->SurfObj : NULL,
+ DCDest->rosdc.CombinedClip,
+ XlateObj,
+ &DestRect,
+ &SourceRect,
+ BitmapMask ? &MaskPoint : NULL,
+ &DCDest->eboFill.BrushObject,
+ &BrushOrigin,
+ ROP3_TO_ROP4(ROP));
+ if (UsesSource)
+ {
+ EXLATEOBJ_vCleanup(&exlo);
+ }
+
+failed:
+ DC_vFinishBlit(DCDest, DCSrc);
+ if (UsesSource)
+ {
+ DC_UnlockDc(DCSrc);
+ }
+ if (DCMask)
+ {
+ DC_UnlockDc(DCMask);
+ }
+ DC_UnlockDc(DCDest);
+
+ return Status;
+}
+
+
+BOOL APIENTRY
+NtGdiStretchBlt(
+ HDC hDCDest,
+ INT XOriginDest,
+ INT YOriginDest,
+ INT WidthDest,
+ INT HeightDest,
+ HDC hDCSrc,
+ INT XOriginSrc,
+ INT YOriginSrc,
+ INT WidthSrc,
+ INT HeightSrc,
+ DWORD ROP,
+ IN DWORD dwBackColor)
+{
+ return GreStretchBltMask(
+ hDCDest,
+ XOriginDest,
+ YOriginDest,
+ WidthDest,
+ HeightDest,
+ hDCSrc,
+ XOriginSrc,
+ YOriginSrc,
+ WidthSrc,
+ HeightSrc,
+ ROP,
+ dwBackColor,
+ NULL,
+ 0,
+ 0);
+}
+
+
+BOOL FASTCALL
+IntPatBlt(
+ PDC pdc,
+ INT XLeft,
+ INT YLeft,
+ INT Width,
+ INT Height,
+ DWORD dwRop,
+ PBRUSH pbrush)
+{
+ RECTL DestRect;
+ SURFACE *psurf;
+ EBRUSHOBJ eboFill ;
+ POINTL BrushOrigin;
+ BOOL ret;
+
+ ASSERT(pbrush);
+
+ if (pbrush->flAttrs & GDIBRUSH_IS_NULL)
+ {
+ return TRUE;
+ }
+
+ if (Width > 0)
+ {
+ DestRect.left = XLeft;
+ DestRect.right = XLeft + Width;
+ }
+ else
+ {
+ DestRect.left = XLeft + Width + 1;
+ DestRect.right = XLeft + 1;
+ }
+
+ if (Height > 0)
+ {
+ DestRect.top = YLeft;
+ DestRect.bottom = YLeft + Height;
+ }
+ else
+ {
+ DestRect.top = YLeft + Height + 1;
+ DestRect.bottom = YLeft + 1;
+ }
+
+ IntLPtoDP(pdc, (LPPOINT)&DestRect, 2);
+
+ DestRect.left += pdc->ptlDCOrig.x;
+ DestRect.top += pdc->ptlDCOrig.y;
+ DestRect.right += pdc->ptlDCOrig.x;
+ DestRect.bottom += pdc->ptlDCOrig.y;
+
+ BrushOrigin.x = pbrush->ptOrigin.x + pdc->ptlDCOrig.x;
+ BrushOrigin.y = pbrush->ptOrigin.y + pdc->ptlDCOrig.y;
+
+ DC_vPrepareDCsForBlit(pdc, DestRect, NULL, DestRect);
+
+ psurf = pdc->dclevel.pSurface;
+
+ if (pdc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
+ DC_vUpdateFillBrush(pdc);
+
+ EBRUSHOBJ_vInit(&eboFill, pbrush, pdc);
+
+ ret = IntEngBitBlt(
+ &psurf->SurfObj,
+ NULL,
+ NULL,
+ pdc->rosdc.CombinedClip,
+ NULL,
+ &DestRect,
+ NULL,
+ NULL,
+ &eboFill.BrushObject,
+ &BrushOrigin,
+ ROP3_TO_ROP4(dwRop));
+
+ DC_vFinishBlit(pdc, NULL);
+
+ EBRUSHOBJ_vCleanup(&eboFill);
+
+ return ret;
+}
+
+BOOL FASTCALL
+IntGdiPolyPatBlt(
+ HDC hDC,
+ DWORD dwRop,
+ PPATRECT pRects,
+ INT cRects,
+ ULONG Reserved)
+{
+ INT i;
+ PBRUSH pbrush;
+ PDC pdc;
+
+ pdc = DC_LockDc(hDC);
+ if (!pdc)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ if (pdc->dctype == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(pdc);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+
+ for (i = 0; i < cRects; i++)
+ {
+ pbrush = BRUSH_LockBrush(pRects->hBrush);
+ if(pbrush != NULL)
+ {
+ IntPatBlt(
+ pdc,
+ pRects->r.left,
+ pRects->r.top,
+ pRects->r.right,
+ pRects->r.bottom,
+ dwRop,
+ pbrush);
+ BRUSH_UnlockBrush(pbrush);
+ }
+ pRects++;
+ }
+
+ DC_UnlockDc(pdc);
+
+ return TRUE;
+}
+
+
+BOOL APIENTRY
+NtGdiPatBlt(
+ HDC hDC,
+ INT XLeft,
+ INT YLeft,
+ INT Width,
+ INT Height,
+ DWORD ROP)
+{
+ PBRUSH pbrush;
+ DC *dc;
+ PDC_ATTR pdcattr;
+ BOOL ret;
+
+ BOOL UsesSource = ROP3_USES_SOURCE(ROP);
+ if (UsesSource)
+ {
+ /* in this case we call on GdiMaskBlt */
+ return NtGdiMaskBlt(hDC, XLeft, YLeft, Width, Height, 0,0,0,0,0,0,ROP,0);
+ }
+
+ dc = DC_LockDc(hDC);
+ if (dc == NULL)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ if (dc->dctype == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(dc);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+
+ pdcattr = dc->pdcattr;
+
+ if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
+ DC_vUpdateFillBrush(dc);
+
+ pbrush = BRUSH_LockBrush(pdcattr->hbrush);
+ if (pbrush == NULL)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ DC_UnlockDc(dc);
+ return FALSE;
+ }
+
+ ret = IntPatBlt(dc, XLeft, YLeft, Width, Height, ROP, pbrush);
+
+ BRUSH_UnlockBrush(pbrush);
+ DC_UnlockDc(dc);
+
+ return ret;
+}
+
+BOOL APIENTRY
+NtGdiPolyPatBlt(
+ HDC hDC,
+ DWORD dwRop,
+ IN PPOLYPATBLT pRects,
+ IN DWORD cRects,
+ IN DWORD Mode)
+{
+ PPATRECT rb = NULL;
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL Ret;
+
+ if (cRects > 0)
+ {
+ rb = ExAllocatePoolWithTag(PagedPool, sizeof(PATRECT) * cRects, TAG_PATBLT);
+ if (!rb)
+ {
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+ _SEH2_TRY
+ {
+ ProbeForRead(pRects,
+ cRects * sizeof(PATRECT),
+ 1);
+ RtlCopyMemory(rb,
+ pRects,
+ cRects * sizeof(PATRECT));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePoolWithTag(rb, TAG_PATBLT);
+ SetLastNtError(Status);
+ return FALSE;
+ }
+ }
+
+ Ret = IntGdiPolyPatBlt(hDC, dwRop, rb, cRects, Mode);
+
+ if (cRects > 0)
+ ExFreePoolWithTag(rb, TAG_PATBLT);
+
+ return Ret;
+}
--- /dev/null
+/*
+ * ReactOS W32 Subsystem
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <win32k.h>
+
+#define NDEBUG
+#include <debug.h>
+
+LONG APIENTRY
+IntSetBitmapBits(
+ PSURFACE psurf,
+ DWORD Bytes,
+ IN PBYTE Bits)
+{
+ /* Don't copy more bytes than the buffer has */
+ Bytes = min(Bytes, psurf->SurfObj.cjBits);
+
+ RtlCopyMemory(psurf->SurfObj.pvBits, Bits, Bytes);
+
+ return Bytes;
+}
+
+void
+NTAPI
+UnsafeSetBitmapBits(
+ PSURFACE psurf,
+ IN ULONG cjBits,
+ IN PVOID pvBits)
+{
+ PUCHAR pjDst, pjSrc;
+ LONG lDeltaDst, lDeltaSrc;
+ ULONG nWidth, nHeight, cBitsPixel;
+
+ nWidth = psurf->SurfObj.sizlBitmap.cx;
+ nHeight = psurf->SurfObj.sizlBitmap.cy;
+ cBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
+
+ /* Get pointers */
+ pjDst = psurf->SurfObj.pvScan0;
+ pjSrc = pvBits;
+ lDeltaDst = psurf->SurfObj.lDelta;
+ lDeltaSrc = BITMAP_GetWidthBytes(nWidth, cBitsPixel);
+
+ while (nHeight--)
+ {
+ /* Copy one line */
+ memcpy(pjDst, pjSrc, lDeltaSrc);
+ pjSrc += lDeltaSrc;
+ pjDst += lDeltaDst;
+ }
+
+}
+
+HBITMAP
+APIENTRY
+GreCreateBitmapEx(
+ IN INT nWidth,
+ IN INT nHeight,
+ IN ULONG cjWidthBytes,
+ IN ULONG iFormat,
+ IN USHORT fjBitmap,
+ IN ULONG cjSizeImage,
+ IN OPTIONAL PVOID pvBits,
+ IN FLONG flags)
+{
+ PSURFACE psurf;
+ SURFOBJ *pso;
+ HBITMAP hbmp;
+ PVOID pvCompressedBits;
+ SIZEL sizl;
+
+ /* Verify format */
+ if (iFormat < BMF_1BPP || iFormat > BMF_PNG) return NULL;
+
+ /* Allocate a surface */
+ psurf = SURFACE_AllocSurface(STYPE_BITMAP, nWidth, nHeight, iFormat);
+ if (!psurf)
+ {
+ DPRINT1("SURFACE_AllocSurface failed.\n");
+ return NULL;
+ }
+
+ /* Get the handle for the bitmap and the surfobj */
+ hbmp = (HBITMAP)psurf->SurfObj.hsurf;
+ pso = &psurf->SurfObj;
+
+ /* The infamous RLE hack */
+ if (iFormat == BMF_4RLE)
+ {
+ sizl.cx = nWidth; sizl.cy = nHeight;
+ pvCompressedBits = pvBits;
+ pvBits = EngAllocMem(FL_ZERO_MEMORY, pso->cjBits, TAG_DIB);
+ Decompress4bpp(sizl, pvCompressedBits, pvBits, pso->lDelta);
+ fjBitmap |= BMF_RLE_HACK;
+ }
+ else if (iFormat == BMF_8RLE)
+ {
+ sizl.cx = nWidth; sizl.cy = nHeight;
+ pvCompressedBits = pvBits;
+ pvBits = EngAllocMem(FL_ZERO_MEMORY, pso->cjBits, TAG_DIB);
+ Decompress8bpp(sizl, pvCompressedBits, pvBits, pso->lDelta);
+ fjBitmap |= BMF_RLE_HACK;
+ }
+
+ /* Mark as API bitmap */
+ psurf->flags |= (flags | API_BITMAP);
+
+ /* Set the bitmap bits */
+ if (!SURFACE_bSetBitmapBits(psurf, fjBitmap, cjWidthBytes, pvBits))
+ {
+ /* Bail out if that failed */
+ DPRINT1("SURFACE_bSetBitmapBits failed.\n");
+ SURFACE_FreeSurfaceByHandle(hbmp);
+ return NULL;
+ }
+
+ /* Unlock the surface and return */
+ SURFACE_UnlockSurface(psurf);
+ return hbmp;
+}
+
+/* Creates a DDB surface,
+ * as in CreateCompatibleBitmap or CreateBitmap.
+ */
+HBITMAP
+APIENTRY
+GreCreateBitmap(
+ IN INT nWidth,
+ IN INT nHeight,
+ IN UINT cPlanes,
+ IN UINT cBitsPixel,
+ IN OPTIONAL PVOID pvBits)
+{
+ /* Call the extended function */
+ return GreCreateBitmapEx(nWidth,
+ nHeight,
+ 0, /* auto width */
+ BitmapFormat(cBitsPixel * cPlanes, BI_RGB),
+ 0, /* no bitmap flags */
+ 0, /* auto size */
+ pvBits,
+ DDB_SURFACE /* DDB */);
+}
+
+HBITMAP
+APIENTRY
+NtGdiCreateBitmap(
+ IN INT nWidth,
+ IN INT nHeight,
+ IN UINT cPlanes,
+ IN UINT cBitsPixel,
+ IN OPTIONAL LPBYTE pUnsafeBits)
+{
+ HBITMAP hbmp;
+ ULONG cjWidthBytes, iFormat;
+
+ /* NOTE: Windows also doesn't store nr. of planes separately! */
+ cBitsPixel = BITMAP_GetRealBitsPixel(cBitsPixel * cPlanes);
+
+ /* Calculate bitmap format */
+ iFormat = BitmapFormat(cBitsPixel, BI_RGB);
+
+ /* Check parameters */
+ if (iFormat == 0 || nWidth <= 0 || nWidth >= 0x8000000 || nHeight <= 0)
+ {
+ DPRINT1("Width = %d, Height = %d BitsPixel = %d\n",
+ nWidth, nHeight, cBitsPixel);
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ return NULL;
+ }
+
+ /* Make sure that cjBits will not overflow */
+ cjWidthBytes = BITMAP_GetWidthBytes(nWidth, cBitsPixel);
+ if ((ULONGLONG)cjWidthBytes * nHeight >= 0x100000000ULL)
+ {
+ DPRINT1("Width = %d, Height = %d BitsPixel = %d\n",
+ nWidth, nHeight, cBitsPixel);
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ return NULL;
+ }
+
+ /* cBitsPixel = cBitsPixel * cPlanes now! */
+ hbmp = GreCreateBitmap(nWidth, nHeight, 1, cBitsPixel, NULL);
+
+ if (pUnsafeBits)
+ {
+ PSURFACE psurf = SURFACE_LockSurface(hbmp);
+ _SEH2_TRY
+ {
+ ProbeForRead(pUnsafeBits, cjWidthBytes * nHeight, 1);
+ UnsafeSetBitmapBits(psurf, 0, pUnsafeBits);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SURFACE_UnlockSurface(psurf);
+ SURFACE_FreeSurfaceByHandle(hbmp);
+ _SEH2_YIELD(return NULL;)
+ }
+ _SEH2_END
+
+ SURFACE_UnlockSurface(psurf);
+ }
+
+ return hbmp;
+}
+
+
+HBITMAP FASTCALL
+IntCreateCompatibleBitmap(
+ PDC Dc,
+ INT Width,
+ INT Height)
+{
+ HBITMAP Bmp = NULL;
+
+ /* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */
+ if (0 == Width || 0 == Height)
+ {
+ Bmp = NtGdiGetStockObject(DEFAULT_BITMAP);
+ }
+ else
+ {
+ if (Dc->dctype != DC_TYPE_MEMORY)
+ {
+ PSURFACE psurf;
+ SIZEL size;
+
+ size.cx = abs(Width);
+ size.cy = abs(Height);
+ Bmp = GreCreateBitmap(abs(Width),
+ abs(Height),
+ 1,
+ Dc->ppdev->gdiinfo.cBitsPixel,
+ NULL);
+ psurf = SURFACE_LockSurface(Bmp);
+ ASSERT(psurf);
+ /* Set palette */
+ psurf->ppal = PALETTE_ShareLockPalette(Dc->ppdev->devinfo.hpalDefault);
+ /* Set flags */
+ psurf->flags = API_BITMAP;
+ psurf->hdc = NULL; // Fixme
+ SURFACE_UnlockSurface(psurf);
+ }
+ else
+ {
+ DIBSECTION dibs;
+ INT Count;
+ PSURFACE psurf = Dc->dclevel.pSurface;
+ Count = BITMAP_GetObject(psurf, sizeof(dibs), &dibs);
+
+ if (Count)
+ {
+ if (Count == sizeof(BITMAP))
+ {
+ SIZEL size;
+ PSURFACE psurfBmp;
+ size.cx = abs(Width);
+ size.cy = abs(Height);
+ Bmp = GreCreateBitmap(abs(Width),
+ abs(Height),
+ 1,
+ dibs.dsBm.bmBitsPixel,
+ NULL);
+ psurfBmp = SURFACE_LockSurface(Bmp);
+ ASSERT(psurfBmp);
+ /* Assign palette */
+ psurfBmp->ppal = psurf->ppal;
+ GDIOBJ_IncrementShareCount((POBJ)psurf->ppal);
+ /* Set flags */
+ psurfBmp->flags = API_BITMAP;
+ psurfBmp->hdc = NULL; // Fixme
+ SURFACE_UnlockSurface(psurfBmp);
+ }
+ else
+ {
+ /* A DIB section is selected in the DC */
+ BYTE buf[sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD)] = {0};
+ PVOID Bits;
+ BITMAPINFO* bi = (BITMAPINFO*)buf;
+
+ bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
+ bi->bmiHeader.biWidth = Width;
+ bi->bmiHeader.biHeight = Height;
+ bi->bmiHeader.biPlanes = dibs.dsBmih.biPlanes;
+ bi->bmiHeader.biBitCount = dibs.dsBmih.biBitCount;
+ bi->bmiHeader.biCompression = dibs.dsBmih.biCompression;
+ bi->bmiHeader.biSizeImage = 0;
+ bi->bmiHeader.biXPelsPerMeter = dibs.dsBmih.biXPelsPerMeter;
+ bi->bmiHeader.biYPelsPerMeter = dibs.dsBmih.biYPelsPerMeter;
+ bi->bmiHeader.biClrUsed = dibs.dsBmih.biClrUsed;
+ bi->bmiHeader.biClrImportant = dibs.dsBmih.biClrImportant;
+
+ if (bi->bmiHeader.biCompression == BI_BITFIELDS)
+ {
+ /* Copy the color masks */
+ RtlCopyMemory(bi->bmiColors, dibs.dsBitfields, 3*sizeof(RGBQUAD));
+ }
+ else if (bi->bmiHeader.biBitCount <= 8)
+ {
+ /* Copy the color table */
+ UINT Index;
+ PPALETTE PalGDI;
+
+ if (!psurf->ppal)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return 0;
+ }
+
+ PalGDI = PALETTE_LockPalette(psurf->ppal->BaseObject.hHmgr);
+
+ for (Index = 0;
+ Index < 256 && Index < PalGDI->NumColors;
+ Index++)
+ {
+ bi->bmiColors[Index].rgbRed = PalGDI->IndexedColors[Index].peRed;
+ bi->bmiColors[Index].rgbGreen = PalGDI->IndexedColors[Index].peGreen;
+ bi->bmiColors[Index].rgbBlue = PalGDI->IndexedColors[Index].peBlue;
+ bi->bmiColors[Index].rgbReserved = 0;
+ }
+ PALETTE_UnlockPalette(PalGDI);
+
+ Bmp = DIB_CreateDIBSection(Dc,
+ bi,
+ DIB_RGB_COLORS,
+ &Bits,
+ NULL,
+ 0,
+ 0);
+ return Bmp;
+ }
+ }
+ }
+ }
+ }
+ return Bmp;
+}
+
+HBITMAP APIENTRY
+NtGdiCreateCompatibleBitmap(
+ HDC hDC,
+ INT Width,
+ INT Height)
+{
+ HBITMAP Bmp;
+ PDC Dc;
+
+ if (Width <= 0 || Height <= 0 || (Width * Height) > 0x3FFFFFFF)
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return NULL;
+ }
+
+ if (!hDC)
+ return GreCreateBitmap(Width, Height, 1, 1, 0);
+
+ Dc = DC_LockDc(hDC);
+
+ DPRINT("NtGdiCreateCompatibleBitmap(%04x,%d,%d, bpp:%d) = \n",
+ hDC, Width, Height, Dc->ppdev->gdiinfo.cBitsPixel);
+
+ if (NULL == Dc)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return NULL;
+ }
+
+ Bmp = IntCreateCompatibleBitmap(Dc, Width, Height);
+
+ DPRINT("\t\t%04x\n", Bmp);
+ DC_UnlockDc(Dc);
+ return Bmp;
+}
+
+BOOL APIENTRY
+NtGdiGetBitmapDimension(
+ HBITMAP hBitmap,
+ LPSIZE Dimension)
+{
+ PSURFACE psurfBmp;
+ BOOL Ret = TRUE;
+
+ if (hBitmap == NULL)
+ return FALSE;
+
+ psurfBmp = SURFACE_LockSurface(hBitmap);
+ if (psurfBmp == NULL)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ _SEH2_TRY
+ {
+ ProbeForWrite(Dimension, sizeof(SIZE), 1);
+ *Dimension = psurfBmp->sizlDim;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Ret = FALSE;
+ }
+ _SEH2_END
+
+ SURFACE_UnlockSurface(psurfBmp);
+
+ return Ret;
+}
+
+COLORREF APIENTRY
+NtGdiGetPixel(HDC hDC, INT XPos, INT YPos)
+{
+ PDC dc = NULL;
+ COLORREF Result = (COLORREF)CLR_INVALID; // default to failure
+ BOOL bInRect = FALSE;
+ SURFACE *psurf;
+ SURFOBJ *pso;
+ PPALETTE ppal;
+ EXLATEOBJ exlo;
+ HBITMAP hBmpTmp;
+
+ dc = DC_LockDc(hDC);
+
+ if (!dc)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return Result;
+ }
+
+ if (dc->dctype == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(dc);
+ return Result;
+ }
+
+ XPos += dc->ptlDCOrig.x;
+ YPos += dc->ptlDCOrig.y;
+ if (RECTL_bPointInRect(&dc->rosdc.CombinedClip->rclBounds, XPos, YPos))
+ {
+ bInRect = TRUE;
+ psurf = dc->dclevel.pSurface;
+ if (psurf)
+ {
+ pso = &psurf->SurfObj;
+ if (psurf->ppal)
+ {
+ ppal = psurf->ppal;
+ GDIOBJ_IncrementShareCount(&ppal->BaseObject);
+ }
+ else
+ ppal = PALETTE_ShareLockPalette(dc->ppdev->devinfo.hpalDefault);
+
+ if (psurf->SurfObj.iBitmapFormat == BMF_1BPP && !psurf->hSecure)
+ {
+ /* FIXME: palette should be gpalMono already ! */
+ EXLATEOBJ_vInitialize(&exlo, &gpalMono, &gpalRGB, 0, 0xffffff, 0);
+ }
+ else
+ {
+ EXLATEOBJ_vInitialize(&exlo, ppal, &gpalRGB, 0, 0xffffff, 0);
+ }
+
+ // check if this DC has a DIB behind it...
+ if (pso->pvScan0) // STYPE_BITMAP == pso->iType
+ {
+ ASSERT(pso->lDelta);
+ Result = XLATEOBJ_iXlate(&exlo.xlo,
+ DibFunctionsForBitmapFormat[pso->iBitmapFormat].DIB_GetPixel(pso, XPos, YPos));
+ }
+
+ EXLATEOBJ_vCleanup(&exlo);
+ PALETTE_ShareUnlockPalette(ppal);
+ }
+ }
+ DC_UnlockDc(dc);
+
+ // if Result is still CLR_INVALID, then the "quick" method above didn't work
+ if (bInRect && Result == CLR_INVALID)
+ {
+ // FIXME: create a 1x1 32BPP DIB, and blit to it
+ HDC hDCTmp = NtGdiCreateCompatibleDC(hDC);
+ if (hDCTmp)
+ {
+ static const BITMAPINFOHEADER bih = { sizeof(BITMAPINFOHEADER), 1, 1, 1, 32, BI_RGB, 0, 0, 0, 0, 0 };
+ BITMAPINFO bi;
+ RtlMoveMemory(&(bi.bmiHeader), &bih, sizeof(bih));
+ hBmpTmp = NtGdiCreateDIBitmapInternal(hDC,
+ bi.bmiHeader.biWidth,
+ bi.bmiHeader.biHeight,
+ 0,
+ NULL,
+ &bi,
+ DIB_RGB_COLORS,
+ bi.bmiHeader.biBitCount,
+ bi.bmiHeader.biSizeImage,
+ 0,
+ 0);
+
+ //HBITMAP hBmpTmp = GreCreateBitmap(1, 1, 1, 32, NULL);
+ if (hBmpTmp)
+ {
+ HBITMAP hBmpOld = (HBITMAP)NtGdiSelectBitmap(hDCTmp, hBmpTmp);
+ if (hBmpOld)
+ {
+ PSURFACE psurf;
+
+ NtGdiBitBlt(hDCTmp, 0, 0, 1, 1, hDC, XPos, YPos, SRCCOPY, 0, 0);
+ NtGdiSelectBitmap(hDCTmp, hBmpOld);
+
+ // our bitmap is no longer selected, so we can access it's stuff...
+ psurf = SURFACE_LockSurface(hBmpTmp);
+ if (psurf)
+ {
+ // Dont you need to convert something here?
+ Result = *(COLORREF*)psurf->SurfObj.pvScan0;
+ SURFACE_UnlockSurface(psurf);
+ }
+ }
+ GreDeleteObject(hBmpTmp);
+ }
+ NtGdiDeleteObjectApp(hDCTmp);
+ }
+ }
+
+ return Result;
+}
+
+
+LONG APIENTRY
+IntGetBitmapBits(
+ PSURFACE psurf,
+ DWORD Bytes,
+ OUT PBYTE Bits)
+{
+ LONG ret;
+
+ ASSERT(Bits);
+
+ /* Don't copy more bytes than the buffer has */
+ Bytes = min(Bytes, psurf->SurfObj.cjBits);
+
+#if 0
+ /* FIXME: Call DDI CopyBits here if available */
+ if (psurf->DDBitmap)
+ {
+ DPRINT("Calling device specific BitmapBits\n");
+ if (psurf->DDBitmap->funcs->pBitmapBits)
+ {
+ ret = psurf->DDBitmap->funcs->pBitmapBits(hbitmap,
+ bits,
+ count,
+ DDB_GET);
+ }
+ else
+ {
+ ERR_(bitmap)("BitmapBits == NULL??\n");
+ ret = 0;
+ }
+ }
+ else
+#endif
+ {
+ RtlCopyMemory(Bits, psurf->SurfObj.pvBits, Bytes);
+ ret = Bytes;
+ }
+ return ret;
+}
+
+VOID
+FASTCALL
+UnsafeGetBitmapBits(
+ PSURFACE psurf,
+ DWORD Bytes,
+ OUT PBYTE pvBits)
+{
+ PUCHAR pjDst, pjSrc;
+ LONG lDeltaDst, lDeltaSrc;
+ ULONG nWidth, nHeight, cBitsPixel;
+
+ nWidth = psurf->SurfObj.sizlBitmap.cx;
+ nHeight = psurf->SurfObj.sizlBitmap.cy;
+ cBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
+
+ /* Get pointers */
+ pjSrc = psurf->SurfObj.pvScan0;
+ pjDst = pvBits;
+ lDeltaSrc = psurf->SurfObj.lDelta;
+ lDeltaDst = BITMAP_GetWidthBytes(nWidth, cBitsPixel);
+
+ while (nHeight--)
+ {
+ /* Copy one line */
+ RtlCopyMemory(pjDst, pjSrc, lDeltaDst);
+ pjSrc += lDeltaSrc;
+ pjDst += lDeltaDst;
+ }
+}
+
+LONG APIENTRY
+NtGdiGetBitmapBits(
+ HBITMAP hBitmap,
+ ULONG Bytes,
+ OUT OPTIONAL PBYTE pUnsafeBits)
+{
+ PSURFACE psurf;
+ LONG bmSize, ret;
+
+ if (pUnsafeBits != NULL && Bytes == 0)
+ {
+ return 0;
+ }
+
+ psurf = SURFACE_LockSurface(hBitmap);
+ if (!psurf)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return 0;
+ }
+
+ bmSize = BITMAP_GetWidthBytes(psurf->SurfObj.sizlBitmap.cx,
+ BitsPerFormat(psurf->SurfObj.iBitmapFormat)) *
+ abs(psurf->SurfObj.sizlBitmap.cy);
+
+ /* If the bits vector is null, the function should return the read size */
+ if (pUnsafeBits == NULL)
+ {
+ SURFACE_UnlockSurface(psurf);
+ return bmSize;
+ }
+
+ /* Don't copy more bytes than the buffer has */
+ Bytes = min(Bytes, bmSize);
+
+ // FIXME: use MmSecureVirtualMemory
+ _SEH2_TRY
+ {
+ ProbeForWrite(pUnsafeBits, Bytes, 1);
+ UnsafeGetBitmapBits(psurf, Bytes, pUnsafeBits);
+ ret = Bytes;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ret = 0;
+ }
+ _SEH2_END
+
+ SURFACE_UnlockSurface(psurf);
+
+ return ret;
+}
+
+
+LONG APIENTRY
+NtGdiSetBitmapBits(
+ HBITMAP hBitmap,
+ DWORD Bytes,
+ IN PBYTE pUnsafeBits)
+{
+ LONG ret;
+ PSURFACE psurf;
+
+ if (pUnsafeBits == NULL || Bytes == 0)
+ {
+ return 0;
+ }
+
+ psurf = SURFACE_LockSurface(hBitmap);
+ if (psurf == NULL)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return 0;
+ }
+
+ _SEH2_TRY
+ {
+ ProbeForRead(pUnsafeBits, Bytes, 1);
+ UnsafeSetBitmapBits(psurf, Bytes, pUnsafeBits);
+ ret = 1;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ret = 0;
+ }
+ _SEH2_END
+
+ SURFACE_UnlockSurface(psurf);
+
+ return ret;
+}
+
+BOOL APIENTRY
+NtGdiSetBitmapDimension(
+ HBITMAP hBitmap,
+ INT Width,
+ INT Height,
+ LPSIZE Size)
+{
+ PSURFACE psurf;
+ BOOL Ret = TRUE;
+
+ if (hBitmap == NULL)
+ return FALSE;
+
+ psurf = SURFACE_LockSurface(hBitmap);
+ if (psurf == NULL)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ if (Size)
+ {
+ _SEH2_TRY
+ {
+ ProbeForWrite(Size, sizeof(SIZE), 1);
+ *Size = psurf->sizlDim;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Ret = FALSE;
+ }
+ _SEH2_END
+ }
+
+ /* The dimension is changed even if writing the old value failed */
+ psurf->sizlDim.cx = Width;
+ psurf->sizlDim.cy = Height;
+
+ SURFACE_UnlockSurface(psurf);
+
+ return Ret;
+}
+
+VOID IntHandleSpecialColorType(HDC hDC, COLORREF* Color)
+{
+ PDC pdc = NULL;
+ RGBQUAD quad;
+ PALETTEENTRY palEntry;
+ UINT index;
+
+ switch (*Color >> 24)
+ {
+ case 0x10: /* DIBINDEX */
+ if (IntGetDIBColorTable(hDC, LOWORD(*Color), 1, &quad) == 1)
+ {
+ *Color = RGB(quad.rgbRed, quad.rgbGreen, quad.rgbBlue);
+ }
+ else
+ {
+ /* Out of color table bounds - use black */
+ *Color = RGB(0, 0, 0);
+ }
+ break;
+ case 0x02: /* PALETTERGB */
+ pdc = DC_LockDc(hDC);
+ if (pdc->dclevel.hpal != NtGdiGetStockObject(DEFAULT_PALETTE))
+ {
+ index = NtGdiGetNearestPaletteIndex(pdc->dclevel.hpal, *Color);
+ IntGetPaletteEntries(pdc->dclevel.hpal, index, 1, &palEntry);
+ *Color = RGB(palEntry.peRed, palEntry.peGreen, palEntry.peBlue);
+ }
+ else
+ {
+ /* Use the pure color */
+ *Color = *Color & 0x00FFFFFF;
+ }
+ DC_UnlockDc(pdc);
+ break;
+ case 0x01: /* PALETTEINDEX */
+ pdc = DC_LockDc(hDC);
+ if (IntGetPaletteEntries(pdc->dclevel.hpal, LOWORD(*Color), 1, &palEntry) == 1)
+ {
+ *Color = RGB(palEntry.peRed, palEntry.peGreen, palEntry.peBlue);
+ }
+ else
+ {
+ /* Index does not exist, use zero index */
+ IntGetPaletteEntries(pdc->dclevel.hpal, 0, 1, &palEntry);
+ *Color = RGB(palEntry.peRed, palEntry.peGreen, palEntry.peBlue);
+ }
+ DC_UnlockDc(pdc);
+ break;
+ default:
+ DPRINT("Unsupported color type %d passed\n", *Color >> 24);
+ break;
+ }
+}
+
+BOOL APIENTRY
+GdiSetPixelV(
+ HDC hDC,
+ INT X,
+ INT Y,
+ COLORREF Color)
+{
+ HBRUSH hBrush;
+ HGDIOBJ OldBrush;
+
+ if ((Color & 0xFF000000) != 0)
+ {
+ IntHandleSpecialColorType(hDC, &Color);
+ }
+
+ hBrush = NtGdiCreateSolidBrush(Color, NULL);
+ if (hBrush == NULL)
+ return FALSE;
+
+ OldBrush = NtGdiSelectBrush(hDC, hBrush);
+ if (OldBrush == NULL)
+ {
+ GreDeleteObject(hBrush);
+ return FALSE;
+ }
+
+ NtGdiPatBlt(hDC, X, Y, 1, 1, PATCOPY);
+ NtGdiSelectBrush(hDC, OldBrush);
+ GreDeleteObject(hBrush);
+
+ return TRUE;
+}
+
+COLORREF APIENTRY
+NtGdiSetPixel(
+ HDC hDC,
+ INT X,
+ INT Y,
+ COLORREF Color)
+{
+ DPRINT("0 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
+
+ if (GdiSetPixelV(hDC,X,Y,Color))
+ {
+ Color = NtGdiGetPixel(hDC,X,Y);
+ DPRINT("1 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
+ return Color;
+ }
+
+ Color = (COLORREF)CLR_INVALID;
+ DPRINT("2 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
+ return Color;
+}
+
+
+/* Internal Functions */
+
+UINT FASTCALL
+BITMAP_GetRealBitsPixel(UINT nBitsPixel)
+{
+ if (nBitsPixel <= 1)
+ return 1;
+ if (nBitsPixel <= 4)
+ return 4;
+ if (nBitsPixel <= 8)
+ return 8;
+ if (nBitsPixel <= 16)
+ return 16;
+ if (nBitsPixel <= 24)
+ return 24;
+ if (nBitsPixel <= 32)
+ return 32;
+
+ return 0;
+}
+
+INT FASTCALL
+BITMAP_GetWidthBytes(INT bmWidth, INT bpp)
+{
+#if 0
+ switch (bpp)
+ {
+ case 1:
+ return 2 * ((bmWidth+15) >> 4);
+
+ case 24:
+ bmWidth *= 3; /* fall through */
+ case 8:
+ return bmWidth + (bmWidth & 1);
+
+ case 32:
+ return bmWidth * 4;
+
+ case 16:
+ case 15:
+ return bmWidth * 2;
+
+ case 4:
+ return 2 * ((bmWidth+3) >> 2);
+
+ default:
+ DPRINT ("stub");
+ }
+
+ return -1;
+#endif
+
+ return ((bmWidth * bpp + 15) & ~15) >> 3;
+}
+
+HBITMAP FASTCALL
+BITMAP_CopyBitmap(HBITMAP hBitmap)
+{
+ HBITMAP res;
+ BITMAP bm;
+ SURFACE *Bitmap, *resBitmap;
+ SIZEL Size;
+
+ if (hBitmap == NULL)
+ {
+ return 0;
+ }
+
+ Bitmap = SURFACE_LockSurface(hBitmap);
+ if (Bitmap == NULL)
+ {
+ return 0;
+ }
+
+ BITMAP_GetObject(Bitmap, sizeof(BITMAP), (PVOID)&bm);
+ bm.bmBits = NULL;
+ if (Bitmap->SurfObj.lDelta >= 0)
+ bm.bmHeight = -bm.bmHeight;
+
+ Size.cx = abs(bm.bmWidth);
+ Size.cy = abs(bm.bmHeight);
+ res = GreCreateBitmapEx(Size.cx,
+ Size.cy,
+ bm.bmWidthBytes,
+ Bitmap->SurfObj.iBitmapFormat,
+ Bitmap->SurfObj.fjBitmap,
+ Bitmap->SurfObj.cjBits,
+ NULL,
+ Bitmap->flags);
+
+
+ if (res)
+ {
+ resBitmap = SURFACE_LockSurface(res);
+ if (resBitmap)
+ {
+ IntSetBitmapBits(resBitmap, Bitmap->SurfObj.cjBits, Bitmap->SurfObj.pvBits);
++ resBitmap->ppal = Bitmap->ppal;
++ GDIOBJ_IncrementShareCount((POBJ)Bitmap->ppal);
+ SURFACE_UnlockSurface(resBitmap);
+ }
+ else
+ {
+ GreDeleteObject(res);
+ res = NULL;
+ }
+ }
+
+ SURFACE_UnlockSurface(Bitmap);
+
+ return res;
+}
+
+INT APIENTRY
+BITMAP_GetObject(SURFACE *psurf, INT Count, LPVOID buffer)
+{
+ PBITMAP pBitmap;
+
+ if (!buffer) return sizeof(BITMAP);
+ if ((UINT)Count < sizeof(BITMAP)) return 0;
+
+ /* always fill a basic BITMAP structure */
+ pBitmap = buffer;
+ pBitmap->bmType = 0;
+ pBitmap->bmWidth = psurf->SurfObj.sizlBitmap.cx;
+ pBitmap->bmHeight = psurf->SurfObj.sizlBitmap.cy;
+ pBitmap->bmPlanes = 1;
+ pBitmap->bmBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
+ pBitmap->bmWidthBytes = BITMAP_GetWidthBytes(pBitmap->bmWidth, pBitmap->bmBitsPixel);
+
+ /* Check for DIB section */
+ if (psurf->hSecure)
+ {
+ /* Set bmBits in this case */
+ pBitmap->bmBits = psurf->SurfObj.pvBits;
+ /* DIBs data are 32 bits aligned */
+ pBitmap->bmWidthBytes = DIB_GetDIBWidthBytes(pBitmap->bmWidth, pBitmap->bmBitsPixel);
+
+ if (Count >= sizeof(DIBSECTION))
+ {
+ /* Fill rest of DIBSECTION */
+ PDIBSECTION pds = buffer;
+
+ pds->dsBmih.biSize = sizeof(BITMAPINFOHEADER);
+ pds->dsBmih.biWidth = pds->dsBm.bmWidth;
+ pds->dsBmih.biHeight = pds->dsBm.bmHeight;
+ pds->dsBmih.biPlanes = pds->dsBm.bmPlanes;
+ pds->dsBmih.biBitCount = pds->dsBm.bmBitsPixel;
+ if(psurf->ppal->Mode & PAL_BITFIELDS)
+ {
+ pds->dsBmih.biCompression = BI_BITFIELDS;
+ }
+ else
+ {
+ switch (psurf->SurfObj.iBitmapFormat)
+ {
+ case BMF_1BPP:
+ case BMF_4BPP:
+ case BMF_8BPP:
+ case BMF_16BPP:
+ case BMF_24BPP:
+ case BMF_32BPP:
+ pds->dsBmih.biCompression = BI_RGB;
+ break;
+ case BMF_4RLE:
+ pds->dsBmih.biCompression = BI_RLE4;
+ break;
+ case BMF_8RLE:
+ pds->dsBmih.biCompression = BI_RLE8;
+ break;
+ case BMF_JPEG:
+ pds->dsBmih.biCompression = BI_JPEG;
+ break;
+ case BMF_PNG:
+ pds->dsBmih.biCompression = BI_PNG;
+ break;
+ }
+ }
+ pds->dsBmih.biSizeImage = psurf->SurfObj.cjBits;
+ pds->dsBmih.biXPelsPerMeter = 0;
+ pds->dsBmih.biYPelsPerMeter = 0;
+ pds->dsBmih.biClrUsed = psurf->ppal->NumColors;
+ pds->dsBmih.biClrImportant = psurf->biClrImportant;
+ pds->dsBitfields[0] = psurf->ppal->RedMask;
+ pds->dsBitfields[1] = psurf->ppal->GreenMask;
+ pds->dsBitfields[2] = psurf->ppal->BlueMask;
+ pds->dshSection = psurf->hDIBSection;
+ pds->dsOffset = psurf->dwOffset;
+
+ return sizeof(DIBSECTION);
+ }
+ }
+ else
+ {
+ /* not set according to wine test, confirmed in win2k */
+ pBitmap->bmBits = NULL;
+ }
+
+ return sizeof(BITMAP);
+}
+
+/*
+ * @implemented
+ */
+HDC
+APIENTRY
+NtGdiGetDCforBitmap(
+ IN HBITMAP hsurf)
+{
+ HDC hdc = NULL;
+ PSURFACE psurf = SURFACE_LockSurface(hsurf);
+ if (psurf)
+ {
+ hdc = psurf->hdc;
+ SURFACE_UnlockSurface(psurf);
+ }
+ return hdc;
+}
+
+
+/* EOF */