source: trunk/src/gdi32/dibsect.cpp

Last change on this file was 21460, checked in by ydario, 15 years ago

Cannot commit already committed memory, check status before calling DosSetMem. Size field cannot be zero.

File size: 35.9 KB
RevLine 
[10467]1/* $Id: dibsect.cpp,v 1.69 2004-02-16 16:53:32 sandervl Exp $ */
[97]2
[4]3/*
4 * GDI32 DIB sections
5 *
[4034]6 * Copyright 1998-2000 Sander van Leeuwen (sandervl@xs4all.nl)
[4]7 * Copyright 1998 Patrick Haller
[10373]8 * Copyright 2002-2003 Innotek Systemberatung GmbH (sandervl@innotek.de)
[4]9 *
10 * Project Odin Software License can be found in LICENSE.TXT
11 *
[10373]12 * Basic GPI object and bitmap data synchronization:
[2718]13 *
[10373]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 *
[4]40 */
41#define INCL_GPI
42#define INCL_WIN
[1533]43#include <os2wrap.h> //Odin32 OS/2 api wrappers
[4]44#include <stdlib.h>
45#include <string.h>
[2600]46#include <win32type.h>
47#include <misc.h>
[3184]48#include <win32api.h>
[2600]49#include <winconst.h>
[4873]50#include <winuser32.h>
[3711]51#include <dcdata.h>
[7717]52#include "dibsect.h"
[2718]53#include "oslibgpi.h"
[3184]54#include "rgbcvt.h"
[10373]55#include <memmap.h>
[4]56
[4447]57#define DBG_LOCALLOG DBG_dibsect
[2802]58#include "dbglocal.h"
59
[10373]60static BOOL WIN32API DIBExceptionNotify(LPVOID lpBase, ULONG offset, BOOL fWriteAccess,
61 DWORD dwSize, DWORD dwUserData);
[9966]62
[10373]63
[4]64//******************************************************************************
65//******************************************************************************
[10373]66DIBSection::DIBSection(BITMAPINFOHEADER_W *pbmi, char *pColors, DWORD iUsage, DWORD hSection, DWORD dwOffset, HBITMAP hBitmap, int fFlip)
[5390]67 : bmpBits(NULL), pOS2bmp(NULL), next(NULL), bmpBitsDblBuffer(NULL),
[10373]68 hdc(0), hwndParent(0), fDirty(FALSE), fInvalid(FALSE), dwSize(0)
[4]69{
[4127]70 int palsize=0;
71
[1533]72 bmpsize = pbmi->biWidth;
[4]73 /* @@@PH 98/06/07 -- high-color bitmaps don't have palette */
74
75 this->fFlip = fFlip;
[3302]76 os2bmphdrsize = sizeof(BITMAPINFO2);
[4]77
78 switch(pbmi->biBitCount)
79 {
80 case 1:
[4450]81 bmpsize = ((bmpsize + 31) & ~31) / 8;
82 palsize = ((1 << pbmi->biBitCount))*sizeof(RGB2);
83 os2bmphdrsize += palsize;
84 break;
[4]85 case 4:
[4450]86 bmpsize = ((bmpsize + 7) & ~7) / 2;
87 palsize = ((1 << pbmi->biBitCount))*sizeof(RGB2);
88 os2bmphdrsize += palsize;
89 break;
[4]90 case 8:
[4450]91 palsize = ((1 << pbmi->biBitCount))*sizeof(RGB2);
92 os2bmphdrsize += palsize;
93 bmpsize = (bmpsize + 3) & ~3;
94 break;
[4]95 case 16:
[4450]96 bmpsize *= 2;
97 bmpsize = (bmpsize + 3) & ~3;
98 break;
[4]99 case 24:
[4450]100 bmpsize *= 3;
101 bmpsize = (bmpsize + 3) & ~3;
102 break;
[4]103 case 32:
[4450]104 bmpsize *= 4;
105 break;
106 default:
107 dprintf(("Unsupported nr of bits %d", pbmi->biBitCount));
108 DebugInt3();
109 break;
[4]110 }
[1533]111
[2718]112 this->hSection = hSection;
[4127]113 this->dwOffset = dwOffset;
[2718]114 if(hSection) {
[9966]115 bmpBits = (char *)MapViewOfFile(hSection, FILE_MAP_ALL_ACCESS_W, 0, dwOffset, bmpsize*pbmi->biHeight - dwOffset);
[4450]116 if(!bmpBits) {
117 dprintf(("Dibsection: mapViewOfFile %x failed!", hSection));
118 DebugInt3();
119 }
[2718]120 }
121 if(!bmpBits) {
[10373]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;
[2718]133 }
[10373]134 else memset(bmpBits, 0, bmpsize*pbmi->biHeight);
[4]135
[3302]136 pOS2bmp = (BITMAPINFO2 *)malloc(os2bmphdrsize);
[4]137
[2581]138 memset(pOS2bmp, /* set header + palette entries to zero */
139 0,
[3302]140 os2bmphdrsize);
[4]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;
[4681]147 pOS2bmp->ulCompression = pbmi->biCompression; //same as OS/2 (uncompressed, rle8, rle4)
[3626]148 //SvL: Ignore BI_BITFIELDS_W type (GpiDrawBits fails otherwise)
149 if(pOS2bmp->ulCompression == BI_BITFIELDS_W) {
[4450]150 pOS2bmp->ulCompression = 0;
[2592]151 }
[4]152 pOS2bmp->cbImage = pbmi->biSizeImage;
[10373]153 dprintf(("hBitmap %x", hBitmap));
[4]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));
[2592]160 dprintf(("Bits at %x, size %d",bmpBits, bmpsize*pbmi->biHeight));
[4]161
[2600]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
[4127]175 dibinfo.dshSection = hSection;
[4034]176 dibinfo.dsOffset = dwOffset;
[2600]177
[3227]178 if(iUsage == DIB_PAL_COLORS || pbmi->biBitCount <= 8)
179 {
180 dibinfo.dsBitfields[0] = dibinfo.dsBitfields[1] = dibinfo.dsBitfields[2] = 0;
[4450]181 if(palsize) {
[10088]182 SetDIBColorTable(0, (pbmi->biClrUsed) ? pbmi->biClrUsed : (1 << pbmi->biBitCount), (RGBQUAD *)(pbmi+1));
[4450]183 }
[3227]184 }
185 else {
[4450]186 switch(pbmi->biBitCount)
187 {
[3227]188 case 16:
[4447]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;
[3227]193
194 case 24:
195 case 32:
[7327]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) {
[4450]200 dprintf(("DIBSection: unsupported bitfields for 32 bits bitmap!!"));
201 }
[4447]202 break;
203 }
[4450]204 dprintf(("BI_BITFIELDS_W %x %x %x", dibinfo.dsBitfields[0], dibinfo.dsBitfields[1], dibinfo.dsBitfields[2]));
[2600]205 }
[3527]206 //double buffer for rgb 555 dib sections (for conversion) or flipped sections
207 if(dibinfo.dsBitfields[1] == 0x03e0 || (fFlip & FLIP_VERT)) {
[4450]208 DosAllocMem((PPVOID)&bmpBitsDblBuffer, bmpsize*pbmi->biHeight, PAG_READ|PAG_WRITE|PAG_COMMIT);
[3527]209 }
[2600]210
[10373]211 this->hBitmap = hBitmap;
[2592]212 this->iUsage = iUsage;
[4]213
[7717]214 lock();
[1533]215 if(section == NULL)
216 {
217 dprintf(("section was NULL\n"));
218 section = this;
[4]219 }
220 else
221 {
222 DIBSection *dsect = section;
[2267]223 dprintf2(("Increment section starting at %08X\n",dsect));
[4]224
225 while ( (dsect->next != this) &&
226 (dsect->next != NULL) )
227 {
[5399]228//// dprintf2(("Increment section to %08X\n",dsect->next));
[1533]229 dsect = dsect->next;
[4]230 }
231 dsect->next = this;
232 }
[7717]233 unlock();
[4]234}
235//******************************************************************************
236//******************************************************************************
237DIBSection::~DIBSection()
238{
[10373]239 dprintf(("Delete DIBSection %x", hBitmap));
[2718]240
241 if(hSection) {
[10373]242 UnmapViewOfFile(bmpBits);
[2718]243 }
[10373]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 }
[2718]254
[3711]255 if(bmpBitsDblBuffer)
[10373]256 DosFreeMem(bmpBitsDblBuffer);
[3235]257
[4]258 if(pOS2bmp)
[10373]259 free(pOS2bmp);
[4]260
[7717]261 lock();
[1966]262 if(section == this)
263 {
[10373]264 section = this->next;
[4]265 }
[1966]266 else
267 {
[10373]268 DIBSection *dsect = section;
[4]269
[10373]270 while(dsect->next != this)
271 {
272 dsect = dsect->next;
273 }
274 dsect->next = this->next;
[4]275 }
[7717]276 unlock();
[4]277}
278//******************************************************************************
279//******************************************************************************
280int DIBSection::SetDIBColorTable(int startIdx, int cEntries, RGBQUAD *rgb)
281{
[5825]282 int i, end;
[4]283
[5799]284 dprintf(("SetDIBColorTable %d %d %x", startIdx, cEntries, rgb));
[5825]285
286 if(pOS2bmp->cBitCount > 8) {
287 dprintf(("DIBSection::SetDIBColorTable: bpp > 8; ignore"));
288 return 0;
[4]289 }
[1966]290
[5825]291 end = startIdx + cEntries;
292 if(end > (1 << pOS2bmp->cBitCount)) {
293 end = (1 << pOS2bmp->cBitCount);
[5972]294 cEntries = end - startIdx;
[5825]295 }
296
[4]297 memcpy(&pOS2bmp->argbColor[startIdx], rgb, cEntries*sizeof(RGB2));
[1966]298
[5825]299 for(i=startIdx;i<end;i++)
[1966]300 {
301 pOS2bmp->argbColor[i].fcOptions = 0;
302 dprintf2(("Index %d : 0x%08X\n",i, *((ULONG*)(&pOS2bmp->argbColor[i])) ));
[4]303 }
304 return(cEntries);
305}
306//******************************************************************************
307//******************************************************************************
[4574]308int DIBSection::SetDIBColorTable(int startIdx, int cEntries, PALETTEENTRY *palentry)
309{
[5825]310 int i, end;
[4574]311
[5825]312 if(pOS2bmp->cBitCount > 8) {
313 dprintf(("DIBSection::SetDIBColorTable: bpp > 8; ignore"));
314 return 0;
[4574]315 }
316
[5825]317 end = startIdx + cEntries;
318 if(end > (1 << pOS2bmp->cBitCount)) {
319 end = (1 << pOS2bmp->cBitCount);
320 }
321 for(i=startIdx;i<end;i++)
[4574]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;
[9762]327 dprintf2(("Index %d : 0x%08X\n",i, *((ULONG*)(&pOS2bmp->argbColor[i])) ));
[4574]328 }
329
[5825]330 return end - startIdx;
[4574]331}
332//******************************************************************************
333//******************************************************************************
[5825]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//******************************************************************************
[1937]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)
[4]359{
360 HPS hps = (HPS)hdcDest;
361 POINTL point[4];
[3418]362 LONG rc, hdcHeight, hdcWidth;
[3184]363 PVOID bitmapBits = NULL;
[3302]364 int oldyinversion = 0;
[3418]365 BOOL fRestoryYInversion = FALSE, fFrameWindowDC = FALSE;
366 HWND hwndDest;
[3711]367 pDCData pHps;
[4]368
[3755]369 pHps = (pDCData)OSLibGpiQueryDCData((HPS)hdcDest);
[3711]370 if(!pHps)
371 {
[4450]372 SetLastError(ERROR_INVALID_HANDLE_W);
373 return FALSE;
[3711]374 }
[4]375
[3711]376 hwndDest = WindowFromDC(hdcDest); //could return desktop window, so check that
377 if(hwndDest && pHps->hwnd && !pHps->isClient) {
[4450]378 fFrameWindowDC = TRUE;
[3711]379 }
380
[2581]381 dprintf(("DIBSection::BitBlt %x %X (hps %x) %x to(%d,%d)(%d,%d) from (%d,%d)(%d,%d) rop %x flip %x",
[10373]382 hBitmap, hdcDest, hps, hwndDest, nXdest, nYdest, nDestWidth, nDestHeight,
[2581]383 nXsrc, nYsrc, nSrcWidth, nSrcHeight, Rop, fFlip));
[1710]384
[10373]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
[3418]391 if(hwndDest) {
[4450]392 RECT rect;
[3418]393
[4450]394 if(fFrameWindowDC) {
[4574]395 GetWindowRect(hwndDest, &rect);
[4450]396 }
397 else GetClientRect(hwndDest, &rect);
398 hdcHeight = rect.bottom - rect.top;
399 hdcWidth = rect.right - rect.left;
[7717]400 dprintf(("DIBSection::BitBlt hdc size (%d,%d) (WINDOW)", hdcWidth, hdcHeight));
[3418]401 }
402 else {
[5399]403 hdcHeight = pHps->bitmapHeight;
404 hdcWidth = pHps->bitmapWidth;
[7717]405 dprintf(("DIBSection::BitBlt hdc size (%d,%d) (BMP)", hdcWidth, hdcHeight));
[3418]406 }
407
[7662]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)
[4447]411
[7662]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
[4]416 point[0].x = nXdest;
[7717]417 point[1].x = nXdest + nDestWidth - 1;
418#ifdef INVERT
[3418]419 point[0].y = hdcHeight - nYdest - nDestHeight;
[3755]420 point[1].y = hdcHeight - nYdest - 1;
[7717]421#else
422 point[0].y = nYdest;
423 point[1].y = nYdest + nDestHeight - 1;
[7662]424#endif
425
426 //target rectangle is inclusive-inclusive
[3418]427 point[2].x = nXsrc;
[7717]428 point[3].x = nXsrc + nSrcWidth;
429#ifdef INVERT
[3418]430 point[2].y = pOS2bmp->cy - nYsrc - nSrcHeight;
[3437]431 point[3].y = pOS2bmp->cy - nYsrc;
[7717]432#else
433 point[2].y = nYsrc;
[9966]434 point[3].y = nYsrc + nSrcHeight;
[7717]435#endif
[4]436
[4574]437#ifdef INVERT
[3302]438 oldyinversion = GpiQueryYInversion(hps);
[3371]439 if(oldyinversion != 0) {
[9762]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
[4450]464 GpiEnableYInversion(hps, 0);
465 fRestoryYInversion = TRUE;
[3371]466 }
[9966]467#else
468 dprintf(("Sync destination dibsection: hdc y inversion = %d", GpiQueryYInversion(hdc)));
[4574]469#endif
[4]470
[9762]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
[4574]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
[1937]481 if(fFlip & FLIP_HOR)
482 {
[4447]483 ULONG x;
484 x = point[0].x;
485 point[0].x = point[1].x;
486 point[1].x = x;
[4]487 }
488
[3527]489 ULONG os2mode, winmode;
490
491 os2mode = BBO_OR;
492 winmode = GetStretchBltMode(hdcDest);
493 switch(winmode) {
494 case BLACKONWHITE_W:
[4450]495 os2mode = BBO_AND;
496 break;
[3527]497 case WHITEONBLACK_W:
498 case HALFTONE_W: //TODO:
[4450]499 os2mode = BBO_OR;
500 break;
[3527]501 case COLORONCOLOR_W:
[4450]502 os2mode = BBO_IGNORE;
503 break;
[3527]504 }
[9966]505#ifndef INVERT
506 if(!(fFlip & FLIP_VERT)) {
507#else
[3527]508 if(fFlip & FLIP_VERT) {
[9966]509#endif
[4450]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;
[3527]519 }
[3711]520 else bitmapBits = bmpBits;
[3527]521
[5931]522 //Translate ROP
523 Rop = Rop >> 16;
[5677]524
[3184]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?
[4447]527 dprintf(("DIBSection::BitBlt; convert rgb 555 to 565 (old y inv. = %d)", oldyinversion));
[4]528
[4450]529 if(bmpBitsDblBuffer == NULL)
530 DebugInt3();
[4447]531
[4450]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);
[4447]538
[4450]539 if (iLength > 0)
540 {
[10167]541 pRGB555to565((WORD *)bmpBitsDblBuffer, (WORD *)bitmapBits, iLength/sizeof(WORD));
[4450]542 }
543 else
544 {
545 dprintf(("GDI32: DIBSect::BitBlt: WARNING! zero-length bitmap! %08xh", pOS2bmp));
546 }
[5677]547 rc = GpiDrawBits(hps, bmpBitsDblBuffer, pOS2bmp, 4, &point[0], Rop, os2mode);
[3184]548 }
[5346]549 else {
[5677]550 rc = GpiDrawBits(hps, bitmapBits, pOS2bmp, 4, &point[0], Rop, os2mode);
[5346]551 }
[3302]552 if(rc == GPI_OK) {
[4574]553#ifdef INVERT
[4450]554 //restore old y inversion height
555 if(fRestoryYInversion) GpiEnableYInversion(hps, oldyinversion);
[4574]556#endif
[7717]557 SetLastError(ERROR_SUCCESS_W);
[3755]558
[4450]559 return(TRUE);
[3302]560 }
[4574]561#ifdef INVERT
[3371]562 if(fRestoryYInversion) GpiEnableYInversion(hps, oldyinversion);
[4574]563#endif
[3418]564
[4]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));
[3371]566 dprintf(("WinGetLastError returned %X\n", WinGetLastError(WinQueryAnchorBlock(hwndDest)) & 0xFFFF));
[4]567 return(FALSE);
568}
569//******************************************************************************
570//******************************************************************************
[5333]571void DIBSection::sync(HDC hdc, DWORD nYdest, DWORD nDestHeight, BOOL orgYInversion)
[3418]572{
573 APIRET rc;
574 char *destBuf;
575
[10373]576 dprintf(("Sync destination dibsection %x (%x) (%d,%d) flip %d", hBitmap, hdc, nYdest, nDestHeight, fFlip));
[3418]577
[5333]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) {
[7717]587#ifdef DEBUG
588 POINT point;
589 GetViewportOrgEx(hdc, &point);
590 dprintf(("Viewport origin (%d,%d)", point.x, point.y));
591#endif
[5333]592 GpiEnableYInversion(hdc, 0);
593 }
[4127]594 }
[9966]595#else
596 dprintf(("Sync destination dibsection: hdc y inversion = %d", GpiQueryYInversion(hdc)));
[4127]597#endif
598
[9966]599#ifndef INVERT
600 if(!(fFlip & FLIP_VERT)) {
601#else
[3711]602 if(fFlip & FLIP_VERT) {
[9966]603#endif
[10373]604 //origin is top left, so no y conversion is necessary
[4450]605 destBuf = bmpBitsDblBuffer + nYdest*dibinfo.dsBm.bmWidthBytes;
[3711]606
[6794]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
[9966]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,
[3711]620 tmphdr);
[7113]621 if(rc == GPI_ALTERROR) {
622 dprintf(("ERROR: GpiQueryBitmapBits failed with %x", WinGetLastError(0)));
623 }
624
[4450]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 }
[3711]633 }
634 else {
[6794]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
[10373]642 //origin is bottom left, nYdest is based on top left coordinate system
[9966]643#ifdef INVERT
644 int dest = dibinfo.dsBm.bmHeight - nYdest - nDestHeight;
645#else
646 int dest = nYdest;
647#endif
[10373]648
649 destBuf = GetDIBObject() + dest*dibinfo.dsBm.bmWidthBytes;
650
651 rc = GpiQueryBitmapBits(hdc, dest, nDestHeight, destBuf,
[5333]652 tmphdr);
[7113]653 if(rc == GPI_ALTERROR) {
[6794]654 dprintf(("ERROR: GpiQueryBitmapBits failed with %x", WinGetLastError(0)));
655 }
[4127]656#ifdef DEBUG_PALETTE
[4450]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 }
[4127]663#endif
[3711]664 }
[5799]665 memcpy(pOS2bmp, tmphdr, os2bmphdrsize);
[5333]666
[4034]667 if(dibinfo.dsBitfields[1] == 0x3E0) {//RGB 555?
[9966]668 dprintf(("DIBSection::sync: convert RGB 565 to RGB 555"));
[4034]669
[9966]670 destBuf = GetDIBObject() + nYdest*dibinfo.dsBm.bmWidthBytes;
[4034]671
[10167]672 pRGB565to555((WORD *)destBuf, (WORD *)destBuf, (nDestHeight*dibinfo.dsBm.bmWidthBytes)/sizeof(WORD));
[4034]673 }
[5901]674
[3418]675 free(tmphdr);
676 if(rc != nDestHeight) {
[9966]677 dprintf(("!WARNING!: GpiQueryBitmapBits returned %d instead of %d scanlines", rc, nDestHeight));
[3418]678 }
[5333]679
680#ifdef INVERT
681 if(oldyinversion) GpiEnableYInversion(hdc, oldyinversion);
682#endif
683
[3418]684}
685//******************************************************************************
[10373]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?
[10467]737 dprintf(("DIBSection::flush: convert RGB 555 to RGB 565"));
[10373]738
[10467]739 pRGB555to565((WORD *)destBuf, (WORD *)destBuf, (nDestHeight*dibinfo.dsBm.bmWidthBytes)/sizeof(WORD));
[10373]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?
[10467]772 dprintf(("DIBSection::flush: convert RGB 555 to RGB 565"));
[10373]773
[10467]774 pRGB555to565((WORD *)bmpBitsDblBuffer, (WORD *)destBuf, (nDestHeight*dibinfo.dsBm.bmWidthBytes)/sizeof(WORD));
[10373]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//******************************************************************************
[4127]910//manual sync if no stretching and bpp is the same
[4447]911//WARNING: this also assumes the colortables are the same
[3418]912//******************************************************************************
[4127]913void DIBSection::sync(DWORD xDst, DWORD yDst, DWORD widthDst, DWORD heightDst, PVOID bits)
914{
915 char *srcbuf, *destbuf;
916 int linesize;
917
[4447]918 srcbuf = (char *)bits + dibinfo.dsBm.bmWidthBytes*yDst +
[4127]919 (xDst*dibinfo.dsBm.bmWidthBytes)/pOS2bmp->cx;
[4447]920 destbuf = (char *)GetDIBObject() + dibinfo.dsBm.bmWidthBytes*yDst +
[4127]921 (xDst*dibinfo.dsBm.bmWidthBytes)/pOS2bmp->cx;
922 linesize = (widthDst*dibinfo.dsBm.bmWidthBytes)/pOS2bmp->cx;
923 for(int i=0;i<heightDst;i++) {
[4450]924 memcpy(destbuf, srcbuf, linesize);
925 destbuf += dibinfo.dsBm.bmWidthBytes;
926 srcbuf += linesize;
[4127]927 }
928}
929//******************************************************************************
930//******************************************************************************
[4]931void DIBSection::SelectDIBObject(HDC hdc)
932{
933 this->hdc = hdc;
[3418]934 hwndParent = WindowFromDC(hdc);
[10373]935 dprintf(("SelectDIBObject %x into %x hwndParent = %x", hBitmap, hdc, hwndParent));
[4]936}
937//******************************************************************************
938//******************************************************************************
[10373]939DIBSection *DIBSection::findObj(HBITMAP hBitmap)
[4]940{
[6557]941 // PH 2001-08-18 shortcut for performance optimization
942 if (!section)
943 return NULL;
[4]944
[10373]945 lock();
[6557]946 DIBSection *dsect = section;
947
948 do
[1966]949 {
[10373]950 if(dsect->hBitmap == hBitmap)
[1966]951 {
[7717]952 unlock();
[4447]953 return(dsect);
[1966]954 }
955 dsect = dsect->next;
[4]956 }
[6557]957 while(dsect);
958
[7717]959 unlock();
[4]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{
[7361]967 // PH 2001-08-18 shortcut for performance optimization
968 if (!section)
969 return NULL;
970
[10373]971 lock();
[7361]972 DIBSection *dsect = section;
973
974 do
[1966]975 {
[4450]976 if(dsect->hdc == hdc)
977 {
[7717]978 unlock();
[4450]979 return(dsect);
980 }
981 dsect = dsect->next;
[4]982 }
[7361]983 while(dsect);
[7717]984
985 unlock();
[4]986 return(NULL);
987}
988//******************************************************************************
989//******************************************************************************
[10373]990void DIBSection::deleteSection(HBITMAP hBitmap)
[4]991{
[10373]992 DIBSection *dsect = findObj(hBitmap);
[4]993
994 if(dsect)
[4450]995 delete dsect;
[4]996}
997//******************************************************************************
998//******************************************************************************
[2267]999int DIBSection::GetDIBSection(int iSize, void *lpBuffer)
[1966]1000{
[2267]1001 DIBSECTION *pDIBSection = (DIBSECTION *)lpBuffer;
[2600]1002 LPBITMAP_W dsBm = (LPBITMAP_W)lpBuffer;
[2267]1003
[10373]1004 dprintf2(("GetDIBSection %x %d %x", hBitmap, iSize, lpBuffer));
[2267]1005 if(iSize == sizeof(DIBSECTION))
[1533]1006 {
[4450]1007 memcpy(pDIBSection, &dibinfo, sizeof(dibinfo));
[2600]1008 return sizeof(DIBSECTION);
[1533]1009 }
[2267]1010 else
[2600]1011 if(iSize == sizeof(BITMAP_W))
[2267]1012 {
[4450]1013 memcpy(dsBm, &dibinfo.dsBm, sizeof(dibinfo.dsBm));
1014 return sizeof(BITMAP_W);
[2267]1015 }
1016 return 0;
[1533]1017
1018}
1019//******************************************************************************
1020//******************************************************************************
[3594]1021int DIBSection::GetBitCount()
[1966]1022{
[2581]1023 if(pOS2bmp == NULL)
[1966]1024 return 0;
1025 else
1026 return pOS2bmp->cBitCount;
1027}
1028//******************************************************************************
1029//******************************************************************************
[3594]1030int DIBSection::GetHeight()
1031{
1032 if(pOS2bmp == NULL)
1033 return 0;
1034 else
1035 return pOS2bmp->cy;
1036}
1037//******************************************************************************
1038//******************************************************************************
[4447]1039int DIBSection::GetWidth()
1040{
1041 if(pOS2bmp == NULL)
1042 return 0;
1043 else
1044 return pOS2bmp->cx;
1045}
1046//******************************************************************************
1047//******************************************************************************
[7717]1048void DIBSection::initDIBSection()
1049{
1050 InitializeCriticalSection(&dibcritsect);
1051}
1052//******************************************************************************
1053//******************************************************************************
1054DIBSection *DIBSection::section = NULL;
1055CRITICAL_SECTION DIBSection::dibcritsect;
[10373]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) {
[21455]1081 ULONG ulMemFlags = 0;
1082 ULONG ulMemCommit = PAG_COMMIT;
[21460]1083 ULONG ulMemSize = dwSize;
[21455]1084 APIRET rc = DosQueryMem(lpBase, &ulMemSize, &ulMemFlags);
[10373]1085 if(rc) {
[21455]1086 dprintf(("DosQueryMem failed with %d!!", rc));
1087 DebugInt3();
1088 return FALSE;
1089 }
1090 dprintf(("DosQueryMem size %d, flags %x", ulMemSize, ulMemFlags));
1091 // YD cannot commit memory two times!
1092 if ((ulMemFlags & PAG_COMMIT) == PAG_COMMIT)
1093 ulMemCommit = 0;
1094 rc = DosSetMem(lpBase, dwSize, PAG_READ|ulMemCommit);
1095 if(rc) {
[10373]1096 dprintf(("DosSetMem failed with %d!!", rc));
1097 DebugInt3();
1098 return FALSE;
1099 }
1100 }
1101
1102 if(fWriteAccess) {
1103 APIRET rc = DosSetMem(lpBase, dwSize, PAG_READ|PAG_WRITE);
1104 if(rc) {
1105 dprintf(("DosSetMem failed with %d!!", rc));
1106 DebugInt3();
1107 return FALSE;
1108 }
1109 dsect->setDirty();
1110 }
1111
1112
1113 return TRUE;
1114}
1115//******************************************************************************
1116//******************************************************************************
Note: See TracBrowser for help on using the repository browser.