1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: GDI alpha blending functions 5 * FILE: win32ss/gdi/eng/alphablend.c 6 * PROGRAMER: Jason Filby 7 */ 8 9 #include <win32k.h> 10 11 #define NDEBUG 12 #include <debug.h> 13 14 15 /* 16 * @implemented 17 */ 18 BOOL 19 APIENTRY 20 EngAlphaBlend( 21 _Inout_ SURFOBJ *psoDest, 22 _In_ SURFOBJ *psoSource, 23 _In_opt_ CLIPOBJ *ClipRegion, 24 _In_opt_ XLATEOBJ *ColorTranslation, 25 _In_ RECTL *DestRect, 26 _In_ RECTL *SourceRect, 27 _In_ BLENDOBJ *BlendObj) 28 { 29 RECTL InputRect; 30 RECTL OutputRect; 31 RECTL ClipRect; 32 RECTL CombinedRect; 33 RECTL Rect; 34 POINTL Translate; 35 INTENG_ENTER_LEAVE EnterLeaveSource; 36 INTENG_ENTER_LEAVE EnterLeaveDest; 37 SURFOBJ* InputObj; 38 SURFOBJ* OutputObj; 39 LONG ClippingType; 40 RECT_ENUM RectEnum; 41 BOOL EnumMore; 42 ULONG i; 43 BOOLEAN Ret; 44 45 DPRINT("EngAlphaBlend(psoDest:0x%p, psoSource:0x%p, ClipRegion:0x%p, ColorTranslation:0x%p,\n", psoDest, psoSource, ClipRegion, ColorTranslation); 46 DPRINT(" DestRect:{0x%x, 0x%x, 0x%x, 0x%x}, SourceRect:{0x%x, 0x%x, 0x%x, 0x%x},\n", 47 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom, 48 SourceRect->left, SourceRect->top, SourceRect->right, SourceRect->bottom); 49 DPRINT(" BlendObj:{0x%x, 0x%x, 0x%x, 0x%x}\n", BlendObj->BlendFunction.BlendOp, 50 BlendObj->BlendFunction.BlendFlags, BlendObj->BlendFunction.SourceConstantAlpha, 51 BlendObj->BlendFunction.AlphaFormat); 52 53 /* Validate output */ 54 OutputRect = *DestRect; 55 RECTL_vMakeWellOrdered(&OutputRect); 56 57 /* Validate input */ 58 InputRect = *SourceRect; 59 RECTL_vMakeWellOrdered(&InputRect); 60 if ( (InputRect.top < 0) || (InputRect.bottom < 0) || 61 (InputRect.left < 0) || (InputRect.right < 0) || 62 InputRect.right > psoSource->sizlBitmap.cx || 63 InputRect.bottom > psoSource->sizlBitmap.cy ) 64 { 65 EngSetLastError(ERROR_INVALID_PARAMETER); 66 return FALSE; 67 } 68 69 if (psoDest == psoSource && 70 !(OutputRect.left >= SourceRect->right || InputRect.left >= OutputRect.right || 71 OutputRect.top >= SourceRect->bottom || InputRect.top >= OutputRect.bottom)) 72 { 73 DPRINT1("Source and destination rectangles overlap!\n"); 74 return FALSE; 75 } 76 77 if (BlendObj->BlendFunction.BlendOp != AC_SRC_OVER) 78 { 79 DPRINT1("BlendOp != AC_SRC_OVER (0x%x)\n", BlendObj->BlendFunction.BlendOp); 80 return FALSE; 81 } 82 if (BlendObj->BlendFunction.BlendFlags != 0) 83 { 84 DPRINT1("BlendFlags != 0 (0x%x)\n", BlendObj->BlendFunction.BlendFlags); 85 return FALSE; 86 } 87 if ((BlendObj->BlendFunction.AlphaFormat & ~AC_SRC_ALPHA) != 0) 88 { 89 DPRINT1("Unsupported AlphaFormat (0x%x)\n", BlendObj->BlendFunction.AlphaFormat); 90 return FALSE; 91 } 92 93 /* Check if there is anything to draw */ 94 if (ClipRegion != NULL && 95 (ClipRegion->rclBounds.left >= ClipRegion->rclBounds.right || 96 ClipRegion->rclBounds.top >= ClipRegion->rclBounds.bottom)) 97 { 98 /* Nothing to do */ 99 return TRUE; 100 } 101 102 /* Now call the DIB function */ 103 if (!IntEngEnter(&EnterLeaveSource, psoSource, &InputRect, TRUE, &Translate, &InputObj)) 104 { 105 return FALSE; 106 } 107 InputRect.left += Translate.x; 108 InputRect.right += Translate.x; 109 InputRect.top += Translate.y; 110 InputRect.bottom += Translate.y; 111 112 if (!IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &OutputObj)) 113 { 114 IntEngLeave(&EnterLeaveSource); 115 return FALSE; 116 } 117 OutputRect.left += Translate.x; 118 OutputRect.right += Translate.x; 119 OutputRect.top += Translate.y; 120 OutputRect.bottom += Translate.y; 121 122 ASSERT(InputRect.left <= InputRect.right && InputRect.top <= InputRect.bottom); 123 124 Ret = FALSE; 125 ClippingType = (ClipRegion == NULL) ? DC_TRIVIAL : ClipRegion->iDComplexity; 126 switch (ClippingType) 127 { 128 case DC_TRIVIAL: 129 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend( 130 OutputObj, InputObj, &OutputRect, &InputRect, ClipRegion, ColorTranslation, BlendObj); 131 break; 132 133 case DC_RECT: 134 Ret = TRUE; 135 ClipRect.left = ClipRegion->rclBounds.left + Translate.x; 136 ClipRect.right = ClipRegion->rclBounds.right + Translate.x; 137 ClipRect.top = ClipRegion->rclBounds.top + Translate.y; 138 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y; 139 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect)) 140 { 141 /* take into acount clipping results when calculating new input rect (scaled to input rect size) */ 142 Rect.left = InputRect.left + (CombinedRect.left - OutputRect.left) * (InputRect.right - InputRect.left) / (OutputRect.right - OutputRect.left); 143 Rect.right = InputRect.right + (CombinedRect.right - OutputRect.right) * (InputRect.right - InputRect.left) / (OutputRect.right - OutputRect.left); 144 Rect.top = InputRect.top + (CombinedRect.top - OutputRect.top) * (InputRect.bottom - InputRect.top) / (OutputRect.bottom - OutputRect.top); 145 Rect.bottom = InputRect.bottom + (CombinedRect.bottom - OutputRect.bottom) * (InputRect.bottom - InputRect.top) / (OutputRect.bottom - OutputRect.top); 146 147 /* Aplha blend one rect */ 148 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend( 149 OutputObj, InputObj, &CombinedRect, &Rect, ClipRegion, ColorTranslation, BlendObj); 150 } 151 break; 152 153 case DC_COMPLEX: 154 Ret = TRUE; 155 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, CD_ANY, 0); 156 do 157 { 158 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), 159 (PVOID) &RectEnum); 160 161 for (i = 0; i < RectEnum.c; i++) 162 { 163 ClipRect.left = RectEnum.arcl[i].left + Translate.x; 164 ClipRect.right = RectEnum.arcl[i].right + Translate.x; 165 ClipRect.top = RectEnum.arcl[i].top + Translate.y; 166 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y; 167 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect)) 168 { 169 /* take into acount clipping results when calculating new input rect (scaled to input rect size) */ 170 Rect.left = InputRect.left + (CombinedRect.left - OutputRect.left) * (InputRect.right - InputRect.left) / (OutputRect.right - OutputRect.left); 171 Rect.right = InputRect.right + (CombinedRect.right - OutputRect.right) * (InputRect.right - InputRect.left) / (OutputRect.right - OutputRect.left); 172 Rect.top = InputRect.top + (CombinedRect.top - OutputRect.top) * (InputRect.bottom - InputRect.top) / (OutputRect.bottom - OutputRect.top); 173 Rect.bottom = InputRect.bottom + (CombinedRect.bottom - OutputRect.bottom) * (InputRect.bottom - InputRect.top) / (OutputRect.bottom - OutputRect.top); 174 175 /* Alpha blend one rect */ 176 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend( 177 OutputObj, InputObj, &CombinedRect, &Rect, ClipRegion, ColorTranslation, BlendObj) && Ret; 178 } 179 } 180 } 181 while (EnumMore); 182 break; 183 184 default: 185 UNIMPLEMENTED; 186 ASSERT(FALSE); 187 break; 188 } 189 190 IntEngLeave(&EnterLeaveDest); 191 IntEngLeave(&EnterLeaveSource); 192 193 return Ret; 194 } 195 196 BOOL 197 APIENTRY 198 IntEngAlphaBlend( 199 _Inout_ SURFOBJ *psoDest, 200 _In_ SURFOBJ *psoSource, 201 _In_opt_ CLIPOBJ *pco, 202 _In_opt_ XLATEOBJ *pxlo, 203 _In_ RECTL *prclDest, 204 _In_ RECTL *prclSrc, 205 _In_ BLENDOBJ *pBlendObj) 206 { 207 BOOL ret = FALSE; 208 SURFACE *psurfDest; 209 210 ASSERT(psoDest); 211 ASSERT(psoSource); 212 ASSERT(prclDest); 213 ASSERT(prclSrc); 214 //ASSERT(pBlendObj); 215 216 /* If no clip object is given, use trivial one */ 217 if (!pco) pco = (CLIPOBJ *)&gxcoTrivial; 218 219 /* Check if there is anything to draw */ 220 if ((pco->rclBounds.left >= pco->rclBounds.right) || 221 (pco->rclBounds.top >= pco->rclBounds.bottom)) 222 { 223 /* Nothing to do */ 224 return TRUE; 225 } 226 227 psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj); 228 229 /* Call the driver's DrvAlphaBlend if available */ 230 if (psurfDest->flags & HOOK_ALPHABLEND) 231 { 232 ret = GDIDEVFUNCS(psoDest).AlphaBlend( 233 psoDest, psoSource, pco, pxlo, 234 prclDest, prclSrc, pBlendObj); 235 } 236 237 if (!ret) 238 { 239 ret = EngAlphaBlend(psoDest, psoSource, pco, pxlo, 240 prclDest, prclSrc, pBlendObj); 241 } 242 243 return ret; 244 } 245 246 /* 247 * @implemented 248 */ 249 BOOL 250 APIENTRY 251 NtGdiEngAlphaBlend(IN SURFOBJ *psoDest, 252 IN SURFOBJ *psoSource, 253 IN CLIPOBJ *ClipRegion, 254 IN XLATEOBJ *ColorTranslation, 255 IN PRECTL upDestRect, 256 IN PRECTL upSourceRect, 257 IN BLENDOBJ *BlendObj) 258 { 259 RECTL DestRect; 260 RECTL SourceRect; 261 262 _SEH2_TRY 263 { 264 ProbeForRead(upDestRect, sizeof(RECTL), 1); 265 RtlCopyMemory(&DestRect,upDestRect, sizeof(RECTL)); 266 267 ProbeForRead(upSourceRect, sizeof(RECTL), 1); 268 RtlCopyMemory(&SourceRect, upSourceRect, sizeof(RECTL)); 269 270 } 271 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 272 { 273 _SEH2_YIELD(return FALSE); 274 } 275 _SEH2_END; 276 277 return EngAlphaBlend(psoDest, psoSource, ClipRegion, ColorTranslation, &DestRect, &SourceRect, BlendObj); 278 } 279 280