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 if (pdcSrc->dclevel.prgnMeta) 61 { 62 pdcDst->dclevel.prgnMeta = IntSysCreateRectpRgn(0, 0, 0, 0); 63 IntGdiCombineRgn(pdcDst->dclevel.prgnMeta, pdcSrc->dclevel.prgnMeta, NULL, RGN_COPY); 64 } 65 pdcDst->fs |= DC_FLAG_DIRTY_RAO; 66 } 67 } 68 69 70 BOOL 71 FASTCALL 72 IntGdiCleanDC(HDC hDC) 73 { 74 PDC dc; 75 if (!hDC) return FALSE; 76 dc = DC_LockDc(hDC); 77 if (!dc) return FALSE; 78 // Clean the DC 79 if (defaultDCstate) 80 { 81 DC_vCopyState(defaultDCstate, dc, FALSE); 82 /* Update the brushes now, because they reference some objects (the DC palette) 83 * Which belong to the current process, and this DC might be used for another process 84 * after being cleaned up (for GetDC(0) for instance) */ 85 DC_vUpdateFillBrush(dc); 86 DC_vUpdateBackgroundBrush(dc); 87 DC_vUpdateLineBrush(dc); 88 DC_vUpdateTextBrush(dc); 89 } 90 91 // Remove Path and reset flags. 92 if (dc->dclevel.hPath) 93 { 94 DPRINT("Clean DC Remove Path\n"); 95 if (!PATH_Delete(dc->dclevel.hPath)) 96 { 97 DPRINT1("Failed to remove Path\n"); 98 } 99 dc->dclevel.hPath = 0; 100 dc->dclevel.flPath = 0; 101 } 102 103 /* DC_vCopyState frees the Clip rgn and the Meta rgn. Take care of the other ones 104 * There is no need to clear prgnVis, as UserGetDC updates it immediately. */ 105 if (dc->prgnRao) 106 REGION_Delete(dc->prgnRao); 107 if (dc->prgnAPI) 108 REGION_Delete(dc->prgnAPI); 109 dc->prgnRao = dc->prgnAPI = NULL; 110 111 dc->fs |= DC_FLAG_DIRTY_RAO; 112 113 DC_UnlockDc(dc); 114 115 return TRUE; 116 } 117 118 __kernel_entry 119 BOOL 120 APIENTRY 121 NtGdiResetDC( 122 _In_ HDC hdc, 123 _In_ LPDEVMODEW pdm, 124 _Out_ PBOOL pbBanding, 125 _In_opt_ DRIVER_INFO_2W *pDriverInfo2, 126 _At_((PUMDHPDEV*)ppUMdhpdev, _Out_) PVOID ppUMdhpdev) 127 { 128 /* According to a comment in Windows SDK the size of the buffer for 129 pdm is (pdm->dmSize + pdm->dmDriverExtra) */ 130 UNIMPLEMENTED; 131 return FALSE; 132 } 133 134 135 VOID 136 NTAPI 137 DC_vRestoreDC( 138 IN PDC pdc, 139 INT iSaveLevel) 140 { 141 HDC hdcSave; 142 PDC pdcSave; 143 144 NT_ASSERT(iSaveLevel > 0); 145 DPRINT("DC_vRestoreDC(%p, %ld)\n", pdc->BaseObject.hHmgr, iSaveLevel); 146 147 /* Loop the save levels */ 148 while (pdc->dclevel.lSaveDepth > iSaveLevel) 149 { 150 hdcSave = pdc->dclevel.hdcSave; 151 DPRINT("RestoreDC = %p\n", hdcSave); 152 153 /* Set us as the owner */ 154 if (!GreSetObjectOwner(hdcSave, GDI_OBJ_HMGR_POWNED)) 155 { 156 /* Could not get ownership. That's bad! */ 157 DPRINT1("Could not get ownership of saved DC (%p) for hdc %p!\n", 158 hdcSave, pdc->BaseObject.hHmgr); 159 NT_ASSERT(FALSE); 160 return;// FALSE; 161 } 162 163 /* Lock the saved dc */ 164 pdcSave = DC_LockDc(hdcSave); 165 if (!pdcSave) 166 { 167 /* WTF? Internal error! */ 168 DPRINT1("Could not lock the saved DC (%p) for dc %p!\n", 169 hdcSave, pdc->BaseObject.hHmgr); 170 NT_ASSERT(FALSE); 171 return;// FALSE; 172 } 173 174 /* Remove the saved dc from the queue */ 175 pdc->dclevel.hdcSave = pdcSave->dclevel.hdcSave; 176 177 /* Decrement save level */ 178 pdc->dclevel.lSaveDepth--; 179 180 /* Is this the state we want? */ 181 if (pdc->dclevel.lSaveDepth == iSaveLevel) 182 { 183 /* Copy the state back */ 184 DC_vCopyState(pdcSave, pdc, FALSE); 185 186 /* Only memory DC's change their surface */ 187 if (pdc->dctype == DCTYPE_MEMORY) 188 DC_vSelectSurface(pdc, pdcSave->dclevel.pSurface); 189 190 if (pdcSave->dclevel.hPath) 191 { 192 PATH_RestorePath( pdc, pdcSave ); 193 } 194 } 195 196 /* Prevent save dc from being restored */ 197 pdcSave->dclevel.lSaveDepth = 1; 198 199 /* Unlock it */ 200 DC_UnlockDc(pdcSave); 201 /* Delete the saved dc */ 202 GreDeleteObject(hdcSave); 203 } 204 205 DPRINT("Leave DC_vRestoreDC()\n"); 206 } 207 208 209 210 BOOL 211 APIENTRY 212 NtGdiRestoreDC( 213 HDC hdc, 214 INT iSaveLevel) 215 { 216 PDC pdc; 217 218 DPRINT("NtGdiRestoreDC(%p, %d)\n", hdc, iSaveLevel); 219 220 /* Lock the original DC */ 221 pdc = DC_LockDc(hdc); 222 if (!pdc) 223 { 224 EngSetLastError(ERROR_INVALID_HANDLE); 225 return FALSE; 226 } 227 228 ASSERT(pdc->dclevel.lSaveDepth > 0); 229 230 /* Negative values are relative to the stack top */ 231 if (iSaveLevel < 0) 232 iSaveLevel = pdc->dclevel.lSaveDepth + iSaveLevel; 233 234 /* Check if we have a valid instance */ 235 if (iSaveLevel <= 0 || iSaveLevel >= pdc->dclevel.lSaveDepth) 236 { 237 DPRINT("Illegal save level, requested: %ld, current: %ld\n", 238 iSaveLevel, pdc->dclevel.lSaveDepth); 239 DC_UnlockDc(pdc); 240 EngSetLastError(ERROR_INVALID_PARAMETER); 241 return FALSE; 242 } 243 244 /* Call the internal function */ 245 DC_vRestoreDC(pdc, iSaveLevel); 246 247 DC_UnlockDc(pdc); 248 249 DPRINT("Leave NtGdiRestoreDC\n"); 250 return TRUE; 251 } 252 253 254 INT 255 APIENTRY 256 NtGdiSaveDC( 257 HDC hDC) 258 { 259 HDC hdcSave; 260 PDC pdc, pdcSave; 261 INT lSaveDepth; 262 263 DPRINT("NtGdiSaveDC(%p)\n", hDC); 264 265 /* Lock the original dc */ 266 pdc = DC_LockDc(hDC); 267 if (pdc == NULL) 268 { 269 DPRINT("Could not lock DC\n"); 270 EngSetLastError(ERROR_INVALID_HANDLE); 271 return 0; 272 } 273 274 /* Allocate a new dc */ 275 pdcSave = DC_AllocDcWithHandle(GDILoObjType_LO_DC_TYPE); 276 if (pdcSave == NULL) 277 { 278 DPRINT("Could not allocate a new DC\n"); 279 DC_UnlockDc(pdc); 280 return 0; 281 } 282 hdcSave = pdcSave->BaseObject.hHmgr; 283 284 InterlockedIncrement(&pdc->ppdev->cPdevRefs); 285 DC_vInitDc(pdcSave, DCTYPE_MEMORY, pdc->ppdev); 286 287 /* Handle references here correctly */ 288 //pdcSrc->dclevel.pSurface = NULL; 289 //pdcSrc->dclevel.pbrFill = NULL; 290 //pdcSrc->dclevel.pbrLine = NULL; 291 //pdcSrc->dclevel.ppal = NULL; 292 293 /* Make it a kernel handle 294 (FIXME: Windows handles this differently, see Wiki) */ 295 GDIOBJ_vSetObjectOwner(&pdcSave->BaseObject, GDI_OBJ_HMGR_PUBLIC); 296 297 /* Copy the current state */ 298 DC_vCopyState(pdc, pdcSave, FALSE); 299 300 /* Only memory DC's change their surface */ 301 if (pdc->dctype == DCTYPE_MEMORY) 302 DC_vSelectSurface(pdcSave, pdc->dclevel.pSurface); 303 304 /* Copy path */ 305 if (pdc->dclevel.hPath) 306 { 307 PATH_SavePath( pdcSave, pdc ); 308 } 309 pdcSave->dclevel.flPath = pdc->dclevel.flPath | DCPATH_SAVESTATE; 310 311 /* Set new dc as save dc */ 312 pdcSave->dclevel.hdcSave = pdc->dclevel.hdcSave; 313 pdc->dclevel.hdcSave = hdcSave; 314 315 /* Increase save depth, return old value */ 316 lSaveDepth = pdc->dclevel.lSaveDepth++; 317 318 /* Cleanup and return */ 319 DC_UnlockDc(pdcSave); 320 DC_UnlockDc(pdc); 321 322 DPRINT("Leave NtGdiSaveDC: %ld, hdcSave = %p\n", lSaveDepth, hdcSave); 323 return lSaveDepth; 324 } 325 326 /* EOF */ 327