source: trunk/src/gdi32/dibsect.cpp@ 10373

Last change on this file since 10373 was 10373, checked in by sandervl, 22 years ago

Update

File size: 35.4 KB
Line 
1/* $Id: dibsect.cpp,v 1.68 2004-01-11 11:42:10 sandervl Exp $ */
2
3/*
4 * GDI32 DIB sections
5 *
6 * Copyright 1998-2000 Sander van Leeuwen (sandervl@xs4all.nl)
7 * Copyright 1998 Patrick Haller
8 * Copyright 2002-2003 Innotek Systemberatung GmbH (sandervl@innotek.de)
9 *
10 * Project Odin Software License can be found in LICENSE.TXT
11 *
12 * Basic GPI object and bitmap data synchronization:
13 *
14 * - CreateDIBSection:
15 * register a memory range for exception notification
16 * set to read/commit during creation
17 *
18 * - if(exception)
19 * if(invalid)
20 * sync and set to commit/read, clear invalid flag
21 * if(write violation)
22 * make as dirty and set range to read/write
23 *
24 * - before GDI operation
25 * if(dirty)
26 * flush (set bitmap bits), clear dirty flag, set range to readonly
27 *
28 * - after GDI operation
29 * set invalid flag, set range to invalid
30 *
31 * - GdiFlush:
32 * NOP
33 *
34 * Should probably detect partial changes to avoid having to sync the entire
35 * DIB section each time something minor changes.
36 *
37 * Might get a little bit more complicated when the application gives us a memory
38 * mapped file handle. (although we can change the protection flags of aliased pages)
39 *
40 */
41#define INCL_GPI
42#define INCL_WIN
43#include <os2wrap.h> //Odin32 OS/2 api wrappers
44#include <stdlib.h>
45#include <string.h>
46#include <win32type.h>
47#include <misc.h>
48#include <win32api.h>
49#include <winconst.h>
50#include <winuser32.h>
51#include <dcdata.h>
52#include "dibsect.h"
53#include "oslibgpi.h"
54#include "rgbcvt.h"
55#include <memmap.h>
56
57#define DBG_LOCALLOG DBG_dibsect
58#include "dbglocal.h"
59
60static BOOL WIN32API DIBExceptionNotify(LPVOID lpBase, ULONG offset, BOOL fWriteAccess,
61 DWORD dwSize, DWORD dwUserData);
62
63
64//******************************************************************************
65//******************************************************************************
66DIBSection::DIBSection(BITMAPINFOHEADER_W *pbmi, char *pColors, DWORD iUsage, DWORD hSection, DWORD dwOffset, HBITMAP hBitmap, int fFlip)
67 : bmpBits(NULL), pOS2bmp(NULL), next(NULL), bmpBitsDblBuffer(NULL),
68 hdc(0), hwndParent(0), fDirty(FALSE), fInvalid(FALSE), dwSize(0)
69{
70 int palsize=0;
71
72 bmpsize = pbmi->biWidth;
73 /* @@@PH 98/06/07 -- high-color bitmaps don't have palette */
74
75 this->fFlip = fFlip;
76 os2bmphdrsize = sizeof(BITMAPINFO2);
77
78 switch(pbmi->biBitCount)
79 {
80 case 1:
81 bmpsize = ((bmpsize + 31) & ~31) / 8;
82 palsize = ((1 << pbmi->biBitCount))*sizeof(RGB2);
83 os2bmphdrsize += palsize;
84 break;
85 case 4:
86 bmpsize = ((bmpsize + 7) & ~7) / 2;
87 palsize = ((1 << pbmi->biBitCount))*sizeof(RGB2);
88 os2bmphdrsize += palsize;
89 break;
90 case 8:
91 palsize = ((1 << pbmi->biBitCount))*sizeof(RGB2);
92 os2bmphdrsize += palsize;
93 bmpsize = (bmpsize + 3) & ~3;
94 break;
95 case 16:
96 bmpsize *= 2;
97 bmpsize = (bmpsize + 3) & ~3;
98 break;
99 case 24:
100 bmpsize *= 3;
101 bmpsize = (bmpsize + 3) & ~3;
102 break;
103 case 32:
104 bmpsize *= 4;
105 break;
106 default:
107 dprintf(("Unsupported nr of bits %d", pbmi->biBitCount));
108 DebugInt3();
109 break;
110 }
111
112 this->hSection = hSection;
113 this->dwOffset = dwOffset;
114 if(hSection) {
115 bmpBits = (char *)MapViewOfFile(hSection, FILE_MAP_ALL_ACCESS_W, 0, dwOffset, bmpsize*pbmi->biHeight - dwOffset);
116 if(!bmpBits) {
117 dprintf(("Dibsection: mapViewOfFile %x failed!", hSection));
118 DebugInt3();
119 }
120 }
121 if(!bmpBits) {
122 APIRET rc = DosAllocMem((PPVOID)&bmpBits, bmpsize*pbmi->biHeight, PAG_READ|PAG_COMMIT);
123 if(rc) {
124 dprintf(("DosAllocMem failed with %d", rc));
125 DebugInt3();
126 }
127 if(MMAP_RegisterMemoryRange(DIBExceptionNotify, bmpBits, bmpsize*pbmi->biHeight, hBitmap) == FALSE)
128 {
129 dprintf(("MMAP_RegisterMemoryRange failed!!"));
130 DebugInt3();
131 }
132 dwSize = bmpsize*pbmi->biHeight;
133 }
134 else memset(bmpBits, 0, bmpsize*pbmi->biHeight);
135
136 pOS2bmp = (BITMAPINFO2 *)malloc(os2bmphdrsize);
137
138 memset(pOS2bmp, /* set header + palette entries to zero */
139 0,
140 os2bmphdrsize);
141
142 pOS2bmp->cbFix = sizeof(BITMAPINFO2) - sizeof(RGB2);
143 pOS2bmp->cx = pbmi->biWidth;
144 pOS2bmp->cy = pbmi->biHeight;
145 pOS2bmp->cPlanes = pbmi->biPlanes;
146 pOS2bmp->cBitCount = pbmi->biBitCount;
147 pOS2bmp->ulCompression = pbmi->biCompression; //same as OS/2 (uncompressed, rle8, rle4)
148 //SvL: Ignore BI_BITFIELDS_W type (GpiDrawBits fails otherwise)
149 if(pOS2bmp->ulCompression == BI_BITFIELDS_W) {
150 pOS2bmp->ulCompression = 0;
151 }
152 pOS2bmp->cbImage = pbmi->biSizeImage;
153 dprintf(("hBitmap %x", hBitmap));
154 dprintf(("pOS2bmp->cx %d\n", pOS2bmp->cx));
155 dprintf(("pOS2bmp->cy %d\n", pOS2bmp->cy));
156 dprintf(("pOS2bmp->cPlanes %d\n", pOS2bmp->cPlanes));
157 dprintf(("pOS2bmp->cBitCount %d\n", pOS2bmp->cBitCount));
158 dprintf(("pOS2bmp->ulCompression %d\n", pOS2bmp->ulCompression));
159 dprintf(("pOS2bmp->cbImage %d\n", pOS2bmp->cbImage));
160 dprintf(("Bits at %x, size %d",bmpBits, bmpsize*pbmi->biHeight));
161
162 // clear DIBSECTION structure
163 memset(&dibinfo, 0, sizeof(dibinfo));
164
165 // copy BITMAPINFOHEADER data into DIBSECTION structure
166 memcpy(&dibinfo.dsBmih, pbmi, sizeof(*pbmi));
167 dibinfo.dsBm.bmType = 0;
168 dibinfo.dsBm.bmWidth = pbmi->biWidth;
169 dibinfo.dsBm.bmHeight = pbmi->biHeight;
170 dibinfo.dsBm.bmWidthBytes= bmpsize;
171 dibinfo.dsBm.bmPlanes = pbmi->biPlanes;
172 dibinfo.dsBm.bmBitsPixel = pbmi->biBitCount;
173 dibinfo.dsBm.bmBits = bmpBits;
174
175 dibinfo.dshSection = hSection;
176 dibinfo.dsOffset = dwOffset;
177
178 if(iUsage == DIB_PAL_COLORS || pbmi->biBitCount <= 8)
179 {
180 dibinfo.dsBitfields[0] = dibinfo.dsBitfields[1] = dibinfo.dsBitfields[2] = 0;
181 if(palsize) {
182 SetDIBColorTable(0, (pbmi->biClrUsed) ? pbmi->biClrUsed : (1 << pbmi->biBitCount), (RGBQUAD *)(pbmi+1));
183 }
184 }
185 else {
186 switch(pbmi->biBitCount)
187 {
188 case 16:
189 dibinfo.dsBitfields[0] = (pbmi->biCompression == BI_BITFIELDS_W) ? *(DWORD *)pColors : 0x7c00;
190 dibinfo.dsBitfields[1] = (pbmi->biCompression == BI_BITFIELDS_W) ? *((DWORD *)pColors + 1) : 0x03e0;
191 dibinfo.dsBitfields[2] = (pbmi->biCompression == BI_BITFIELDS_W) ? *((DWORD *)pColors + 2) : 0x001f;
192 break;
193
194 case 24:
195 case 32:
196 dibinfo.dsBitfields[0] = (pbmi->biCompression == BI_BITFIELDS_W) ? *(DWORD *)pColors : 0xff0000;
197 dibinfo.dsBitfields[1] = (pbmi->biCompression == BI_BITFIELDS_W) ? *((DWORD *)pColors + 1) : 0x00ff00;
198 dibinfo.dsBitfields[2] = (pbmi->biCompression == BI_BITFIELDS_W) ? *((DWORD *)pColors + 2) : 0x0000ff;
199 if(dibinfo.dsBitfields[0] != 0xff0000 && dibinfo.dsBitfields[1] != 0xff00 && dibinfo.dsBitfields[2] != 0xff) {
200 dprintf(("DIBSection: unsupported bitfields for 32 bits bitmap!!"));
201 }
202 break;
203 }
204 dprintf(("BI_BITFIELDS_W %x %x %x", dibinfo.dsBitfields[0], dibinfo.dsBitfields[1], dibinfo.dsBitfields[2]));
205 }
206 //double buffer for rgb 555 dib sections (for conversion) or flipped sections
207 if(dibinfo.dsBitfields[1] == 0x03e0 || (fFlip & FLIP_VERT)) {
208 DosAllocMem((PPVOID)&bmpBitsDblBuffer, bmpsize*pbmi->biHeight, PAG_READ|PAG_WRITE|PAG_COMMIT);
209 }
210
211 this->hBitmap = hBitmap;
212 this->iUsage = iUsage;
213
214 lock();
215 if(section == NULL)
216 {
217 dprintf(("section was NULL\n"));
218 section = this;
219 }
220 else
221 {
222 DIBSection *dsect = section;
223 dprintf2(("Increment section starting at %08X\n",dsect));
224
225 while ( (dsect->next != this) &&
226 (dsect->next != NULL) )
227 {
228//// dprintf2(("Increment section to %08X\n",dsect->next));
229 dsect = dsect->next;
230 }
231 dsect->next = this;
232 }
233 unlock();
234}
235//******************************************************************************
236//******************************************************************************
237DIBSection::~DIBSection()
238{
239 dprintf(("Delete DIBSection %x", hBitmap));
240
241 if(hSection) {
242 UnmapViewOfFile(bmpBits);
243 }
244 else
245 {
246 if(MMAP_UnregisterMemoryRange(bmpBits) == FALSE)
247 {
248 dprintf(("MMAP_UnregisterMemoryRange failed!!"));
249 DebugInt3();
250 }
251 if(bmpBits)
252 DosFreeMem(bmpBits);
253 }
254
255 if(bmpBitsDblBuffer)
256 DosFreeMem(bmpBitsDblBuffer);
257
258 if(pOS2bmp)
259 free(pOS2bmp);
260
261 lock();
262 if(section == this)
263 {
264 section = this->next;
265 }
266 else
267 {
268 DIBSection *dsect = section;
269
270 while(dsect->next != this)
271 {
272 dsect = dsect->next;
273 }
274 dsect->next = this->next;
275 }
276 unlock();
277}
278//******************************************************************************
279//******************************************************************************
280int DIBSection::SetDIBColorTable(int startIdx, int cEntries, RGBQUAD *rgb)
281{
282 int i, end;
283
284 dprintf(("SetDIBColorTable %d %d %x", startIdx, cEntries, rgb));
285
286 if(pOS2bmp->cBitCount > 8) {
287 dprintf(("DIBSection::SetDIBColorTable: bpp > 8; ignore"));
288 return 0;
289 }
290
291 end = startIdx + cEntries;
292 if(end > (1 << pOS2bmp->cBitCount)) {
293 end = (1 << pOS2bmp->cBitCount);
294 cEntries = end - startIdx;
295 }
296
297 memcpy(&pOS2bmp->argbColor[startIdx], rgb, cEntries*sizeof(RGB2));
298
299 for(i=startIdx;i<end;i++)
300 {
301 pOS2bmp->argbColor[i].fcOptions = 0;
302 dprintf2(("Index %d : 0x%08X\n",i, *((ULONG*)(&pOS2bmp->argbColor[i])) ));
303 }
304 return(cEntries);
305}
306//******************************************************************************
307//******************************************************************************
308int DIBSection::SetDIBColorTable(int startIdx, int cEntries, PALETTEENTRY *palentry)
309{
310 int i, end;
311
312 if(pOS2bmp->cBitCount > 8) {
313 dprintf(("DIBSection::SetDIBColorTable: bpp > 8; ignore"));
314 return 0;
315 }
316
317 end = startIdx + cEntries;
318 if(end > (1 << pOS2bmp->cBitCount)) {
319 end = (1 << pOS2bmp->cBitCount);
320 }
321 for(i=startIdx;i<end;i++)
322 {
323 pOS2bmp->argbColor[i].fcOptions = 0;
324 pOS2bmp->argbColor[i].bBlue = palentry[i].peBlue;
325 pOS2bmp->argbColor[i].bGreen = palentry[i].peGreen;
326 pOS2bmp->argbColor[i].bRed = palentry[i].peRed;
327 dprintf2(("Index %d : 0x%08X\n",i, *((ULONG*)(&pOS2bmp->argbColor[i])) ));
328 }
329
330 return end - startIdx;
331}
332//******************************************************************************
333//******************************************************************************
334int DIBSection::GetDIBColorTable(int startIdx, int cEntries, RGBQUAD *rgb)
335{
336 int i, end = startIdx + cEntries;
337
338 if(pOS2bmp->cBitCount > 8) {
339 dprintf(("DIBSection::GetDIBColorTable: bpp > 8 -> return 0"));
340 return 0;
341 }
342 if(end > (1 << pOS2bmp->cBitCount)) {
343 end = (1 << pOS2bmp->cBitCount);
344 dprintf(("DIBSection::GetDIBColorTable: %d->%d", startIdx, end));
345 }
346 memcpy(rgb, &pOS2bmp->argbColor[startIdx], cEntries*sizeof(RGBQUAD));
347
348 for(i=0;i<cEntries;i++) {
349 rgb[i].rgbReserved = 0;
350 }
351
352 return end - startIdx;
353}
354//******************************************************************************
355//******************************************************************************
356BOOL DIBSection::BitBlt(HDC hdcDest, int nXdest, int nYdest, int nDestWidth,
357 int nDestHeight, int nXsrc, int nYsrc,
358 int nSrcWidth, int nSrcHeight, DWORD Rop)
359{
360 HPS hps = (HPS)hdcDest;
361 POINTL point[4];
362 LONG rc, hdcHeight, hdcWidth;
363 PVOID bitmapBits = NULL;
364 int oldyinversion = 0;
365 BOOL fRestoryYInversion = FALSE, fFrameWindowDC = FALSE;
366 HWND hwndDest;
367 pDCData pHps;
368
369 pHps = (pDCData)OSLibGpiQueryDCData((HPS)hdcDest);
370 if(!pHps)
371 {
372 SetLastError(ERROR_INVALID_HANDLE_W);
373 return FALSE;
374 }
375
376 hwndDest = WindowFromDC(hdcDest); //could return desktop window, so check that
377 if(hwndDest && pHps->hwnd && !pHps->isClient) {
378 fFrameWindowDC = TRUE;
379 }
380
381 dprintf(("DIBSection::BitBlt %x %X (hps %x) %x to(%d,%d)(%d,%d) from (%d,%d)(%d,%d) rop %x flip %x",
382 hBitmap, hdcDest, hps, hwndDest, nXdest, nYdest, nDestWidth, nDestHeight,
383 nXsrc, nYsrc, nSrcWidth, nSrcHeight, Rop, fFlip));
384
385 //shortcut; better to sync it here instead of in the exception handler
386 //(pages touched inside PMGPI)
387 if(isInvalid()) {
388 sync();
389 }
390
391 if(hwndDest) {
392 RECT rect;
393
394 if(fFrameWindowDC) {
395 GetWindowRect(hwndDest, &rect);
396 }
397 else GetClientRect(hwndDest, &rect);
398 hdcHeight = rect.bottom - rect.top;
399 hdcWidth = rect.right - rect.left;
400 dprintf(("DIBSection::BitBlt hdc size (%d,%d) (WINDOW)", hdcWidth, hdcHeight));
401 }
402 else {
403 hdcHeight = pHps->bitmapHeight;
404 hdcWidth = pHps->bitmapWidth;
405 dprintf(("DIBSection::BitBlt hdc size (%d,%d) (BMP)", hdcWidth, hdcHeight));
406 }
407
408 //Don't clip destination size to destination DC size
409 //This messes up the two bitmaps in the opening window of Opera 6
410 //(choice between MDI & SDI interface)
411
412 //win32 coordinates are relative to left top, OS/2 expects left bottom
413 //source rectangle is non-inclusive (top, right not included)
414 //destination rectangle is incl.-inclusive (everything included)
415
416 point[0].x = nXdest;
417 point[1].x = nXdest + nDestWidth - 1;
418#ifdef INVERT
419 point[0].y = hdcHeight - nYdest - nDestHeight;
420 point[1].y = hdcHeight - nYdest - 1;
421#else
422 point[0].y = nYdest;
423 point[1].y = nYdest + nDestHeight - 1;
424#endif
425
426 //target rectangle is inclusive-inclusive
427 point[2].x = nXsrc;
428 point[3].x = nXsrc + nSrcWidth;
429#ifdef INVERT
430 point[2].y = pOS2bmp->cy - nYsrc - nSrcHeight;
431 point[3].y = pOS2bmp->cy - nYsrc;
432#else
433 point[2].y = nYsrc;
434 point[3].y = nYsrc + nSrcHeight;
435#endif
436
437#ifdef INVERT
438 oldyinversion = GpiQueryYInversion(hps);
439 if(oldyinversion != 0) {
440 POINT viewpt, winpt;
441
442 GetViewportOrgEx(hps, &viewpt);
443 GetWindowOrgEx(hps, &winpt);
444
445 dprintf(("Viewport origin (%d,%d)", viewpt.x, viewpt.y));
446 dprintf(("Windows origin (%d,%d)", winpt.x, winpt.y));
447
448 /* By resetting y inversion to 0, we must take the new windows
449 * origin into account. The default matrix set up for the origin
450 * depends on y inversion. Therefor we must add the y origin value,
451 * multiplied by two, to the top & bottom coordinates
452 */
453 point[0].y -= winpt.y*2;
454 point[1].y -= winpt.y*2;
455
456 /* By resetting y inversion to 0, we must take the new viewport
457 * origin into account. The default matrix set up for the origin
458 * depends on y inversion. Therefor we must subtract the y origin value,
459 * multiplied by two, from the top & bottom coordinates
460 */
461 point[0].y -= viewpt.y*2;
462 point[1].y -= viewpt.y*2;
463
464 GpiEnableYInversion(hps, 0);
465 fRestoryYInversion = TRUE;
466 }
467#else
468 dprintf(("Sync destination dibsection: hdc y inversion = %d", GpiQueryYInversion(hdc)));
469#endif
470
471 dprintf(("DIBSection::BitBlt (%d,%d)(%d,%d) from (%d,%d)(%d,%d) dim (%d,%d)(%d,%d)", point[0].x, point[0].y,
472 point[1].x, point[1].y, point[2].x, point[2].y, point[3].x, point[3].y,
473 nDestWidth, nDestHeight, nSrcWidth, nSrcHeight));
474
475#ifdef DEBUG
476 RECTL rcltemp;
477 GreGetDCOrigin(hps, (PPOINTL)&rcltemp);
478 dprintf(("origin (%d,%d) yinv %d", rcltemp.xLeft, rcltemp.yBottom, oldyinversion));
479#endif
480
481 if(fFlip & FLIP_HOR)
482 {
483 ULONG x;
484 x = point[0].x;
485 point[0].x = point[1].x;
486 point[1].x = x;
487 }
488
489 ULONG os2mode, winmode;
490
491 os2mode = BBO_OR;
492 winmode = GetStretchBltMode(hdcDest);
493 switch(winmode) {
494 case BLACKONWHITE_W:
495 os2mode = BBO_AND;
496 break;
497 case WHITEONBLACK_W:
498 case HALFTONE_W: //TODO:
499 os2mode = BBO_OR;
500 break;
501 case COLORONCOLOR_W:
502 os2mode = BBO_IGNORE;
503 break;
504 }
505#ifndef INVERT
506 if(!(fFlip & FLIP_VERT)) {
507#else
508 if(fFlip & FLIP_VERT) {
509#endif
510 //manually reverse bitmap data
511 char *src = bmpBits + (pOS2bmp->cy-1)*dibinfo.dsBm.bmWidthBytes;
512 char *dst = bmpBitsDblBuffer;
513 for(int i=0;i<pOS2bmp->cy;i++) {
514 memcpy(dst, src, dibinfo.dsBm.bmWidthBytes);
515 dst += dibinfo.dsBm.bmWidthBytes;
516 src -= dibinfo.dsBm.bmWidthBytes;
517 }
518 bitmapBits = bmpBitsDblBuffer;
519 }
520 else bitmapBits = bmpBits;
521
522 //Translate ROP
523 Rop = Rop >> 16;
524
525 //SvL: Optimize this.. (don't convert entire bitmap if only a part will be blitted to the dc)
526 if(dibinfo.dsBitfields[1] == 0x3E0) {//RGB 555?
527 dprintf(("DIBSection::BitBlt; convert rgb 555 to 565 (old y inv. = %d)", oldyinversion));
528
529 if(bmpBitsDblBuffer == NULL)
530 DebugInt3();
531
532 // PH 2000/10/01 - Fix for Beyond Compare 1.9d
533 // Note: according to documentation, cmImage can be zero for
534 // RGB- / non-compressed bitmaps.
535 int iLength = pOS2bmp->cbImage;
536 if (iLength == 0)
537 iLength = pOS2bmp->cx * pOS2bmp->cy * (pOS2bmp->cBitCount >> 3);
538
539 if (iLength > 0)
540 {
541 pRGB555to565((WORD *)bmpBitsDblBuffer, (WORD *)bitmapBits, iLength/sizeof(WORD));
542 }
543 else
544 {
545 dprintf(("GDI32: DIBSect::BitBlt: WARNING! zero-length bitmap! %08xh", pOS2bmp));
546 }
547 rc = GpiDrawBits(hps, bmpBitsDblBuffer, pOS2bmp, 4, &point[0], Rop, os2mode);
548 }
549 else {
550 rc = GpiDrawBits(hps, bitmapBits, pOS2bmp, 4, &point[0], Rop, os2mode);
551 }
552 if(rc == GPI_OK) {
553#ifdef INVERT
554 //restore old y inversion height
555 if(fRestoryYInversion) GpiEnableYInversion(hps, oldyinversion);
556#endif
557 SetLastError(ERROR_SUCCESS_W);
558
559 return(TRUE);
560 }
561#ifdef INVERT
562 if(fRestoryYInversion) GpiEnableYInversion(hps, oldyinversion);
563#endif
564
565 dprintf(("DIBSection::BitBlt %X (%d,%d) (%d,%d) to (%d,%d) (%d,%d) returned %d\n", hps, point[0].x, point[0].y, point[1].x, point[1].y, point[2].x, point[2].y, point[3].x, point[3].y, rc));
566 dprintf(("WinGetLastError returned %X\n", WinGetLastError(WinQueryAnchorBlock(hwndDest)) & 0xFFFF));
567 return(FALSE);
568}
569//******************************************************************************
570//******************************************************************************
571void DIBSection::sync(HDC hdc, DWORD nYdest, DWORD nDestHeight, BOOL orgYInversion)
572{
573 APIRET rc;
574 char *destBuf;
575
576 dprintf(("Sync destination dibsection %x (%x) (%d,%d) flip %d", hBitmap, hdc, nYdest, nDestHeight, fFlip));
577
578 BITMAPINFO2 *tmphdr = (BITMAPINFO2 *)malloc(os2bmphdrsize);
579 memcpy(tmphdr, pOS2bmp, os2bmphdrsize);
580
581#ifdef INVERT
582 int oldyinversion = 0;
583 if(orgYInversion == TRUE) {
584 oldyinversion = GpiQueryYInversion(hdc);
585 dprintf(("Sync destination dibsection: hdc y inversion = %d", oldyinversion));
586 if(oldyinversion != 0) {
587#ifdef DEBUG
588 POINT point;
589 GetViewportOrgEx(hdc, &point);
590 dprintf(("Viewport origin (%d,%d)", point.x, point.y));
591#endif
592 GpiEnableYInversion(hdc, 0);
593 }
594 }
595#else
596 dprintf(("Sync destination dibsection: hdc y inversion = %d", GpiQueryYInversion(hdc)));
597#endif
598
599#ifndef INVERT
600 if(!(fFlip & FLIP_VERT)) {
601#else
602 if(fFlip & FLIP_VERT) {
603#endif
604 //origin is top left, so no y conversion is necessary
605 destBuf = bmpBitsDblBuffer + nYdest*dibinfo.dsBm.bmWidthBytes;
606
607 //SvL: cbImage can be too small for compressed images; GpiQueryBitmapBits
608 // will fail in that case (CoolEdit 2000). Perhaps because the returned
609 // compressed image is larger than the original.
610 // Use uncompressed size instead
611 // NOTE: The correct size will be returned by GpiQueryBitmapBits
612 tmphdr->cbImage = dibinfo.dsBm.bmHeight*dibinfo.dsBm.bmWidthBytes;
613
614#ifdef INVERT
615 int dest = dibinfo.dsBm.bmHeight - nYdest - nDestHeight;
616#else
617 int dest = nYdest;
618#endif
619 rc = GpiQueryBitmapBits(hdc, dest, nDestHeight, destBuf,
620 tmphdr);
621 if(rc == GPI_ALTERROR) {
622 dprintf(("ERROR: GpiQueryBitmapBits failed with %x", WinGetLastError(0)));
623 }
624
625 //manually reverse bitmap data
626 char *src = destBuf;
627 char *dst = GetDIBObject() + (nYdest+nDestHeight-1)*dibinfo.dsBm.bmWidthBytes;
628 for(int i=0;i<nDestHeight;i++) {
629 memcpy(dst, src, dibinfo.dsBm.bmWidthBytes);
630 dst -= dibinfo.dsBm.bmWidthBytes;
631 src += dibinfo.dsBm.bmWidthBytes;
632 }
633 }
634 else {
635 //SvL: cbImage can be too small for compressed images; GpiQueryBitmapBits
636 // will fail in that case (CoolEdit 2000). Perhaps because the returned
637 // compressed image is larger than the original.
638 // Use uncompressed size instead
639 // NOTE: The correct size will be returned by GpiQueryBitmapBits
640 tmphdr->cbImage = dibinfo.dsBm.bmHeight*dibinfo.dsBm.bmWidthBytes;
641
642 //origin is bottom left, nYdest is based on top left coordinate system
643#ifdef INVERT
644 int dest = dibinfo.dsBm.bmHeight - nYdest - nDestHeight;
645#else
646 int dest = nYdest;
647#endif
648
649 destBuf = GetDIBObject() + dest*dibinfo.dsBm.bmWidthBytes;
650
651 rc = GpiQueryBitmapBits(hdc, dest, nDestHeight, destBuf,
652 tmphdr);
653 if(rc == GPI_ALTERROR) {
654 dprintf(("ERROR: GpiQueryBitmapBits failed with %x", WinGetLastError(0)));
655 }
656#ifdef DEBUG_PALETTE
657 if(rc != GPI_ALTERROR && tmphdr->cBitCount <= 8) {
658 for(int i=0;i<(1<<tmphdr->cBitCount);i++)
659 {
660 dprintf2(("Index %d : 0x%08X\n",i, *((ULONG*)(&tmphdr->argbColor[i])) ));
661 }
662 }
663#endif
664 }
665 memcpy(pOS2bmp, tmphdr, os2bmphdrsize);
666
667 if(dibinfo.dsBitfields[1] == 0x3E0) {//RGB 555?
668 dprintf(("DIBSection::sync: convert RGB 565 to RGB 555"));
669
670 destBuf = GetDIBObject() + nYdest*dibinfo.dsBm.bmWidthBytes;
671
672 pRGB565to555((WORD *)destBuf, (WORD *)destBuf, (nDestHeight*dibinfo.dsBm.bmWidthBytes)/sizeof(WORD));
673 }
674
675 free(tmphdr);
676 if(rc != nDestHeight) {
677 dprintf(("!WARNING!: GpiQueryBitmapBits returned %d instead of %d scanlines", rc, nDestHeight));
678 }
679
680#ifdef INVERT
681 if(oldyinversion) GpiEnableYInversion(hdc, oldyinversion);
682#endif
683
684}
685//******************************************************************************
686//******************************************************************************
687void DIBSection::flush(HDC hdc, DWORD nYdest, DWORD nDestHeight, BOOL orgYInversion)
688{
689 APIRET rc;
690 char *destBuf;
691
692 dprintf(("flush destination dibsection %x (%x) (%d,%d) flip %d", hBitmap, hdc, nYdest, nDestHeight, fFlip));
693
694#ifdef INVERT
695 int oldyinversion = 0;
696 if(orgYInversion == TRUE) {
697 oldyinversion = GpiQueryYInversion(hdc);
698 dprintf(("Flush destination dibsection: hdc y inversion = %d", oldyinversion));
699 if(oldyinversion != 0) {
700#ifdef DEBUG
701 POINT point;
702 GetViewportOrgEx(hdc, &point);
703 dprintf(("Viewport origin (%d,%d)", point.x, point.y));
704#endif
705 GpiEnableYInversion(hdc, 0);
706 }
707 }
708#else
709 dprintf(("flush destination dibsection: hdc y inversion = %d", GpiQueryYInversion(hdc)));
710#endif
711
712#ifndef INVERT
713 if(!(fFlip & FLIP_VERT)) {
714#else
715 if(fFlip & FLIP_VERT) {
716#endif
717 //origin is top left, so no y conversion is necessary
718 destBuf = bmpBitsDblBuffer + nYdest*dibinfo.dsBm.bmWidthBytes;
719
720 //SvL: cbImage can be too small for compressed images; GpiQueryBitmapBits
721 // will fail in that case (CoolEdit 2000). Perhaps because the returned
722 // compressed image is larger than the original.
723 // Use uncompressed size instead
724 // NOTE: The correct size will be returned by GpiQueryBitmapBits
725 pOS2bmp->cbImage = dibinfo.dsBm.bmHeight*dibinfo.dsBm.bmWidthBytes;
726
727 //manually reverse bitmap data
728 char *src = GetDIBObject() + (nYdest+nDestHeight-1)*dibinfo.dsBm.bmWidthBytes;
729 char *dst = destBuf;
730 for(int i=0;i<nDestHeight;i++) {
731 memcpy(dst, src, dibinfo.dsBm.bmWidthBytes);
732 dst += dibinfo.dsBm.bmWidthBytes;
733 src -= dibinfo.dsBm.bmWidthBytes;
734 }
735
736 if(dibinfo.dsBitfields[1] == 0x3E0) {//RGB 555?
737 dprintf(("DIBSection::flush: convert RGB 565 to RGB 555"));
738
739 pRGB565to555((WORD *)destBuf, (WORD *)destBuf, (nDestHeight*dibinfo.dsBm.bmWidthBytes)/sizeof(WORD));
740 }
741
742#ifdef INVERT
743 int dest = dibinfo.dsBm.bmHeight - nYdest - nDestHeight;
744#else
745 int dest = nYdest;
746#endif
747 rc = GpiSetBitmapBits(hdc, dest, nDestHeight, destBuf,
748 pOS2bmp);
749 if(rc == GPI_ALTERROR) {
750 dprintf(("ERROR: GpiQueryBitmapBits failed with %x", WinGetLastError(0)));
751 }
752
753 }
754 else {
755 //SvL: cbImage can be too small for compressed images; GpiQueryBitmapBits
756 // will fail in that case (CoolEdit 2000). Perhaps because the returned
757 // compressed image is larger than the original.
758 // Use uncompressed size instead
759 // NOTE: The correct size will be returned by GpiQueryBitmapBits
760 pOS2bmp->cbImage = dibinfo.dsBm.bmHeight*dibinfo.dsBm.bmWidthBytes;
761
762 //origin is bottom left, nYdest is based on top left coordinate system
763#ifdef INVERT
764 int dest = dibinfo.dsBm.bmHeight - nYdest - nDestHeight;
765#else
766 int dest = nYdest;
767#endif
768
769 destBuf = GetDIBObject() + dest*dibinfo.dsBm.bmWidthBytes;
770
771 if(dibinfo.dsBitfields[1] == 0x3E0) {//RGB 555?
772 dprintf(("DIBSection::flush: convert RGB 565 to RGB 555"));
773
774 pRGB565to555((WORD *)bmpBitsDblBuffer, (WORD *)destBuf, (nDestHeight*dibinfo.dsBm.bmWidthBytes)/sizeof(WORD));
775 destBuf = bmpBitsDblBuffer;
776 }
777
778 rc = GpiSetBitmapBits(hdc, dest, nDestHeight, destBuf,
779 pOS2bmp);
780 if(rc == GPI_ALTERROR) {
781 dprintf(("ERROR: GpiQueryBitmapBits failed with %x", WinGetLastError(0)));
782 }
783#ifdef DEBUG_PALETTE
784 if(rc != GPI_ALTERROR && pOS2bmp->cBitCount <= 8) {
785 for(int i=0;i<(1<<pOS2bmp->cBitCount);i++)
786 {
787 dprintf2(("Index %d : 0x%08X\n",i, *((ULONG*)(&pOS2bmp->argbColor[i])) ));
788 }
789 }
790#endif
791 }
792 if(rc != nDestHeight) {
793 dprintf(("!WARNING!: GpiQueryBitmapBits returned %d instead of %d scanlines", rc, nDestHeight));
794 }
795
796#ifdef INVERT
797 if(oldyinversion) GpiEnableYInversion(hdc, oldyinversion);
798#endif
799
800}
801//******************************************************************************
802//Mark the DIB section as invalid; a subsequent read or write access must
803//cause a pagefault
804//******************************************************************************
805void DIBSection::setInvalid()
806{
807 if(!fInvalid) {
808 dprintf(("DIBSection::setInvalid %x (%x)", GetBitmapHandle(), GetDIBObject()));
809 APIRET rc = DosSetMem(bmpBits, dwSize, PAG_DECOMMIT);
810 if(rc) {
811 dprintf(("DIBSection::setInvalid: DosSetMem failed with %d!!", rc));
812 DebugInt3();
813 }
814 fInvalid = TRUE;
815 }
816}
817//******************************************************************************
818//******************************************************************************
819void DIBSection::flush()
820{
821 if(pOS2bmp == NULL) {
822 DebugInt3();
823 return;
824 }
825 if(hdc == 0) {
826 HBITMAP hOldBmp;
827 HDC hdcFlush = CreateCompatibleDC(0);
828
829 hOldBmp = SelectObject(hdcFlush, hBitmap);
830 flush(hdcFlush, 0, pOS2bmp->cy);
831
832 SelectObject(hdcFlush, hOldBmp);
833 DeleteDC(hdcFlush);
834 }
835 else flush(hdc, 0, pOS2bmp->cy);
836
837 APIRET rc = DosSetMem(bmpBits, dwSize, PAG_READ);
838 if(rc) {
839 dprintf(("DIBSection::flush: DosSetMem failed with %d!!", rc));
840 DebugInt3();
841 }
842 fDirty = FALSE;
843}
844//******************************************************************************
845//******************************************************************************
846void DIBSection::sync()
847{
848 if(pOS2bmp == NULL) {
849 DebugInt3();
850 return;
851 }
852 APIRET rc = DosSetMem(bmpBits, dwSize, PAG_COMMIT|PAG_READ|PAG_WRITE);
853 if(rc) {
854 //might already be committed
855 rc = DosSetMem(bmpBits, dwSize, PAG_READ|PAG_WRITE);
856 if(rc) {
857 dprintf(("DIBSection::sync: DosSetMem failed with %d!!", rc));
858 DebugInt3();
859 }
860 }
861 if(hdc == 0) {
862 HBITMAP hOldBmp;
863 HDC hdcFlush = CreateCompatibleDC(0);
864
865 hOldBmp = SelectObject(hdcFlush, hBitmap);
866 sync(hdcFlush, 0, pOS2bmp->cy);
867
868 SelectObject(hdcFlush, hOldBmp);
869 DeleteDC(hdcFlush);
870 }
871 else sync(hdc, 0, pOS2bmp->cy);
872
873 fInvalid = FALSE;
874
875 //Set bitmap memory to readonly again to detect updates
876 rc = DosSetMem(bmpBits, dwSize, PAG_READ);
877 if(rc) {
878 dprintf(("DosSetMem failed with %d!!", rc));
879 DebugInt3();
880 }
881}
882//******************************************************************************
883//******************************************************************************
884void DIBSection::syncAll()
885{
886 if (!section)
887 return;
888
889 lock();
890 DIBSection *dsect = section;
891
892 do
893 {
894 if(dsect->isDirty() && dsect->isInvalid()) {
895 DebugInt3();
896 }
897 if(dsect->isInvalid())
898 {
899 dsect->sync();
900 }
901 dsect = dsect->next;
902 }
903 while(dsect);
904
905 unlock();
906
907 return;
908}
909//******************************************************************************
910//manual sync if no stretching and bpp is the same
911//WARNING: this also assumes the colortables are the same
912//******************************************************************************
913void DIBSection::sync(DWORD xDst, DWORD yDst, DWORD widthDst, DWORD heightDst, PVOID bits)
914{
915 char *srcbuf, *destbuf;
916 int linesize;
917
918 srcbuf = (char *)bits + dibinfo.dsBm.bmWidthBytes*yDst +
919 (xDst*dibinfo.dsBm.bmWidthBytes)/pOS2bmp->cx;
920 destbuf = (char *)GetDIBObject() + dibinfo.dsBm.bmWidthBytes*yDst +
921 (xDst*dibinfo.dsBm.bmWidthBytes)/pOS2bmp->cx;
922 linesize = (widthDst*dibinfo.dsBm.bmWidthBytes)/pOS2bmp->cx;
923 for(int i=0;i<heightDst;i++) {
924 memcpy(destbuf, srcbuf, linesize);
925 destbuf += dibinfo.dsBm.bmWidthBytes;
926 srcbuf += linesize;
927 }
928}
929//******************************************************************************
930//******************************************************************************
931void DIBSection::SelectDIBObject(HDC hdc)
932{
933 this->hdc = hdc;
934 hwndParent = WindowFromDC(hdc);
935 dprintf(("SelectDIBObject %x into %x hwndParent = %x", hBitmap, hdc, hwndParent));
936}
937//******************************************************************************
938//******************************************************************************
939DIBSection *DIBSection::findObj(HBITMAP hBitmap)
940{
941 // PH 2001-08-18 shortcut for performance optimization
942 if (!section)
943 return NULL;
944
945 lock();
946 DIBSection *dsect = section;
947
948 do
949 {
950 if(dsect->hBitmap == hBitmap)
951 {
952 unlock();
953 return(dsect);
954 }
955 dsect = dsect->next;
956 }
957 while(dsect);
958
959 unlock();
960 return(NULL);
961}
962//******************************************************************************
963//A bitmap can only be selected into one DC, so this works.
964//******************************************************************************
965DIBSection *DIBSection::findHDC(HDC hdc)
966{
967 // PH 2001-08-18 shortcut for performance optimization
968 if (!section)
969 return NULL;
970
971 lock();
972 DIBSection *dsect = section;
973
974 do
975 {
976 if(dsect->hdc == hdc)
977 {
978 unlock();
979 return(dsect);
980 }
981 dsect = dsect->next;
982 }
983 while(dsect);
984
985 unlock();
986 return(NULL);
987}
988//******************************************************************************
989//******************************************************************************
990void DIBSection::deleteSection(HBITMAP hBitmap)
991{
992 DIBSection *dsect = findObj(hBitmap);
993
994 if(dsect)
995 delete dsect;
996}
997//******************************************************************************
998//******************************************************************************
999int DIBSection::GetDIBSection(int iSize, void *lpBuffer)
1000{
1001 DIBSECTION *pDIBSection = (DIBSECTION *)lpBuffer;
1002 LPBITMAP_W dsBm = (LPBITMAP_W)lpBuffer;
1003
1004 dprintf2(("GetDIBSection %x %d %x", hBitmap, iSize, lpBuffer));
1005 if(iSize == sizeof(DIBSECTION))
1006 {
1007 memcpy(pDIBSection, &dibinfo, sizeof(dibinfo));
1008 return sizeof(DIBSECTION);
1009 }
1010 else
1011 if(iSize == sizeof(BITMAP_W))
1012 {
1013 memcpy(dsBm, &dibinfo.dsBm, sizeof(dibinfo.dsBm));
1014 return sizeof(BITMAP_W);
1015 }
1016 return 0;
1017
1018}
1019//******************************************************************************
1020//******************************************************************************
1021int DIBSection::GetBitCount()
1022{
1023 if(pOS2bmp == NULL)
1024 return 0;
1025 else
1026 return pOS2bmp->cBitCount;
1027}
1028//******************************************************************************
1029//******************************************************************************
1030int DIBSection::GetHeight()
1031{
1032 if(pOS2bmp == NULL)
1033 return 0;
1034 else
1035 return pOS2bmp->cy;
1036}
1037//******************************************************************************
1038//******************************************************************************
1039int DIBSection::GetWidth()
1040{
1041 if(pOS2bmp == NULL)
1042 return 0;
1043 else
1044 return pOS2bmp->cx;
1045}
1046//******************************************************************************
1047//******************************************************************************
1048void DIBSection::initDIBSection()
1049{
1050 InitializeCriticalSection(&dibcritsect);
1051}
1052//******************************************************************************
1053//******************************************************************************
1054DIBSection *DIBSection::section = NULL;
1055CRITICAL_SECTION DIBSection::dibcritsect;
1056
1057
1058//******************************************************************************
1059//******************************************************************************
1060static BOOL WIN32API DIBExceptionNotify(LPVOID lpBase, ULONG offset, BOOL fWriteAccess,
1061 DWORD dwSize, DWORD dwUserData)
1062{
1063 DIBSection *dsect;
1064 HBITMAP hBitmap = (HBITMAP)dwUserData;
1065
1066 dprintf(("DIBExceptionNotify %x %x %d %d %x", lpBase, offset, fWriteAccess, dwSize, dwUserData));
1067
1068 dsect = DIBSection::findObj(hBitmap);
1069 if(dsect == NULL) {
1070 dprintf(("dib section not found!!"));
1071 DebugInt3();
1072 return FALSE;
1073 }
1074 if(dsect->isInvalid())
1075 {//implies read or write to reserved pages
1076 //synchronize bitmap memory and bitmap object
1077 dsect->sync();
1078 }
1079 else
1080 if(!fWriteAccess) {
1081 APIRET rc = DosSetMem(lpBase, dwSize, PAG_READ|PAG_COMMIT);
1082 if(rc) {
1083 dprintf(("DosSetMem failed with %d!!", rc));
1084 DebugInt3();
1085 return FALSE;
1086 }
1087 }
1088
1089 if(fWriteAccess) {
1090 APIRET rc = DosSetMem(lpBase, dwSize, PAG_READ|PAG_WRITE);
1091 if(rc) {
1092 dprintf(("DosSetMem failed with %d!!", rc));
1093 DebugInt3();
1094 return FALSE;
1095 }
1096 dsect->setDirty();
1097 }
1098
1099
1100 return TRUE;
1101}
1102//******************************************************************************
1103//******************************************************************************
Note: See TracBrowser for help on using the repository browser.