1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Win32k subsystem 4 * PURPOSE: Functions for saving and restoring dc states 5 * FILE: win32ss/gdi/ntgdi/dcstate.c 6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@rectos.org) 7 */ 8 9 #include <win32k.h> 10 11 #define NDEBUG 12 #include <debug.h> 13 14 VOID 15 FASTCALL 16 DC_vCopyState(PDC pdcSrc, PDC pdcDst, BOOL To) 17 { 18 DPRINT("DC_vCopyState(%p, %p)\n", pdcSrc->BaseObject.hHmgr, pdcDst->BaseObject.hHmgr); 19 20 /* Copy full DC attribute */ 21 *pdcDst->pdcattr = *pdcSrc->pdcattr; 22 23 /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */ 24 /* The VisRectRegion field needs to be set to a valid state */ 25 26 /* Mark some fields as dirty */ 27 pdcDst->pdcattr->ulDirty_ |= (DIRTY_FILL|DIRTY_LINE|DIRTY_TEXT|DIRTY_BACKGROUND|DIRTY_CHARSET|DC_ICM_NOT_CALIBRATED|DC_ICM_NOT_SET); // Note: Use if, To is FALSE.... 28 29 /* Copy DC level */ 30 pdcDst->dclevel.pColorSpace = pdcSrc->dclevel.pColorSpace; 31 pdcDst->dclevel.laPath = pdcSrc->dclevel.laPath; 32 pdcDst->dclevel.ca = pdcSrc->dclevel.ca; 33 pdcDst->dclevel.mxWorldToDevice = pdcSrc->dclevel.mxWorldToDevice; 34 pdcDst->dclevel.mxDeviceToWorld = pdcSrc->dclevel.mxDeviceToWorld; 35 pdcDst->dclevel.mxWorldToPage = pdcSrc->dclevel.mxWorldToPage; 36 pdcDst->dclevel.efM11PtoD = pdcSrc->dclevel.efM11PtoD; 37 pdcDst->dclevel.efM22PtoD = pdcSrc->dclevel.efM22PtoD; 38 pdcDst->dclevel.sizl = pdcSrc->dclevel.sizl; 39 pdcDst->dclevel.hpal = pdcSrc->dclevel.hpal; 40 41 /* Handle references here correctly */ 42 DC_vSelectFillBrush(pdcDst, pdcSrc->dclevel.pbrFill); 43 DC_vSelectLineBrush(pdcDst, pdcSrc->dclevel.pbrLine); 44 DC_vSelectPalette(pdcDst, pdcSrc->dclevel.ppal); 45 46 /* Dereference the old font, reference the new one */ 47 if (pdcDst->dclevel.plfnt) LFONT_ShareUnlockFont(pdcDst->dclevel.plfnt); /// @todo should aways be != NULL 48 GDIOBJ_vReferenceObjectByPointer(&pdcSrc->dclevel.plfnt->BaseObject); 49 pdcDst->dclevel.plfnt = pdcSrc->dclevel.plfnt; 50 51 /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */ 52 if (!To) 53 { 54 IntGdiExtSelectClipRgn(pdcDst, pdcSrc->dclevel.prgnClip, RGN_COPY); 55 if (pdcDst->dclevel.prgnMeta) 56 { 57 REGION_Delete(pdcDst->dclevel.prgnMeta); 58 pdcDst->dclevel.prgnMeta = NULL; 59 } 60 /* The only way to reset the Meta Region to its original state is to return to a previously saved version of the DC with SaveDC. */ 61 if (pdcSrc->dclevel.prgnMeta) 62 { 63 pdcDst->dclevel.prgnMeta = IntSysCreateRectpRgn(0, 0, 0, 0); 64 IntGdiCombineRgn(pdcDst->dclevel.prgnMeta, pdcSrc->dclevel.prgnMeta, NULL, RGN_COPY); 65 } 66 pdcDst->fs |= DC_DIRTY_RAO; 67 } 68 } 69 70 71 BOOL 72 FASTCALL 73 IntGdiCleanDC(HDC hDC) 74 { 75 PDC dc; 76 if (!hDC) return FALSE; 77 dc = DC_LockDc(hDC); 78 if (!dc) return FALSE; 79 // Clean the DC 80 if (defaultDCstate) 81 { 82 DC_vCopyState(defaultDCstate, dc, FALSE); 83 /* Update the brushes now, because they reference some objects (the DC palette) 84 * Which belong to the current process, and this DC might be used for another process 85 * after being cleaned up (for GetDC(0) for instance) */ 86 DC_vUpdateFillBrush(dc); 87 DC_vUpdateBackgroundBrush(dc); 88 DC_vUpdateLineBrush(dc); 89 DC_vUpdateTextBrush(dc); 90 } 91 92 // Remove Path and reset flags. 93 if (dc->dclevel.hPath) 94 { 95 DPRINT("Clean DC Remove Path\n"); 96 if (!PATH_Delete(dc->dclevel.hPath)) 97 { 98 DPRINT1("Failed to remove Path\n"); 99 } 100 dc->dclevel.hPath = 0; 101 dc->dclevel.flPath = 0; 102 } 103 104 /* DC_vCopyState frees the Clip rgn and the Meta rgn. Take care of the other ones 105 * There is no need to clear prgnVis, as UserGetDC updates it immediately. */ 106 if (dc->prgnRao) 107 REGION_Delete(dc->prgnRao); 108 if (dc->prgnAPI) 109 REGION_Delete(dc->prgnAPI); 110 dc->prgnRao = dc->prgnAPI = NULL; 111 112 dc->fs |= DC_DIRTY_RAO; 113 114 DC_UnlockDc(dc); 115 116 return TRUE; 117 } 118 119 __kernel_entry 120 BOOL 121 APIENTRY 122 NtGdiResetDC( 123 _In_ HDC hdc, 124 _In_ LPDEVMODEW pdm, 125 _Out_ PBOOL pbBanding, 126 _In_opt_ DRIVER_INFO_2W *pDriverInfo2, 127 _At_((PUMDHPDEV*)ppUMdhpdev, _Out_) PVOID ppUMdhpdev) 128 { 129 /* According to a comment in Windows SDK the size of the buffer for 130 pdm is (pdm->dmSize + pdm->dmDriverExtra) */ 131 UNIMPLEMENTED; 132 return FALSE; 133 } 134 135 136 VOID 137 NTAPI 138 DC_vRestoreDC( 139 IN PDC pdc, 140 INT iSaveLevel) 141 { 142 HDC hdcSave; 143 PDC pdcSave; 144 145 NT_ASSERT(iSaveLevel > 0); 146 DPRINT("DC_vRestoreDC(%p, %ld)\n", pdc->BaseObject.hHmgr, iSaveLevel); 147 148 /* Loop the save levels */ 149 while (pdc->dclevel.lSaveDepth > iSaveLevel) 150 { 151 hdcSave = pdc->dclevel.hdcSave; 152 DPRINT("RestoreDC = %p\n", hdcSave); 153 154 /* Set us as the owner */ 155 if (!GreSetObjectOwner(hdcSave, GDI_OBJ_HMGR_POWNED)) 156 { 157 /* Could not get ownership. That's bad! */ 158 DPRINT1("Could not get ownership of saved DC (%p) for hdc %p!\n", 159 hdcSave, pdc->BaseObject.hHmgr); 160 NT_ASSERT(FALSE); 161 return;// FALSE; 162 } 163 164 /* Lock the saved dc */ 165 pdcSave = DC_LockDc(hdcSave); 166 if (!pdcSave) 167 { 168 /* WTF? Internal error! */ 169 DPRINT1("Could not lock the saved DC (%p) for dc %p!\n", 170 hdcSave, pdc->BaseObject.hHmgr); 171 NT_ASSERT(FALSE); 172 return;// FALSE; 173 } 174 175 /* Remove the saved dc from the queue */ 176 pdc->dclevel.hdcSave = pdcSave->dclevel.hdcSave; 177 178 /* Decrement save level */ 179 pdc->dclevel.lSaveDepth--; 180 181 /* Is this the state we want? */ 182 if (pdc->dclevel.lSaveDepth == iSaveLevel) 183 { 184 /* Copy the state back */ 185 DC_vCopyState(pdcSave, pdc, FALSE); 186 187 /* Only memory DC's change their surface */ 188 if (pdc->dctype == DCTYPE_MEMORY) 189 DC_vSelectSurface(pdc, pdcSave->dclevel.pSurface); 190 191 if (pdcSave->dclevel.hPath) 192 { 193 PATH_RestorePath( pdc, pdcSave ); 194 } 195 } 196 197 /* Prevent save dc from being restored */ 198 pdcSave->dclevel.lSaveDepth = 1; 199 200 /* Unlock it */ 201 DC_UnlockDc(pdcSave); 202 /* Delete the saved dc */ 203 GreDeleteObject(hdcSave); 204 } 205 206 DPRINT("Leave DC_vRestoreDC()\n"); 207 } 208 209 210 211 BOOL 212 APIENTRY 213 NtGdiRestoreDC( 214 HDC hdc, 215 INT iSaveLevel) 216 { 217 PDC pdc; 218 219 DPRINT("NtGdiRestoreDC(%p, %d)\n", hdc, iSaveLevel); 220 221 /* Lock the original DC */ 222 pdc = DC_LockDc(hdc); 223 if (!pdc) 224 { 225 EngSetLastError(ERROR_INVALID_HANDLE); 226 return FALSE; 227 } 228 229 ASSERT(pdc->dclevel.lSaveDepth > 0); 230 231 /* Negative values are relative to the stack top */ 232 if (iSaveLevel < 0) 233 iSaveLevel = pdc->dclevel.lSaveDepth + iSaveLevel; 234 235 /* Check if we have a valid instance */ 236 if (iSaveLevel <= 0 || iSaveLevel >= pdc->dclevel.lSaveDepth) 237 { 238 DPRINT("Illegal save level, requested: %ld, current: %ld\n", 239 iSaveLevel, pdc->dclevel.lSaveDepth); 240 DC_UnlockDc(pdc); 241 EngSetLastError(ERROR_INVALID_PARAMETER); 242 return FALSE; 243 } 244 245 /* Call the internal function */ 246 DC_vRestoreDC(pdc, iSaveLevel); 247 248 DC_UnlockDc(pdc); 249 250 DPRINT("Leave NtGdiRestoreDC\n"); 251 return TRUE; 252 } 253 254 255 INT 256 APIENTRY 257 NtGdiSaveDC( 258 HDC hDC) 259 { 260 HDC hdcSave; 261 PDC pdc, pdcSave; 262 INT lSaveDepth; 263 264 DPRINT("NtGdiSaveDC(%p)\n", hDC); 265 266 /* Lock the original dc */ 267 pdc = DC_LockDc(hDC); 268 if (pdc == NULL) 269 { 270 DPRINT("Could not lock DC\n"); 271 EngSetLastError(ERROR_INVALID_HANDLE); 272 return 0; 273 } 274 275 /* Allocate a new dc */ 276 pdcSave = DC_AllocDcWithHandle(GDILoObjType_LO_DC_TYPE); 277 if (pdcSave == NULL) 278 { 279 DPRINT("Could not allocate a new DC\n"); 280 DC_UnlockDc(pdc); 281 return 0; 282 } 283 hdcSave = pdcSave->BaseObject.hHmgr; 284 285 PDEVOBJ_vReference(pdc->ppdev); 286 DC_vInitDc(pdcSave, DCTYPE_MEMORY, pdc->ppdev); 287 288 /* Handle references here correctly */ 289 //pdcSrc->dclevel.pSurface = NULL; 290 //pdcSrc->dclevel.pbrFill = NULL; 291 //pdcSrc->dclevel.pbrLine = NULL; 292 //pdcSrc->dclevel.ppal = NULL; 293 294 /* Make it a kernel handle 295 (FIXME: Windows handles this differently, see Wiki) */ 296 GDIOBJ_vSetObjectOwner(&pdcSave->BaseObject, GDI_OBJ_HMGR_PUBLIC); 297 298 /* Copy the current state */ 299 DC_vCopyState(pdc, pdcSave, FALSE); 300 301 /* Only memory DC's change their surface */ 302 if (pdc->dctype == DCTYPE_MEMORY) 303 DC_vSelectSurface(pdcSave, pdc->dclevel.pSurface); 304 305 /* Copy path */ 306 if (pdc->dclevel.hPath) 307 { 308 PATH_SavePath( pdcSave, pdc ); 309 } 310 pdcSave->dclevel.flPath = pdc->dclevel.flPath | DCPATH_SAVESTATE; 311 312 /* Set new dc as save dc */ 313 pdcSave->dclevel.hdcSave = pdc->dclevel.hdcSave; 314 pdc->dclevel.hdcSave = hdcSave; 315 316 /* Increase save depth, return old value */ 317 lSaveDepth = pdc->dclevel.lSaveDepth++; 318 319 /* Cleanup and return */ 320 DC_UnlockDc(pdcSave); 321 DC_UnlockDc(pdc); 322 323 DPRINT("Leave NtGdiSaveDC: %ld, hdcSave = %p\n", lSaveDepth, hdcSave); 324 return lSaveDepth; 325 } 326 327 /* EOF */ 328